RK3288 增加双屏异显 eDP+LVDS

CPU:RK3288

系统:Android 5.1

 

下面是官方文档中的信息。

1、rk3288 支持的显示接口可以任意组合。

2、双屏异显时,一个显示接口当主屏,另一个当副屏;主副屏由板级 dts 文件确定,启动后无法动态更改。

3、当两路显示接口显示不同分辨率时,rk3288 只能为一路显示接口提供精确时钟,另一路显示接口时钟会有微小频偏。

 

瑞芯微虽然提供了 Android 5.1 的补丁,但是本人在移植过程中出现一些问题(打补丁最好一行行核对,不要图方便直接使用指令)。

设备 eDP 为主屏,lvds 为副屏。

 

(1)首先修改两个屏参文件 lcd-xxx.dtsi。

eDP 屏参文件补丁

diff --git a/kernel/arch/arm/boot/dts/lcd-NV116FH1.dtsi b/kernel/arch/arm/boot/dts/lcd-NV116FH1.dtsi
index 3862b05..7bf992f 100755
--- a/kernel/arch/arm/boot/dts/lcd-NV116FH1.dtsi 
+++ b/kernel/arch/arm/boot/dts/lcd-NV116FH1.dtsi 
@@ -3,11 +3,9 @@
  *
  */
 
-/ {
-
-        disp_timings: display-timings {
-                        native-mode = <&timing0>;
-                        timing0: timing0 {
+        display-timings {
+                        native-mode = <&nv116fhm>;
+                        nv116fhm: timing0 {
                 screen-type = ;
                 out-face    = ;
                 clock-frequency = <205000000>;
@@ -30,4 +30,3 @@
                swap-gb = <0>;
                         };
               };
-};

lvds 屏参文件补丁

diff --git a/kernel/arch/arm/boot/dts/lcd-ZJ080NA-08A.dtsi b/kernel/arch/arm/boot/dts/lcd-ZJ080NA-08A.dtsi
old mode 100644
new mode 100755
index fc6385c..58f999be
--- a/kernel/arch/arm/boot/dts/lcd-ZJ080NA-08A.dtsi
+++ b/kernel/arch/arm/boot/dts/lcd-ZJ080NA-08A.dtsi
@@ -3,11 +3,10 @@
  *
  */
 
-/ {
 
-        disp_timings: display-timings {
-                        native-mode = <&timing0>;
-                        timing0: timing0 {
+        display-timings {
+                        native-mode = <&zj080na>;
+                        zj080na: timing0 {
                 screen-type = ;
                 lvds-format = ;
                 out-face    = ;
@@ -30,4 +30,3 @@
                swap-gb = <0>;
             };
         };
-};

 

(2)根据官方提供,打上 kernel 补丁

diff --git a/kernel/arch/arm/boot/dts/rk3288-tb_8846.dts b/kernel/arch/arm/boot/dts/rk3288-tb_8846.dts
index 6a65163..fc48fc0 100755
--- a/kernel/arch/arm/boot/dts/rk3288-tb_8846.dts
+++ b/kernel/arch/arm/boot/dts/rk3288-tb_8846.dts
@@ -565,12 +565,56 @@ clock-frequency = <50000000>;
 };
 
 &fb {
-    rockchip,disp-mode = ;
-    rockchip,uboot-logo-on = <1>;
+    rockchip,disp-mode = ;
+    rockchip,uboot-logo-on = <0>;
 };
 
 &rk_screen {
-     display-timings = <&disp_timings>;
+    status = "okay";
+    screen0 {
+        screen_prop = ;
+        native-mode = ;
+        power_ctr {
+            lcd_en {
+                rockchip,power_type = ;
+                gpios = <&gpio7 GPIO_A5 GPIO_ACTIVE_HIGH>;
+                rockchip,delay = <10>;
+            };
+            /*lcd_cs {
+                rockchip,power_type = ;
+                gpios = <&gpio7 GPIO_A4 GPIO_ACTIVE_HIGH>;
+                rockchip,delay = <10>;
+            };*/
+        };
+        #include "lcd-NV156FH1.dtsi"
+    };
+    screen1 {
+        screen_prop = ;
+        native-mode = ;
+        power_ctr {
+            lcd_en {
+                rockchip,power_type = ;
+                gpios = <&gpio7 GPIO_A3 GPIO_ACTIVE_HIGH>;
+                rockchip,delay = <10>;
+            };
+            /*lcd_cs {
+                rockchip,power_type = ;
+                gpios = <&gpio7 GPIO_A4 GPIO_ACTIVE_HIGH>;
+                rockchip,delay = <10>;
+            };*/
+        };
+        #include "lcd-ZJ080NA-08A.dtsi"
+    };
+};
+
+&edp {
+    status = "okay";
+    prop = ;
+};
+
+&lvds {
+    status = "okay";
+    prop = ;
 };
 
 /*lcdc0 as PRMRY(LCD),lcdc1 as EXTEND(HDMI)*/
@@ -587,18 +631,18 @@ clock-frequency = <50000000>;
             rockchip,delay = <5>;
         };*/
 
-        lcd_en:lcd_en {
+        /*lcd_en:lcd_en {
             rockchip,power_type = ;
             gpios = <&gpio7 GPIO_A3 GPIO_ACTIVE_HIGH>;
             rockchip,delay = <200>;
         };
         
-        /*lcd_cs:lcd_cs {
+        lcd_cs:lcd_cs {
             rockchip,power_type = ;
             gpios = <&gpio7 GPIO_A4 GPIO_ACTIVE_HIGH>;
             rockchip,delay = <10>;
-        };*/
-
+        };
+        */
         /*lcd_rst:lcd_rst {
             rockchip,power_type = ;
             gpios = <&gpio3 GPIO_D6 GPIO_ACTIVE_HIGH>;
@@ -615,7 +659,7 @@ clock-frequency = <50000000>;
 };
 
 &hdmi {
-    status = "okay";
+    status = "disabled";
     rockchip,hdmi_video_source = ;
 };
 
diff --git a/kernel/drivers/video/rockchip/rk_fb.c b/kernel/drivers/video/rockchip/rk_fb.c
index 533ce2b..4037cfd 100755
--- a/kernel/drivers/video/rockchip/rk_fb.c
+++ b/kernel/drivers/video/rockchip/rk_fb.c
@@ -112,9 +112,8 @@ EXPORT_SYMBOL(video_data_to_mirroring);
 extern phys_addr_t uboot_logo_base;
 extern phys_addr_t uboot_logo_size;
 extern phys_addr_t uboot_logo_offset;
-static struct rk_fb_trsm_ops *trsm_lvds_ops;
-static struct rk_fb_trsm_ops *trsm_edp_ops;
-static struct rk_fb_trsm_ops *trsm_mipi_ops;
+static struct rk_fb_trsm_ops *trsm_prmry_ops;
+static struct rk_fb_trsm_ops *trsm_extend_ops;
 static int uboot_logo_on;
 
 static int rk_fb_debug_lvl;
@@ -148,53 +147,24 @@ int rk_fb_get_display_policy(void)
 
 int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type)
 {
-    switch (type) {
-    case SCREEN_RGB:
-    case SCREEN_LVDS:
-    case SCREEN_DUAL_LVDS:
-    case SCREEN_LVDS_10BIT:
-    case SCREEN_DUAL_LVDS_10BIT:
-        trsm_lvds_ops = ops;
-        break;
-    case SCREEN_EDP:
-        trsm_edp_ops = ops;
-        break;
-    case SCREEN_MIPI:
-    case SCREEN_DUAL_MIPI:
-        trsm_mipi_ops = ops;
-        break;
-    default:
-        printk(KERN_WARNING "%s:un supported transmitter:%d!\n",
-               __func__, type);
-        break;
-    }
+    if (type == PRMRY)
+        trsm_prmry_ops = ops;
+    else if (type == EXTEND)
+        trsm_extend_ops = ops;
+    else
+        pr_err("%s, type:%d\n", __func__, type);
     return 0;
 }
 
 struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type)
 {
     struct rk_fb_trsm_ops *ops;
-    switch (type) {
-    case SCREEN_RGB:
-    case SCREEN_LVDS:
-    case SCREEN_DUAL_LVDS:
-    case SCREEN_LVDS_10BIT:
-    case SCREEN_DUAL_LVDS_10BIT:
-        ops = trsm_lvds_ops;
-        break;
-    case SCREEN_EDP:
-        ops = trsm_edp_ops;
-        break;
-    case SCREEN_MIPI:
-    case SCREEN_DUAL_MIPI:
-        ops = trsm_mipi_ops;
-        break;
-    default:
-        ops = NULL;
-        printk(KERN_WARNING "%s:un supported transmitter:%d!\n",
-               __func__, type);
-        break;
-    }
+    if (type == PRMRY)
+        ops = trsm_prmry_ops;
+    else if (type == EXTEND)
+        ops = trsm_extend_ops;
+    else
+        pr_err("%s, type:%d\n", __func__, type);
     return ops;
 }
 
@@ -318,10 +288,10 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
 /*
  * rk display power control parse from dts
  */
-int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
+int rk_disp_pwr_ctr_parse_dt(struct device_node *np,
+                 struct rk_screen *rk_screen)
 {
-    struct device_node *root = of_get_child_by_name(dev_drv->dev->of_node,
-                            "power_ctr");
+    struct device_node *root = of_get_child_by_name(np, "power_ctr");
     struct device_node *child;
     struct rk_disp_pwr_ctr_list *pwr_ctr;
     struct list_head *pos;
@@ -330,10 +300,10 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
     u32 debug = 0;
     int ret;
 
-    INIT_LIST_HEAD(&dev_drv->pwrlist_head);
+    INIT_LIST_HEAD(rk_screen->pwrlist_head);
     if (!root) {
-        dev_err(dev_drv->dev, "can't find power_ctr node for lcdc%d\n",
-            dev_drv->id);
+        dev_err(rk_screen->dev, "can't find power_ctr node for lcdc%d\n",
+            rk_screen->lcdc_id);
         return -ENODEV;
     }
 
@@ -346,7 +316,7 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
                 pwr_ctr->pwr_ctr.type = GPIO;
                 pwr_ctr->pwr_ctr.gpio = of_get_gpio_flags(child, 0, &flags);
                 if (!gpio_is_valid(pwr_ctr->pwr_ctr.gpio)) {
-                    dev_err(dev_drv->dev, "%s ivalid gpio\n",
+                    dev_err(rk_screen->dev, "%s ivalid gpio\n",
                         child->name);
                     return -EINVAL;
                 }
@@ -354,7 +324,7 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
                 ret = gpio_request(pwr_ctr->pwr_ctr.gpio,
                            child->name);
                 if (ret) {
-                    dev_err(dev_drv->dev,
+                    dev_err(rk_screen->dev,
                         "request %s gpio fail:%d\n",
                         child->name, ret);
                 }
@@ -365,7 +335,7 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
                 ret = of_property_read_string(child, "rockchip,regulator_name",
                                  &(pwr_ctr->pwr_ctr.rgl_name));
                 if (ret || IS_ERR_OR_NULL(pwr_ctr->pwr_ctr.rgl_name))
-                    dev_err(dev_drv->dev, "get regulator name failed!\n");
+                    dev_err(rk_screen->dev, "get regulator name failed!\n");
                 if (!of_property_read_u32(child, "rockchip,regulator_voltage", &val))
                     pwr_ctr->pwr_ctr.volt = val;
                 else
@@ -377,13 +347,13 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
             pwr_ctr->pwr_ctr.delay = val;
         else
             pwr_ctr->pwr_ctr.delay = 0;
-        list_add_tail(&pwr_ctr->list, &dev_drv->pwrlist_head);
+        list_add_tail(&pwr_ctr->list, rk_screen->pwrlist_head);
     }
 
     of_property_read_u32(root, "rockchip,debug", &debug);
 
     if (debug) {
-        list_for_each(pos, &dev_drv->pwrlist_head) {
+        list_for_each(pos, rk_screen->pwrlist_head) {
             pwr_ctr = list_entry(pos, struct rk_disp_pwr_ctr_list,
                          list);
             printk(KERN_INFO "pwr_ctr_name:%s\n"
@@ -411,9 +381,14 @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv)
     struct regulator *regulator_lcd = NULL;
     int count = 10;
 
-    if (list_empty(&dev_drv->pwrlist_head))
+    if (!dev_drv->cur_screen->pwrlist_head) {
+        pr_info("error:  %s, lcdc%d screen pwrlist null\n",
+            __func__, dev_drv->id);
+        return 0;
+    }
+    if (list_empty(dev_drv->cur_screen->pwrlist_head))
         return 0;
-    list_for_each(pos, &dev_drv->pwrlist_head) {
+    list_for_each(pos, dev_drv->cur_screen->pwrlist_head) {
         pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list,
                       list);
         pwr_ctr = &pwr_ctr_list->pwr_ctr;
@@ -455,9 +430,14 @@ int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv)
     struct regulator *regulator_lcd = NULL;
     int count = 10;
 
-    if (list_empty(&dev_drv->pwrlist_head))
+    if (!dev_drv->cur_screen->pwrlist_head) {
+        pr_info("error:  %s, lcdc%d screen pwrlist null\n",
+            __func__, dev_drv->id);
         return 0;
-    list_for_each(pos, &dev_drv->pwrlist_head) {
+    }
+    if (list_empty(dev_drv->cur_screen->pwrlist_head))
+        return 0;
+    list_for_each(pos, dev_drv->cur_screen->pwrlist_head) {
         pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list,
                       list);
         pwr_ctr = &pwr_ctr_list->pwr_ctr;
@@ -586,7 +566,7 @@ int rk_fb_prase_timing_dt(struct device_node *np, struct rk_screen *screen)
         pr_err("parse display timing err\n");
         return -EINVAL;
     }
-    dt = display_timings_get(disp_timing, disp_timing->native_mode);
+    dt = display_timings_get(disp_timing, screen->native_mode);
     rk_fb_video_mode_from_timing(dt, screen);
     return 0;
 
@@ -1676,6 +1656,7 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                 win->area[i].smem_start =
                     reg_win_data->reg_area_data[i].smem_start;
                                 if (inf->disp_mode == DUAL ||
+                                    inf->disp_mode == DUAL_LCD ||
                                     inf->disp_mode == NO_DUAL) {
                         win->area[i].xpos =
                                 reg_win_data->reg_area_data[i].xpos;
@@ -3852,7 +3833,8 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
         win = dev_drv->win[win_id];
 
     if (!strcmp(fbi->fix.id, "fb0")) {
-        fb_mem_size = get_fb_size(dev_drv->reserved_fb);
+        fb_mem_size = get_fb_size(dev_drv->reserved_fb,
+                      dev_drv->cur_screen);
 #if defined(CONFIG_ION_ROCKCHIP)
         if (rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0)
             return -ENOMEM;
@@ -3873,7 +3855,8 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
         if (dev_drv->prop == EXTEND && dev_drv->iommu_enabled) {
             struct rk_lcdc_driver *dev_drv_prmry;
             int win_id_prmry;
-            fb_mem_size = get_fb_size(dev_drv->reserved_fb);
+            fb_mem_size = get_fb_size(dev_drv->reserved_fb,
+                          dev_drv->cur_screen);
 #if defined(CONFIG_ION_ROCKCHIP)
             dev_drv_prmry = rk_get_prmry_lcdc_drv();
             if (dev_drv_prmry == NULL)
@@ -4036,14 +4019,9 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
         dev_drv->area_support[i] = 1;
     if (dev_drv->ops->area_support_num)
         dev_drv->ops->area_support_num(dev_drv, dev_drv->area_support);
-    rk_disp_pwr_ctr_parse_dt(dev_drv);
-    if (dev_drv->prop == PRMRY) {
-        rk_fb_set_prmry_screen(screen);
-        rk_fb_get_prmry_screen(screen);
-    }
-    dev_drv->trsm_ops = rk_fb_trsm_ops_get(screen->type);
-    if (dev_drv->prop != PRMRY)
-        rk_fb_get_extern_screen(screen);
+    rk_fb_set_screen(screen, dev_drv->prop);
+    rk_fb_get_screen(screen, dev_drv->prop);
+    dev_drv->trsm_ops = rk_fb_trsm_ops_get(dev_drv->prop);
     dev_drv->output_color = screen->color_mode;
 
     return 0;
@@ -4361,17 +4339,24 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
         main_fbi->fbops->fb_pan_display(&main_fbi->var, main_fbi);
 #endif
     } else {
-                struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> 1];
-                extend_fbi->var.pixclock = rk_fb->fb[0]->var.pixclock;
+        struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> 1];
+        extend_fbi->var.pixclock = rk_fb->fb[0]->var.pixclock;
+        extend_fbi->var.xres_virtual = rk_fb->fb[0]->var.xres_virtual;
+        extend_fbi->var.yres_virtual = rk_fb->fb[0]->var.yres_virtual;
         extend_fbi->fbops->fb_open(extend_fbi, 1);
-#if defined(CONFIG_ROCKCHIP_IOMMU)
         if (dev_drv->iommu_enabled) {
             if (dev_drv->mmu_dev)
                 rockchip_iovmm_set_fault_handler(dev_drv->dev,
                                  rk_fb_sysmmu_fault_handler);
+                if (dev_drv->ops->mmu_en)
+                    dev_drv->ops->mmu_en(dev_drv);
         }
-#endif
         rk_fb_alloc_buffer(extend_fbi);
+        if (rk_fb->disp_mode == DUAL_LCD) {
+            extend_fbi->fbops->fb_set_par(extend_fbi);
+            extend_fbi->fbops->fb_pan_display(&extend_fbi->var,
+                              extend_fbi);
+        }
     }
 #endif
     return 0;
diff --git a/kernel/drivers/video/rockchip/screen/rk_screen.c b/kernel/drivers/video/rockchip/screen/rk_screen.c
index d5e3b15..87a82d9 100755
--- a/kernel/drivers/video/rockchip/screen/rk_screen.c
+++ b/kernel/drivers/video/rockchip/screen/rk_screen.c
@@ -4,14 +4,23 @@
 #include "lcd.h"
 #include "../hdmi/rockchip-hdmi.h"
 
-static struct rk_screen *rk_screen;
+static struct rk_screen *prmry_screen;
+static struct rk_screen *extend_screen;
+
+static void rk_screen_info_error(struct rk_screen *screen, int prop)
+{
+    pr_err(">>>>>>>>>>>>>>>>>>>>error<<<<<<<<<<<<<<<<<<<<\n");
+    pr_err(">>please init %s screen info in dtsi file<<\n",
+           (prop == PRMRY) ? "prmry" : "extend");
+    pr_err(">>>>>>>>>>>>>>>>>>>>error<<<<<<<<<<<<<<<<<<<<\n");
+}
 
 int rk_fb_get_extern_screen(struct rk_screen *screen)
 {
-    if (unlikely(!rk_screen) || unlikely(!screen))
+    if (unlikely(!extend_screen) || unlikely(!screen))
         return -1;
 
-    memcpy(screen, rk_screen, sizeof(struct rk_screen));
+    memcpy(screen, extend_screen, sizeof(struct rk_screen));
     screen->dsp_lut = NULL;
     screen->cabc_lut = NULL;
     screen->type = SCREEN_NULL;
@@ -19,42 +28,84 @@ int rk_fb_get_extern_screen(struct rk_screen *screen)
     return 0;
 }
 
-int  rk_fb_get_prmry_screen(struct rk_screen *screen)
+int rk_fb_get_prmry_screen(struct rk_screen *screen)
 {
-    if (unlikely(!rk_screen) || unlikely(!screen))
+    if (unlikely(!prmry_screen) || unlikely(!screen))
         return -1;
 
-    memcpy(screen, rk_screen, sizeof(struct rk_screen));
+    memcpy(screen, prmry_screen, sizeof(struct rk_screen));
     return 0;
 }
 
-int rk_fb_set_prmry_screen(struct rk_screen *screen)
+int rk_fb_get_screen(struct rk_screen *screen, int prop)
 {
-    if (unlikely(!rk_screen) || unlikely(!screen))
+    struct rk_screen *cur_screen = NULL;
+
+    if (unlikely(!screen))
         return -1;
 
-    rk_screen->lcdc_id = screen->lcdc_id;
-    rk_screen->screen_id = screen->screen_id;
-    rk_screen->x_mirror = screen->x_mirror;
-    rk_screen->y_mirror = screen->y_mirror;
-    rk_screen->overscan.left = screen->overscan.left;
-    rk_screen->overscan.top = screen->overscan.left;
-    rk_screen->overscan.right = screen->overscan.left;
-    rk_screen->overscan.bottom = screen->overscan.left;
+    if (prop == PRMRY) {
+        if (unlikely(!prmry_screen)) {
+            rk_screen_info_error(screen, prop);
+            return -1;
+        }
+        cur_screen = prmry_screen;
+    } else {
+        if (unlikely(!extend_screen)) {
+            rk_screen_info_error(screen, prop);
+            return -1;
+        }
+        cur_screen = extend_screen;
+    }
+
+    memcpy(screen, cur_screen, sizeof(struct rk_screen));
+
     return 0;
 }
 
-size_t get_fb_size(u8 reserved_fb)
+int rk_fb_set_screen(struct rk_screen *screen, int prop)
+{
+    struct rk_screen *cur_screen = NULL;
+
+    if (unlikely(!screen))
+        return -1;
+    if (prop == PRMRY) {
+        if (unlikely(!prmry_screen)) {
+            rk_screen_info_error(screen, prop);
+            return -1;
+        }
+        cur_screen = prmry_screen;
+    } else {
+        if (unlikely(!extend_screen)) {
+            rk_screen_info_error(screen, prop);
+            return -1;
+        }
+        cur_screen = extend_screen;
+    }
+
+    cur_screen->lcdc_id = screen->lcdc_id;
+    cur_screen->screen_id = screen->screen_id;
+    cur_screen->x_mirror = screen->x_mirror;
+    cur_screen->y_mirror = screen->y_mirror;
+    cur_screen->overscan.left = screen->overscan.left;
+    cur_screen->overscan.top = screen->overscan.left;
+    cur_screen->overscan.right = screen->overscan.left;
+    cur_screen->overscan.bottom = screen->overscan.left;
+
+    return 0;
+}
+
+size_t get_fb_size(u8 reserved_fb, struct rk_screen *screen)
 {
     size_t size = 0;
     u32 xres = 0;
     u32 yres = 0;
 
-    if (unlikely(!rk_screen))
+    if (unlikely(!screen))
         return 0;
 
-    xres = rk_screen->mode.xres;
-    yres = rk_screen->mode.yres;
+    xres = screen->mode.xres;
+    yres = screen->mode.yres;
 
     /* align as 64 bytes(16*4) in an odd number of times */
     xres = ALIGN_64BYTE_ODD_TIMES(xres, ALIGN_PIXEL_64BYTE_RGB8888);
@@ -73,22 +124,51 @@ size_t get_fb_size(u8 reserved_fb)
 static int rk_screen_probe(struct platform_device *pdev)
 {
     struct device_node *np = pdev->dev.of_node;
-    int ret;
+    struct device_node *screen_np;
+    struct rk_screen *rk_screen;
+    int ret, screen_prop;
 
     if (!np) {
         dev_err(&pdev->dev, "Missing device tree node.\n");
         return -EINVAL;
     }
-    rk_screen = devm_kzalloc(&pdev->dev,
-            sizeof(struct rk_screen), GFP_KERNEL);
-    if (!rk_screen) {
-        dev_err(&pdev->dev, "kmalloc for rk screen fail!");
-        return  -ENOMEM;
+    
+    for_each_child_of_node(np, screen_np) {
+        rk_screen = devm_kzalloc(&pdev->dev,
+                     sizeof(struct rk_screen), GFP_KERNEL);
+        if (!rk_screen) {
+            dev_err(&pdev->dev, "kmalloc for rk screen fail!");
+            return  -ENOMEM;
+        }
+        rk_screen->pwrlist_head = devm_kzalloc(&pdev->dev,
+                sizeof(struct list_head), GFP_KERNEL);
+        if (!rk_screen->pwrlist_head) {
+            dev_err(&pdev->dev, "kmalloc for rk_screen pwrlist_head fail!");
+            return  -ENOMEM;
+        }
+        of_property_read_u32(screen_np, "screen_prop", &screen_prop);
+        if (screen_prop == PRMRY)
+            prmry_screen = rk_screen;
+        else if (screen_prop == EXTEND)
+            extend_screen = rk_screen;
+        else
+            dev_err(&pdev->dev, "unknow screen prop: %d\n",
+                screen_prop);
+        rk_screen->prop = screen_prop;
+        of_property_read_u32(screen_np, "native-mode", &rk_screen->native_mode);
+        rk_screen->dev = &pdev->dev;
+        ret = rk_fb_prase_timing_dt(screen_np, rk_screen);
+        pr_info("%s screen timing parse %s\n",
+            (screen_prop == PRMRY) ? "prmry" : "extend",
+            ret ? "failed" : "success");
+        ret = rk_disp_pwr_ctr_parse_dt(screen_np, rk_screen);
+        pr_info("%s screen power ctrl parse %s\n",
+            (screen_prop == PRMRY) ? "prmry" : "extend",
+            ret ? "failed" : "success");
     }
-    ret = rk_fb_prase_timing_dt(np, rk_screen);
-    dev_info(&pdev->dev, "rockchip screen probe %s\n",
-                ret ? "failed" : "success");
-    return ret;
+    
+    dev_info(&pdev->dev, "rockchip screen probe success\n");
+    return 0;
 }
 
 static const struct of_device_id rk_screen_dt_ids[] = {
diff --git a/kernel/drivers/video/rockchip/transmitter/rk32_dp.c b/kernel/drivers/video/rockchip/transmitter/rk32_dp.c
index 2b3457c..624089e 100755
--- a/kernel/drivers/video/rockchip/transmitter/rk32_dp.c
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_dp.c
@@ -119,7 +119,7 @@ static int rk32_edp_init_edp(struct rk32_edp *edp)
     struct rk_screen *screen = &edp->screen;
     u32 val = 0;
 
-    rk_fb_get_prmry_screen(screen);
+    rk_fb_get_screen(screen, edp->prop);
 
     if (cpu_is_rk3288()) {
         if (screen->lcdc_id == 1)  /*select lcdc*/
@@ -1712,17 +1712,21 @@ static int rk32_edp_probe(struct platform_device *pdev)
     struct resource *res;
     struct device_node *np = pdev->dev.of_node;
     int ret;
+    int prop;
 
     if (!np) {
         dev_err(&pdev->dev, "Missing device tree node.\n");
         return -EINVAL;
     }
+    of_property_read_u32(np, "prop", &prop);
+    pr_info("Use EDP as %s screen\n", (prop == PRMRY) ? "prmry" : "extend");
 
     edp = devm_kzalloc(&pdev->dev, sizeof(struct rk32_edp), GFP_KERNEL);
     if (!edp) {
         dev_err(&pdev->dev, "no memory for state\n");
         return -ENOMEM;
     }
+    edp->prop = prop;
     edp->dev = &pdev->dev;
     edp->video_info.h_sync_polarity    = 0;
     edp->video_info.v_sync_polarity    = 0;
@@ -1734,7 +1738,7 @@ static int rk32_edp_probe(struct platform_device *pdev)
 
     edp->video_info.link_rate    = LINK_RATE_1_62GBPS;
     edp->video_info.lane_count    = LANE_CNT4;
-    rk_fb_get_prmry_screen(&edp->screen);
+    rk_fb_get_screen(&edp->screen, prop);
     if (edp->screen.type != SCREEN_EDP) {
         dev_err(&pdev->dev, "screen is not edp!\n");
         return -EINVAL;
@@ -1809,7 +1813,7 @@ static int rk32_edp_probe(struct platform_device *pdev)
     if (!support_uboot_display())
         rk32_edp_clk_disable(edp);
     rk32_edp = edp;
-    rk_fb_trsm_ops_register(&trsm_edp_ops, SCREEN_EDP);
+    rk_fb_trsm_ops_register(&trsm_edp_ops, prop);
 #if defined(CONFIG_DEBUG_FS)
     edp->debugfs_dir = debugfs_create_dir("edp", NULL);
     if (IS_ERR(edp->debugfs_dir)) {
diff --git a/kernel/drivers/video/rockchip/transmitter/rk32_dp.h b/kernel/drivers/video/rockchip/transmitter/rk32_dp.h
index 08347b5..8ec3e26 100755
--- a/kernel/drivers/video/rockchip/transmitter/rk32_dp.h
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_dp.h
@@ -566,6 +566,7 @@ struct rk32_edp {
     bool clk_on;
     bool edp_en;
     struct dentry *debugfs_dir;
+    int prop;
 };
 
 
diff --git a/kernel/drivers/video/rockchip/transmitter/rk32_lvds.c b/kernel/drivers/video/rockchip/transmitter/rk32_lvds.c
index 692e33e..6180504 100755
--- a/kernel/drivers/video/rockchip/transmitter/rk32_lvds.c
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_lvds.c
@@ -78,7 +78,7 @@ static int rk32_lvds_en(void)
     u32 val = 0;
     u32 delay_times = 20;
     
-    rk_fb_get_prmry_screen(screen);
+    rk_fb_get_screen(screen, lvds->prop);
 
     /* enable clk */
     rk32_lvds_clk_enable(lvds);
@@ -169,19 +169,22 @@ static int rk32_lvds_probe(struct platform_device *pdev)
     struct rk32_lvds *lvds;
     struct resource *res;
     struct device_node *np = pdev->dev.of_node;
+    int prop;
 
     if (!np) {
         dev_err(&pdev->dev, "Missing device tree node.\n");
         return -EINVAL;
     }
 
+    of_property_read_u32(np, "prop", &prop);
+    pr_info("Use LVDS as %s screen\n", (prop == PRMRY) ? "prmry":"extend");
     lvds = devm_kzalloc(&pdev->dev, sizeof(struct rk32_lvds), GFP_KERNEL);
     if (!lvds) {
         dev_err(&pdev->dev, "no memory for state\n");
         return -ENOMEM;
     }
     lvds->dev = &pdev->dev;
-    rk_fb_get_prmry_screen(&lvds->screen);
+    rk_fb_get_screen(&lvds->screen, prop);
     if ((lvds->screen.type != SCREEN_RGB) && 
         (lvds->screen.type != SCREEN_LVDS) &&
         (lvds->screen.type != SCREEN_DUAL_LVDS) &&
@@ -214,7 +217,8 @@ static int rk32_lvds_probe(struct platform_device *pdev)
     }
 
     rk32_lvds = lvds;
-    rk_fb_trsm_ops_register(&trsm_lvds_ops,SCREEN_LVDS);
+    lvds->prop = prop;
+    rk_fb_trsm_ops_register(&trsm_lvds_ops, prop);
     dev_info(&pdev->dev, "rk32 lvds driver probe success\n");
 
     return 0;
diff --git a/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h b/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h
index 198311a..0a8dd45 100755
--- a/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h
@@ -34,6 +34,7 @@ struct rk32_lvds {
     struct clk              *pd;
     struct rk_screen    screen;
     bool            clk_on;
+    int prop;
 };
 
 static int inline lvds_writel(struct rk32_lvds *lvds, u32 offset, u32 val)
diff --git a/kernel/include/dt-bindings/rkfb/rk_fb.h b/kernel/include/dt-bindings/rkfb/rk_fb.h
index b903f92..05f908f 100755
--- a/kernel/include/dt-bindings/rkfb/rk_fb.h
+++ b/kernel/include/dt-bindings/rkfb/rk_fb.h
@@ -12,6 +12,7 @@
 #define NO_DUAL        0
 #define ONE_DUAL    1
 #define DUAL        2
+#define DUAL_LCD    3
 
 #define OUT_P888            0    //24bit screen,connect to lcdc D0~D23
 #define OUT_P666            1    //18bit screen,connect to lcdc D0~D17
@@ -74,6 +75,13 @@
 #define DISPLAY_POLICY_BOX    1
 #define DISPLAY_POLICY_BOX_TEMP    2
 
+#define DEFAULT_MODE    0
+#define HDMI_720P    0
+#define HDMI_1080P    1
+#define HDMI_2160P    2
+#define NTSC_CVBS    3
+#define PAL_CVBS    4
+
 /*          lvds connect config       
  *                                        
  *              LVDS_8BIT_1    LVDS_8BIT_2     LVDS_8BIT_3     LVDS_6BIT
diff --git a/kernel/include/linux/rk_fb.h b/kernel/include/linux/rk_fb.h
index e17c49c..21beff7 100755
--- a/kernel/include/linux/rk_fb.h
+++ b/kernel/include/linux/rk_fb.h
@@ -713,11 +713,12 @@ extern int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                 struct rk_lcdc_win *win, int id);
 extern int rk_fb_unregister(struct rk_lcdc_driver *dev_drv);
 extern struct rk_lcdc_driver *rk_get_lcdc_drv(char *name);
-extern int rk_fb_get_extern_screen(struct rk_screen *screen);
 extern int rk_fb_get_prmry_screen( struct rk_screen *screen);
-extern int rk_fb_set_prmry_screen(struct rk_screen *screen);
+extern int rk_fb_get_screen(struct rk_screen *screen, int prop);
+extern int rk_fb_set_screen(struct rk_screen *screen, int prop);
 extern u32 rk_fb_get_prmry_screen_pixclock(void);
-extern int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv);
+extern int rk_disp_pwr_ctr_parse_dt(struct device_node *np,
+                    struct rk_screen *rk_screen);
 extern int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv);
 extern int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv);
 extern bool is_prmry_rk_lcdc_registered(void);
diff --git a/kernel/include/linux/rk_screen.h b/kernel/include/linux/rk_screen.h
index af0ffe7..9e57081 100755
--- a/kernel/include/linux/rk_screen.h
+++ b/kernel/include/linux/rk_screen.h
@@ -61,12 +61,16 @@ struct overscan {
 *ft: the time need to display one frame time
 */
 struct rk_screen {
+    struct device    *dev;
+    int prop;
+    struct list_head *pwrlist_head;
     u16 type;
     u16 lvds_format; 
     u16 face;
     u16 color_mode;
     u8 lcdc_id;   
     u8 screen_id; 
+    int native_mode;
     struct fb_videomode mode;
     u32 post_dsp_stx;
     u32 post_dsp_sty;
@@ -144,7 +148,7 @@ struct rk29fb_info {
 };
 
 extern void set_lcd_info(struct rk_screen *screen, struct rk29lcd_info *lcd_info);
-extern size_t get_fb_size(u8 reserved_fb);
+extern size_t get_fb_size(u8 reserved_fb, struct rk_screen *screen);
 
 extern void set_tv_info(struct rk_screen *screen);
 extern void set_hdmi_info(struct rk_screen *screen);
kernel 补丁

 

(3)根据官方提供,打上 hardware 补丁

diff --git a/hardware/rockchip/hwcomposer/rk_hwcomposer.cpp b/hardware/rockchip/hwcomposer/rk_hwcomposer.cpp
index 9f4d7ce..a12bfca 100755
--- a/hardware/rockchip/hwcomposer/rk_hwcomposer.cpp
+++ b/hardware/rockchip/hwcomposer/rk_hwcomposer.cpp
@@ -62,6 +62,7 @@ static int  hwc_device_close(struct hw_device_t * dev);
 
 int         hwc_sprite_replace(hwcContext * Context, hwc_display_contents_1_t * list);
 void*       hwc_control_3dmode_thread(void *arg);
+int         hwc_parse_screen_info(int *outX, int *outY);
 
 void*   hotplug_try_register(void *arg);
 void    hotplug_get_resolution(int* w,int* h);
@@ -9428,6 +9429,10 @@ int hotplug_get_config(int flag){
     int outX = 0;
     int outY = 0;
     hotplug_parse_mode(&outX, &outY);
+    if (hwc_get_int_property("ro.htg.force", "0"))
+        hwc_parse_screen_info(&outX, &outY);
+    else
+        hotplug_parse_mode(&outX, &outY);
     info.xres = outX;
     info.yres = outY;
     info.yres_virtual = info.yres * 3;
@@ -9723,6 +9728,29 @@ OnError:
 
 }
 
+int hwc_parse_screen_info(int *outX, int *outY)
+{
+    char buf[100];
+    int width = 0;
+    int height = 0;
+    int fdExternal = -1;
+    fdExternal = open("/sys/class/graphics/fb4/screen_info", O_RDONLY);
+    if(fdExternal < 0){
+        ALOGE("hotplug_get_config:open fb screen_info error,cvbsfd=%d",fdExternal);
+        return -errno;
+    }
+    if(read(fdExternal,buf,sizeof(buf)) < 0){
+        ALOGE("error reading fb screen_info: %s", strerror(errno));
+        return -1;
+    }
+    close(fdExternal);
+    sscanf(buf,"xres:%d yres:%d",&width,&height);
+    ALOGD("hotplug_get_config:width=%d,height=%d",width,height);
+    *outX = width;
+    *outY = height;
+    return 0;
+}
+
 int hotplug_parse_mode(int *outX, int *outY)
 {
    int fd = open("/sys/class/display/HDMI/mode", O_RDONLY);
@@ -9894,7 +9922,12 @@ void *hotplug_try_register(void *arg)
     if(getHdmiMode() == 1){
         handle_hotplug_event(1, 6);
         ALOGI("hotplug_try_register at line = %d",__LINE__);
-    }else{
+    } else if (hwc_get_int_property("ro.htg.force", "0")) {
+        hotplug_free_dimbuffer();
+        hotplug_get_config(0);
+        handle_hotplug_event(1, 6);
+        ALOGI("hotplug_try_register at line = %d",__LINE__);
+    } else {
 #if (defined(RK3368_BOX) || defined(RK3288_BOX))
 #if RK3288_BOX
         if(context->mLcdcNum == 1){
hardware 补丁

 

(4)根据官方提供,打上 framework 补丁

diff --git a/frameworks/base/api/current.txt b/frameworks/base/api/current.txt
index c537823..c1cc9a6 100755
--- a/frameworks/base/api/current.txt
+++ b/frameworks/base/api/current.txt
@@ -3332,7 +3332,9 @@ package android.app {
     method public boolean isImmersive();
     method public boolean isTaskRoot();
     method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public boolean moveTaskToBack(boolean);
+    method public void moveAppToDisplay(int);
+    method public void moveExtendDisplay();
+    method public boolean moveTaskToBack(boolean);
     method public boolean navigateUpTo(android.content.Intent);
     method public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent);
     method public void onActionModeFinished(android.view.ActionMode);
@@ -3474,7 +3476,8 @@ package android.app {
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
     method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
-    method public void takeKeyEvents(boolean);
+    method public void syncDualDisplay();
+    method public void takeKeyEvents(boolean);
     method public void triggerSearch(java.lang.String, android.os.Bundle);
     method public void unregisterForContextMenu(android.view.View);
     field public static final int DEFAULT_KEYS_DIALER = 1; // 0x1
@@ -7206,7 +7209,8 @@ package android.content {
     method public abstract deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public abstract deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public abstract deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public abstract void setTheme(int);
+    method public abstract void setDualScreen(boolean);
+    method public abstract void setTheme(int);
     method public abstract deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
     method public abstract deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public abstract void startActivities(android.content.Intent[]);
@@ -7371,7 +7375,8 @@ package android.content {
     method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void setTheme(int);
+    method public void setDualScreen(boolean);
+    method public void setTheme(int);
     method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
     method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
@@ -29564,7 +29569,8 @@ package android.test.mock {
     method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void setTheme(int);
+    method public void setDualScreen(boolean);
+    method public void setTheme(int);
     method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
     method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
@@ -34808,7 +34814,9 @@ package android.view {
     method public abstract boolean isFloating();
     method public abstract boolean isShortcutKey(int, android.view.KeyEvent);
     method public final void makeActive();
-    method protected abstract void onActive();
+    method public abstract void moveAppToDisplay(int);
+    method public abstract void moveExtendDisplay();
+    method protected abstract void onActive();
     method public abstract void onConfigurationChanged(android.content.res.Configuration);
     method public abstract void openPanel(int, android.view.KeyEvent);
     method public abstract android.view.View peekDecorView();
@@ -34875,7 +34883,8 @@ package android.view {
     method public abstract boolean superDispatchKeyShortcutEvent(android.view.KeyEvent);
     method public abstract boolean superDispatchTouchEvent(android.view.MotionEvent);
     method public abstract boolean superDispatchTrackballEvent(android.view.MotionEvent);
-    method public abstract void takeInputQueue(android.view.InputQueue.Callback);
+    method public abstract void syncDualDisplay();
+    method public abstract void takeInputQueue(android.view.InputQueue.Callback);
     method public abstract void takeKeyEvents(boolean);
     method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
     method public abstract void togglePanel(int, android.view.KeyEvent);
diff --git a/frameworks/base/api/system-current.txt b/frameworks/base/api/system-current.txt
index ef86f85..0a1feda 100755
--- a/frameworks/base/api/system-current.txt
+++ b/frameworks/base/api/system-current.txt
@@ -3414,7 +3414,9 @@ package android.app {
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public boolean moveTaskToBack(boolean);
+    method public void moveAppToDisplay(int);
+    method public void moveExtendDisplay();
+    method public boolean moveTaskToBack(boolean);
     method public boolean navigateUpTo(android.content.Intent);
     method public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent);
     method public void onActionModeFinished(android.view.ActionMode);
@@ -3557,7 +3559,8 @@ package android.app {
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
     method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
-    method public void takeKeyEvents(boolean);
+    method public void syncDualDisplay();
+    method public void takeKeyEvents(boolean);
     method public void triggerSearch(java.lang.String, android.os.Bundle);
     method public void unregisterForContextMenu(android.view.View);
     field public static final int DEFAULT_KEYS_DIALER = 1; // 0x1
@@ -7444,7 +7447,8 @@ package android.content {
     method public abstract deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public abstract deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public abstract deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public abstract void setTheme(int);
+    method public abstract void setDualScreen(boolean);
+    method public abstract void setTheme(int);
     method public abstract deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
     method public abstract deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public abstract void startActivities(android.content.Intent[]);
@@ -7615,7 +7619,8 @@ package android.content {
     method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void setTheme(int);
+    method public void setDualScreen(boolean);
+    method public void setTheme(int);
     method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
     method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
@@ -31798,7 +31803,8 @@ package android.test.mock {
     method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void setTheme(int);
+    method public void setDualScreen(boolean);
+    method public void setTheme(int);
     method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
     method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
@@ -37042,6 +37048,8 @@ package android.view {
     method public abstract boolean isFloating();
     method public abstract boolean isShortcutKey(int, android.view.KeyEvent);
     method public final void makeActive();
+    method public abstract void moveAppToDisplay(int);
+    method public abstract void moveExtendDisplay();
     method protected abstract void onActive();
     method public abstract void onConfigurationChanged(android.content.res.Configuration);
     method public abstract void openPanel(int, android.view.KeyEvent);
@@ -37110,6 +37118,7 @@ package android.view {
     method public abstract boolean superDispatchKeyShortcutEvent(android.view.KeyEvent);
     method public abstract boolean superDispatchTouchEvent(android.view.MotionEvent);
     method public abstract boolean superDispatchTrackballEvent(android.view.MotionEvent);
+    method public abstract void syncDualDisplay();
     method public abstract void takeInputQueue(android.view.InputQueue.Callback);
     method public abstract void takeKeyEvents(boolean);
     method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
diff --git a/frameworks/base/core/java/android/app/Activity.java b/frameworks/base/core/java/android/app/Activity.java
index ce65cf3..5159661 100755
--- a/frameworks/base/core/java/android/app/Activity.java
+++ b/frameworks/base/core/java/android/app/Activity.java
@@ -6495,4 +6495,22 @@ public class Activity extends ContextThemeWrapper
          */
         public void onTranslucentConversionComplete(boolean drawComplete);
     }
+
+    public void moveAppToDisplay(int id) {
+    if (mWindow != null) {
+            mWindow.moveAppToDisplay(id);
+        }
+    }
+
+    public void syncDualDisplay() {
+    if (mWindow != null) {
+        mWindow.syncDualDisplay();
+    }
+    }
+
+    public void moveExtendDisplay() {
+    if (mWindow != null) {
+        mWindow.moveExtendDisplay();
+    }
+    } 
 }
diff --git a/frameworks/base/core/java/android/app/ContextImpl.java b/frameworks/base/core/java/android/app/ContextImpl.java
index 6c9c804..ebee424 100755
--- a/frameworks/base/core/java/android/app/ContextImpl.java
+++ b/frameworks/base/core/java/android/app/ContextImpl.java
@@ -122,6 +122,7 @@ import android.os.SystemVibrator;
 import android.os.UserManager;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
+import android.provider.Settings;
 import android.print.IPrintManager;
 import android.print.PrintManager;
 import android.service.fingerprint.IFingerprintService;
@@ -2224,6 +2225,32 @@ class ContextImpl extends Context {
         return mDisplayAdjustments;
     }
 
+    @Override
+    public void setDualScreen(boolean enable) {
+
+    int value = 0;
+    if (enable) {
+        value = 1;
+    } else {
+        Settings.System.putInt(getContentResolver(), Settings.System.DUAL_SCREEN_ICON_USED, 0);
+    }
+    Settings.System.putInt(getContentResolver(), Settings.System.DUAL_SCREEN_MODE, value);
+
+    try {
+                IActivityManager am = ActivityManagerNative.getDefault();
+                Configuration config = am.getConfiguration();
+
+                // Will set userSetLocale to indicate this isn't some passing default - the user
+                // wants this remembered
+                config.setDualScreenFlag(enable);
+
+                am.updateConfiguration(config);
+
+        } catch (RemoteException e) {
+                // Intentionally left blank
+         }
+    }
+
     private File getDataDirFile() {
         if (mPackageInfo != null) {
             return mPackageInfo.getDataDirFile();
diff --git a/frameworks/base/core/java/android/content/Context.java b/frameworks/base/core/java/android/content/Context.java
index 7028dfe..25268fc 100755
--- a/frameworks/base/core/java/android/content/Context.java
+++ b/frameworks/base/core/java/android/content/Context.java
@@ -3460,4 +3460,6 @@ public abstract class Context {
     public boolean isRestricted() {
         return false;
     }
+    
+    public abstract void setDualScreen(boolean enable);
 }
diff --git a/frameworks/base/core/java/android/content/ContextWrapper.java b/frameworks/base/core/java/android/content/ContextWrapper.java
index cfae1cf..4ecbea6 100755
--- a/frameworks/base/core/java/android/content/ContextWrapper.java
+++ b/frameworks/base/core/java/android/content/ContextWrapper.java
@@ -710,4 +710,9 @@ public class ContextWrapper extends Context {
     public DisplayAdjustments getDisplayAdjustments(int displayId) {
         return mBase.getDisplayAdjustments(displayId);
     }
+    
+    @Override
+    public void setDualScreen(boolean enable) {
+        mBase.setDualScreen(enable);
+    }
 }
diff --git a/frameworks/base/core/java/android/view/IWindowSession.aidl b/frameworks/base/core/java/android/view/IWindowSession.aidl
index 3fb19c2..3192265 100755
--- a/frameworks/base/core/java/android/view/IWindowSession.aidl
+++ b/frameworks/base/core/java/android/view/IWindowSession.aidl
@@ -232,4 +232,7 @@ interface IWindowSession {
     void updatePositionAndSize(IWindow window,int x,int y,int widht,int height);
 
     void setOnlyShowInExtendDisplay(IWindow window,int transit);
+    
+    void moveAppToDisplay(IWindow window, int id);
+    void syncDualDisplay();
 }
diff --git a/frameworks/base/core/java/android/view/Window.java b/frameworks/base/core/java/android/view/Window.java
index f74d92c..03744d3 100755
--- a/frameworks/base/core/java/android/view/Window.java
+++ b/frameworks/base/core/java/android/view/Window.java
@@ -1896,5 +1896,7 @@ public abstract class Window {
      */
     public abstract void setNavigationBarColor(int color);
 
-
+    public abstract void moveAppToDisplay(int id);
+    public abstract void syncDualDisplay();
+    public abstract void moveExtendDisplay();
 }
diff --git a/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 5333c35..c309cc3 100755
--- a/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -5136,5 +5136,24 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
         }
     }
      
+    @Override
+    public void moveAppToDisplay(int id) {
+        try {
+            mDecor.getRootWindowSession().moveAppToDisplay(mDecor.getWindow(), id);
+        } catch (RemoteException ex) {}
+    }
 
+    @Override
+    public void syncDualDisplay() {
+        try {
+                mDecor.getRootWindowSession().syncDualDisplay();
+        } catch (RemoteException ex) {}
+    }
+
+    @Override
+    public void moveExtendDisplay() {
+        try {
+            mDecor.getRootWindowSession().setOnlyShowInExtendDisplay(mDecor.getWindow(),-1);
+        } catch (RemoteException ex) {}
+    }
 }
diff --git a/frameworks/base/services/core/java/com/android/server/wm/Session.java b/frameworks/base/services/core/java/com/android/server/wm/Session.java
index ec92751..0f70d64 100755
--- a/frameworks/base/services/core/java/com/android/server/wm/Session.java
+++ b/frameworks/base/services/core/java/com/android/server/wm/Session.java
@@ -216,6 +216,14 @@ final class Session extends IWindowSession.Stub
     public void setOnlyShowInExtendDisplay(IWindow window,int transit){
         mService.setOnlyShowInExtendDisplay(this, window,transit);
     }    
+ 
+    public void moveAppToDisplay(IWindow window, int id) {
+        mService.moveAppToDisplay(this, window, id);
+    }
+
+    public void syncDualDisplay() {
+        mService.syncDualDisplay();
+    }
 
     public void performDeferredDestroy(IWindow window) {
         mService.performDeferredDestroyWindow(this, window);
diff --git a/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java b/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
index 37281ca..433a161 100755
--- a/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10050,6 +10050,7 @@ public class WindowManagerService extends IWindowManager.Stub
         public static final int SET_MULTIWINDOW_MODE_ACTION = 41;
         public static final int DO_TASK_DISPLAY_CHANGED = 42;
         public static final int MULTIWINDOW_MOVE_BACK_ACTION = 43;
+        public static final int MOVE_APP_TO_DISPLAY = 44;
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -10621,6 +10622,11 @@ public class WindowManagerService extends IWindowManager.Stub
                     } catch (RemoteException e) {
                     }
                     break;
+                case MOVE_APP_TO_DISPLAY:
+                    synchronized (mWindowMap) {
+                        moveAppToIdDisplay(msg.arg1, msg.arg2, (int)msg.obj);
+                    }
+                    break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG, "handleMessage: exit");
@@ -14493,6 +14499,216 @@ if(mCurConfiguration.enableMultiWindow()&&false){
     }
     Binder.restoreCallingIdentity(origId);
     }
+    
+    public void moveAppToDisplay(Session session, IWindow client, int displayid) {
+        long origId = Binder.clearCallingIdentity();
+            synchronized(mWindowMap){
+                    if(mDisplayContents == null || mDisplayContents.size() <= 1){
+                            return;
+                    }
+                    final int displayCount = mDisplayContents.size();
+                    DisplayContent defaultContent = getDefaultDisplayContentLocked();
+                    int displayId = 0;
+            boolean hasTargetDisplay = false;
+                    for(int i = 0; i < displayCount;i++){
+                            final DisplayContent content = mDisplayContents.valueAt(i);
+                                displayId = content.getDisplayId();
+                if (displayId == displayid) {
+                    hasTargetDisplay = true;
+                                    break;
+                }
+                    }
+                    if(!hasTargetDisplay){
+                            return;
+                    }
+                    if(!okToDisplay()){
+                            return;
+                    }
+                    WindowState current = windowForClientLocked(session, client, false);
+                    if(isHomeWindow(current)){
+                            return;
+                    }
+                    AppWindowToken wtoken = current.mAppToken;
+                    if(wtoken == null){
+                            return;
+                    }
+
+            if(current.getDisplayId() == displayid) return;
+
+                    Settings.System.putInt(mContext.getContentResolver(),
+                            Settings.System.DUAL_SCREEN_ICON_USED, 1);
+                    int groupId = wtoken.groupId;
+                    mH.sendMessage(mH.obtainMessage(H.MOVE_APP_TO_DISPLAY, groupId, displayid, current.getDisplayId()));
+            }
+            Binder.restoreCallingIdentity(origId);
+    }
+
+    public void syncDualDisplay() {
+        updateDisplayShowSynchronization();
+    }
+
+    // case as follow:
+    // 1. mast screen -> external screen
+    // 2. external screen -> mast screen
+    // 3. external screen -> external screen
+    private void moveAppToIdDisplay(int groupId, int displayid, int currentid) {
+        long origId = Binder.clearCallingIdentity();
+        int curMoveTaskId = -1;
+        synchronized(mWindowMap){
+                if(mDisplayContents == null || mDisplayContents.size() <= 1) {
+                        return;
+                }
+        DisplayContent defaultContent = getDefaultDisplayContentLocked();
+        int defaultDisplayId = defaultContent.getDisplayId();
+        final int displayCount = mDisplayContents.size();
+        int displayId = 0;
+        DisplayContent currentContent = null;
+        DisplayContent targetContent = null;
+        for(int i = 0; i < displayCount;i++) {
+                        final DisplayContent content = mDisplayContents.valueAt(i);
+                        if (content.getDisplayId() == displayid) {
+                                targetContent = content;
+                        }
+            if (content.getDisplayId() == currentid) {
+                currentContent = content;
+            }
+                }
+
+        if (targetContent == null) return;
+        if (currentContent == null) return;
+
+        if(!okToDisplay()){
+                        return;
+                }
+
+        WindowState win = null;
+                WindowList windows = currentContent.getWindowList();
+        try {
+                        SurfaceControl.openTransaction();
+            if (displayid == defaultDisplayId) {
+                int max = 1;
+                    int countOfTwoScreen = 0;
+                WindowList defaultWindows = defaultContent.getWindowList();
+                HashMap visibleAppsOfTwoScreen = new HashMap();
+                ArrayList pendingRemoveOfTwoScreen = new ArrayList();
+                for(int j = 0; j < windows.size(); j++) {
+                    win = windows.get(j);
+                    if (win == null) continue;
+                    if (ignoreWindow(win,false) || win.mAppToken == null) continue;
+                    if(isHomeWindow(win)) break;
+                    if(!win.isDefaultDisplay()) {
+                        AppWindowToken tk = win.mAppToken;
+                        if(!visibleAppsOfTwoScreen.containsKey(tk.groupId)){
+                                            visibleAppsOfTwoScreen.put(tk.groupId, tk);
+                            if (tk.groupId == groupId) {
+                                pendingRemoveOfTwoScreen.add(tk);
+                            }
+                        }
+                        /*if(!visibleAppsOfTwoScreen.containsKey(tk.groupId)){
+                                            visibleAppsOfTwoScreen.put(tk.groupId, tk);
+                                            countOfTwoScreen++;
+                                            if(countOfTwoScreen > max){
+                                                    pendingRemoveOfTwoScreen.add(tk);
+                                            }
+                                    }*/
+                    }
+                }
+                if(pendingRemoveOfTwoScreen.size() > 0){
+                    for(int k =0;k < pendingRemoveOfTwoScreen.size(); k++){
+                        int removeTaskId = pendingRemoveOfTwoScreen.get(k).groupId;
+                        for(int m = 0; m < windows.size(); m++){
+                            WindowState ws = windows.get(m);
+                            int mGroupId = ws.mAppToken.groupId;
+                            if (mGroupId == removeTaskId) {
+                                final ArrayList stacks = defaultContent.getStacks();
+                                final int numStacks = stacks.size();
+                                int stackNdx = 1;
+                                final ArrayList tasks = stacks.get(stackNdx).getTasks();
+                                final int numTasks = tasks.size();
+                                for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+                                                                if (tasks.get(taskNdx).taskId != ws.taskId)  continue;
+                                                                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                                                                if (!tokens.contains(ws.mAppToken)) { // wrong happened
+                                                                        tasks.get(taskNdx).addAppToken(tokens.size(), ws.mAppToken);
+                                                                }
+                                                                //break;
+                                                        }
+                                windows.remove(ws);
+                                ws.mDisplayContent = defaultContent;
+                                                    if(ws.mWinAnimator != null){
+                                                            int layerStack = defaultContent.getDisplay().getLayerStack();
+                                                            if(ws.mWinAnimator.mSurfaceControl != null){
+                                                                    ws.mWinAnimator.mSurfaceControl.setLayerStack(layerStack);
+                                                            }
+                                                    }
+                                                    defaultWindows.add(ws);
+                            }
+                        }
+                    }
+                }
+            } else if (currentid == defaultDisplayId) {
+                WindowList targetDisplayAddList = new WindowList();
+                            WindowList targetDisplayWindows = targetContent.getWindowList();
+                for(int i=windows.size()-1; i >= 0; i--){
+                    win = windows.get(i);
+                                    if(win == null){
+                                            continue;
+                                    }
+                                    if (win.mAppToken == null){
+                                            continue;
+                                    }
+                    int mGroupId = win.mAppToken.groupId;
+                                    if(mGroupId == groupId){
+
+                                            final ArrayList stacks = currentContent.getStacks();
+                                            final int numStacks = stacks.size();
+                                            int stackNdx = 1;
+                        final ArrayList tasks = stacks.get(stackNdx).getTasks();
+
+                        final int numTasks = tasks.size();
+                        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+                            if (tasks.get(taskNdx).taskId != win.taskId) continue;
+                            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                            for (int n = 0; n<tokens.size();) {
+                                AppWindowToken awt = tokens.get(n);
+                                if (tokens.contains(awt) || awt.removed) {  // no useful
+                                    tasks.get(taskNdx).removeAppToken(awt);
+                                }
+                            }
+                        }
+                                            windows.remove(win);
+                                            win.mDisplayContent = targetContent;
+
+                                            if(win.mWinAnimator != null){
+                                                    int layerStack = targetContent.getDisplay().getLayerStack();
+                                                    if(win.mWinAnimator.mSurfaceControl!= null){
+                                                            win.mWinAnimator.mSurfaceControl.setLayerStack(layerStack);
+                                                    }
+                                            }
+                                            targetDisplayAddList.add(0, win);
+                                    }
+                }
+                targetDisplayWindows.addAll(targetDisplayAddList);
+            } else {
+                // external screen -> external screen
+            }
+
+            for (int i = 0; i < displayCount; i++) {
+                                final DisplayContent content = mDisplayContents.valueAt(i);
+                                assignLayersLocked(content.getWindowList());
+                                content.layoutNeeded = true;
+                        }
+            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false);
+                        mAppTransition.setReady();
+                        performLayoutAndPlaceSurfacesLocked();
+            
+                }finally {
+                        SurfaceControl.closeTransaction();
+                }
+
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
 
     public void moveWindowToSecondDisplay() {
         int topId = -100;
diff --git a/frameworks/base/test-runner/src/android/test/mock/MockContext.java b/frameworks/base/test-runner/src/android/test/mock/MockContext.java
index 3378872..cd24654 100755
--- a/frameworks/base/test-runner/src/android/test/mock/MockContext.java
+++ b/frameworks/base/test-runner/src/android/test/mock/MockContext.java
@@ -643,4 +643,9 @@ public class MockContext extends Context {
     public File[] getExternalMediaDirs() {
         throw new UnsupportedOperationException();
     }
+    
+    @Override
+    public void setDualScreen(boolean enable) {
+        throw new UnsupportedOperationException();
+    }
 }
framework 补丁

 

(5)官方提供的补丁打完了,但是此时编译可能会报错,如下:

cts/tests/tests/view/src/android/view/cts/WindowTest.java:846: error: WindowTest.MockWindow is not abstract and does not override abstract method moveExtendDisplay() in Window
public class MockWindow extends Window {
^
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
1 error
make: *** [out/target/common/obj/APPS/CtsViewTestCases_intermediates/classes-full-debug.jar] Error 41
make: *** Waiting for unfinished jobs....
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Warning: AndroidManifest.xml already defines minSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest.
Warning: AndroidManifest.xml already defines targetSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest.

#### make failed to build some targets (03:55 (mm:ss)) ####

根据编译错误提示,需要修改 cts/tests/tests/view/src/android/view/cts/WindowTest.java 文件。

diff --git a/cts/tests/tests/view/src/android/view/cts/WindowTest.java b/cts/tests/tests/view/src/android/view/cts/WindowTest.java
index 3c5386d..8732ae7 100755
--- a/cts/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/cts/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -998,6 +998,19 @@ public class WindowTest extends ActivityInstrumentationTestCase2<WindowCtsActivi
         }
 
         @Override
+        public void moveAppToDisplay(int id) {
+        }
+
+        @Override
+        public void syncDualDisplay() {
+        }
+
+        @Override
+        public void moveExtendDisplay() {
+        }
+
+
+        @Override
         public void setDefaultWindowFormat(int format) {
             super.setDefaultWindowFormat(format);
         }

 

(6)此时可以编译成功,在屏参正确的前提下,主屏显示正常,副屏出现花屏,需要在 system.prop 里添加属性 ro.htg.force=1。

diff --git a/device/rockchip/rk3288/system.prop b/device/rockchip/rk3288/system.prop
index 26a2b09..c4f2c3d 100755
--- a/device/rockchip/rk3288/system.prop
+++ b/device/rockchip/rk3288/system.prop
@@ -12,6 +12,7 @@ rild.libpath=/system/lib/libril-rk29-dataonly.so
 rild.libargs=-d /dev/ttyACM0
 persist.tegra.nvmmlite = 1
 ro.audio.monitorOrientation=true
+ro.htg.force=1
 
 #NFC
 debug.nfc.fw_download=false

 

此时大功告成,双屏可以正常显示,也可以实现双屏异显。

 

如果 lcd 出现重复性黑屏亮屏,找到对应的屏参文件,在正常范围内调节频率 clk 值即可。

display-timings {
                        native-mode = <&ee101ia>;
                        ee101ia: timing0 {
                screen-type = ;
                lvds-format = ;
                out-face    = ;
                color-mode = ;
                // 调节 lcd 频率
                clock-frequency = <148500000>;
                hactive = <1920>;
                vactive = <1080>;

 

转载于:https://www.cnblogs.com/lialong1st/p/9149213.html

你可能感兴趣的:(RK3288 增加双屏异显 eDP+LVDS)