zoukankan      html  css  js  c++  java
  • 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 = <SCREEN_EDP>;
                     out-face    = <OUT_P666>;
                     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 = <SCREEN_DUAL_LVDS>;
                     lvds-format = <LVDS_8BIT_1>;
                     out-face    = <OUT_P888>;
    @@ -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 = <DUAL>;
    -    rockchip,uboot-logo-on = <1>;
    +    rockchip,disp-mode = <DUAL_LCD>;
    +    rockchip,uboot-logo-on = <0>;
     };
     
     &rk_screen {
    -     display-timings = <&disp_timings>;
    +    status = "okay";
    +    screen0 {
    +        screen_prop = <PRMRY>;
    +        native-mode = <DEFAULT_MODE>;
    +        power_ctr {
    +            lcd_en {
    +                rockchip,power_type = <GPIO>;
    +                gpios = <&gpio7 GPIO_A5 GPIO_ACTIVE_HIGH>;
    +                rockchip,delay = <10>;
    +            };
    +            /*lcd_cs {
    +                rockchip,power_type = <GPIO>;
    +                gpios = <&gpio7 GPIO_A4 GPIO_ACTIVE_HIGH>;
    +                rockchip,delay = <10>;
    +            };*/
    +        };
    +        #include "lcd-NV156FH1.dtsi"
    +    };
    +    screen1 {
    +        screen_prop = <EXTEND>;
    +        native-mode = <DEFAULT_MODE>;
    +        power_ctr {
    +            lcd_en {
    +                rockchip,power_type = <GPIO>;
    +                gpios = <&gpio7 GPIO_A3 GPIO_ACTIVE_HIGH>;
    +                rockchip,delay = <10>;
    +            };
    +            /*lcd_cs {
    +                rockchip,power_type = <GPIO>;
    +                gpios = <&gpio7 GPIO_A4 GPIO_ACTIVE_HIGH>;
    +                rockchip,delay = <10>;
    +            };*/
    +        };
    +        #include "lcd-ZJ080NA-08A.dtsi"
    +    };
    +};
    +
    +&edp {
    +    status = "okay";
    +    prop = <PRMRY>;
    +};
    +
    +&lvds {
    +    status = "okay";
    +    prop = <EXTEND>;
     };
     
     /*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 = <GPIO>;
                 gpios = <&gpio7 GPIO_A3 GPIO_ACTIVE_HIGH>;
                 rockchip,delay = <200>;
             };
             
    -        /*lcd_cs:lcd_cs {
    +        lcd_cs:lcd_cs {
                 rockchip,power_type = <GPIO>;
                 gpios = <&gpio7 GPIO_A4 GPIO_ACTIVE_HIGH>;
                 rockchip,delay = <10>;
    -        };*/
    -
    +        };
    +        */
             /*lcd_rst:lcd_rst {
                 rockchip,power_type = <GPIO>;
                 gpios = <&gpio3 GPIO_D6 GPIO_ACTIVE_HIGH>;
    @@ -615,7 +659,7 @@ clock-frequency = <50000000>;
     };
     
     &hdmi {
    -    status = "okay";
    +    status = "disabled";
         rockchip,hdmi_video_source = <DISPLAY_SOURCE_LCDC1>;
     };
     
    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!
    ",
    -               __func__, type);
    -        break;
    -    }
    +    if (type == PRMRY)
    +        trsm_prmry_ops = ops;
    +    else if (type == EXTEND)
    +        trsm_extend_ops = ops;
    +    else
    +        pr_err("%s, type:%d
    ", __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!
    ",
    -               __func__, type);
    -        break;
    -    }
    +    if (type == PRMRY)
    +        ops = trsm_prmry_ops;
    +    else if (type == EXTEND)
    +        ops = trsm_extend_ops;
    +    else
    +        pr_err("%s, type:%d
    ", __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
    ",
    -            dev_drv->id);
    +        dev_err(rk_screen->dev, "can't find power_ctr node for lcdc%d
    ",
    +            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
    ",
    +                    dev_err(rk_screen->dev, "%s ivalid gpio
    ",
                             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
    ",
                             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!
    ");
    +                    dev_err(rk_screen->dev, "get regulator name failed!
    ");
                     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
    "
    @@ -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
    ",
    +            __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
    ",
    +            __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
    ");
             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<<<<<<<<<<<<<<<<<<<<
    ");
    +    pr_err(">>please init %s screen info in dtsi file<<
    ",
    +           (prop == PRMRY) ? "prmry" : "extend");
    +    pr_err(">>>>>>>>>>>>>>>>>>>>error<<<<<<<<<<<<<<<<<<<<
    ");
    +}
     
     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.
    ");
             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
    ",
    +                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
    ",
    +            (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
    ",
    +            (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
    ",
    -                ret ? "failed" : "success");
    -    return ret;
    +    
    +    dev_info(&pdev->dev, "rockchip screen probe success
    ");
    +    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.
    ");
             return -EINVAL;
         }
    +    of_property_read_u32(np, "prop", &prop);
    +    pr_info("Use EDP as %s screen
    ", (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
    ");
             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!
    ");
             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.
    ");
             return -EINVAL;
         }
     
    +    of_property_read_u32(np, "prop", &prop);
    +    pr_info("Use LVDS as %s screen
    ", (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
    ");
             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
    ");
     
         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<Integer,AppWindowToken> visibleAppsOfTwoScreen = new HashMap<Integer,AppWindowToken>();
    +                ArrayList<AppWindowToken> pendingRemoveOfTwoScreen = new ArrayList<AppWindowToken>();
    +                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<TaskStack> stacks = defaultContent.getStacks();
    +                                final int numStacks = stacks.size();
    +                                int stackNdx = 1;
    +                                final ArrayList<Task> 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<TaskStack> stacks = currentContent.getStacks();
    +                                            final int numStacks = stacks.size();
    +                                            int stackNdx = 1;
    +                        final ArrayList<Task> 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 = <SCREEN_DUAL_LVDS>;
                    lvds-format = <LVDS_8BIT_1>;
                    out-face    = <OUT_P888>;
                    color-mode = <COLOR_RGB>;
                    // 调节 lcd 频率
                    clock-frequency = <148500000>;
                    hactive = <1920>;
                    vactive = <1080>;

    如果单屏调试都正常点亮,打补丁后,点不亮或者有花屏现象,尝试增大对应屏的电源使能延时 

     lcd_en {
        rockchip,power_type = <GPIO>;
        gpios = <&gpio7 GPIO_A5 GPIO_ACTIVE_HIGH>;
    -   rockchip,delay = <10>;
    +   rockchip,delay = <100>;
    };
  • 相关阅读:
    浅谈localStorage本地存储
    前端代码中经常遇到的问题
    http状态码
    Transition 所支持的css属性
    ie8下的透明 问题
    #event.initMouseEvent
    svg 文字
    前端工作流程转变
    理解javascript 回调函数
    不要被npm、NodeJs、npm、webpack、vue-cli 这些名词搞晕
  • 原文地址:https://www.cnblogs.com/lialong1st/p/9149213.html
Copyright © 2011-2022 走看看