[RK3288][Android6.0] 调试笔记 --- 双屏显示内核Patch

时间:2022-12-28 23:25:50

Platform: RK3288
OS: Android 6.0
Kernel: 3.10.92

根据5.1的双屏显示patch,在android6.0上修改了下,因为没硬件环境,所以未经验证,仅供参考。edp是主屏,lvds是副屏。

edp屏:
lcd-LM133LFL01-EDP1920x1080_dual.dtsi

/*
 * RockChip. DisplayPort screen LM133LFL01 
 *
 */

disp_timings: display-timings {
    native-mode = <&lm133lfl01>;
    lm133lfl01: timing0 {
        screen-type = <SCREEN_EDP>;
        out-face    = <OUT_P666>;
        clock-frequency = <43200000>;
        hactive = <1920>;
        vactive = <1080>;
        hback-porch = <148>;
        hfront-porch = <88>;
        vback-porch = <36>;
        vfront-porch = <4>;
        hsync-len = <44>;
        vsync-len = <5>;
        hsync-active = <1>;
        vsync-active = <1>;
        de-active = <0>;
        pixelclk-active = <0>;
        swap-rb = <0>;
        swap-rg = <0>;
        swap-gb = <0>;
    };
};

lvds屏:
arch/arm/boot/dts/lcd-b101ew05_dual.dtsi

display-timings {
    native-mode = <&b101ew05>;
    b101ew05: timing0 {
        screen-type = <SCREEN_LVDS>;
        lvds-format = <LVDS_8BIT_2>;
        out-face    = <OUT_D888_P666>;
        color-mode = <COLOR_RGB>;
        clock-frequency = <71000000>;
        hactive = <1024>;
        vactive = <600>;
        hback-porch = <100>;
        hfront-porch = <18>;
        vback-porch = <8>;
        vfront-porch = <6>;
        hsync-len = <10>;
        vsync-len = <2>;
        hsync-active = <0>;
        vsync-active = <0>;
        de-active = <0>;
        pixelclk-active = <0>;
        swap-rb = <0>;
        swap-rg = <0>;
        swap-gb = <0>;
    };
};

其余部分:

diff --git a/arch/arm/boot/dts/rk3288-tb_8846.dts b/arch/arm/boot/dts/rk3288-tb_8846.dts
index f80578e..ec71f93 100755
--- a/arch/arm/boot/dts/rk3288-tb_8846.dts
+++ b/arch/arm/boot/dts/rk3288-tb_8846.dts
@@ -1,9 +1,11 @@
 /dts-v1/;

 #include "rk3288.dtsi"
-//#include "lcd-b101ew05.dtsi"
-#include "lcd-F402.dtsi"
-#include "vtl_ts_sdk8846.dtsi"
+
+//#include "lcd-F402.dtsi"
+//#include "vtl_ts_sdk8846.dtsi"
+
 #include "rk3288-cif-sensor.dtsi"
 / {
    fiq-debugger {
@@ -607,14 +609,60 @@
 };

 &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>;//PRMRY
+       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-LM133LFL01-EDP1920x1080_dual.dtsi"
+   };
+   screen1 {
+       screen_prop = <EXTEND>;//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-b101ew05_dual.dtsi"
+   };
 };

+
+&lvds {
+   status = "okay";
+   prop = <EXTEND>;
+};
+
+&edp {
+   status = "okay";
+   prop = <PRMRY>;
+};
+
+
 /*lcdc0 as PRMRY(LCD),lcdc1 as EXTEND(HDMI)*/
 &lcdc0 {
    status = "okay";
@@ -629,7 +677,7 @@
            rockchip,delay = <5>;
        };*/

-       lcd_en:lcd_en {
+       /* lcd_en:lcd_en { rockchip,power_type = <GPIO>; gpios = <&gpio7 GPIO_A3 GPIO_ACTIVE_HIGH>; rockchip,delay = <10>; @@ -639,7 +687,7 @@ rockchip,power_type = <GPIO>; gpios = <&gpio7 GPIO_A4 GPIO_ACTIVE_HIGH>; rockchip,delay = <10>; - }; + }; */

        /*lcd_rst:lcd_rst { rockchip,power_type = <GPIO>; @@ -657,7 +705,7 @@ }; &hdmi { - status = "okay"; + status = "disabled"; rockchip,hdmi_video_source = <DISPLAY_SOURCE_LCDC1>; }; diff --git a/arch/arm/configs/rockchip_defconfig b/arch/arm/configs/rockchip_defconfig index 40edcbf..78a3f27 100644 --- a/arch/arm/configs/rockchip_defconfig +++ b/arch/arm/configs/rockchip_defconfig @@ -433,6 +433,7 @@ CONFIG_DP_ANX6345=y CONFIG_RK32_DP=y CONFIG_MIPI_DSI=y CONFIG_RK32_MIPI_DSI=y +CONFIG_SMART_DUAL_LCD=y CONFIG_RK_HDMI=y CONFIG_RK_TVENCODER=y CONFIG_RK1000_TVOUT=y diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 6034139..39543bc 100755 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -58,6 +58,9 @@ config THREE_FB_BUFFER help select y if android support three buffer,like Jelly Bean +config SMART_DUAL_LCD + bool"smart dual lcd support" + default n source "drivers/video/rockchip/lcdc/Kconfig" source "drivers/video/rockchip/screen/Kconfig" diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index c45387c..8c5eb98 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -71,9 +71,16 @@ 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; + +#ifndef CONFIG_SMART_DUAL_LCD 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; +#else +static struct rk_fb_trsm_ops *trsm_prmry_ops; +static struct rk_fb_trsm_ops *trsm_extend_ops; +#endif + static int uboot_logo_on; static int rk_fb_debug_lvl; @@ -107,6 +114,7 @@ int rk_fb_get_display_policy(void) int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type) { +#ifndef CONFIG_SMART_DUAL_LCD switch (type) { case SCREEN_RGB: case SCREEN_LVDS: @@ -127,13 +135,23 @@ int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type) __func__, type); break; } +#else + if (type == PRMRY) + trsm_prmry_ops = ops; + else if (type == EXTEND) + trsm_extend_ops = ops; + else + pr_err("%s, type:%d\n", __func__, type); +#endif + return 0; } struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type) { - struct rk_fb_trsm_ops *ops; + struct rk_fb_trsm_ops *ops; +#ifndef CONFIG_SMART_DUAL_LCD switch (type) { case SCREEN_RGB: case SCREEN_LVDS: @@ -155,6 +173,15 @@ struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type) __func__, type); break; } +#else + if (type == PRMRY) + ops = trsm_prmry_ops; + else if (type == EXTEND) + ops = trsm_extend_ops; + else + pr_err("%s, type:%d\n", __func__, type); +#endif + return ops; } @@ -309,10 +336,19 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel) /* * rk display power control parse from dts */
+#ifndef CONFIG_SMART_DUAL_LCD
 int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
+#else
+int rk_disp_pwr_ctr_parse_dt(struct device_node *np, struct rk_screen *rk_screen)
+#endif
 {
+#ifndef CONFIG_SMART_DUAL_LCD
    struct device_node *root = of_get_child_by_name(dev_drv->dev->of_node,
                            "power_ctr");
+#else
+   struct device_node *root = of_get_child_by_name(np, "power_ctr");
+#endif
+
    struct device_node *child;
    struct rk_disp_pwr_ctr_list *pwr_ctr;
    struct list_head *pos;
@@ -321,10 +357,20 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
    u32 debug = 0;
    int ret;

+#ifndef CONFIG_SMART_DUAL_LCD
    INIT_LIST_HEAD(&dev_drv->pwrlist_head);
+#else
+   INIT_LIST_HEAD(rk_screen->pwrlist_head);
+#endif
+
    if (!root) {
+#ifndef CONFIG_SMART_DUAL_LCD
        dev_err(dev_drv->dev, "can't find power_ctr node for lcdc%d\n",
            dev_drv->id);
+#else
+       dev_err(rk_screen->dev, "can't find power_ctr node for lcdc%d\n",
+                   rk_screen->lcdc_id);
+#endif
        return -ENODEV;
    }

@@ -337,17 +383,29 @@ 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)) {
+#ifndef CONFIG_SMART_DUAL_LCD
                    dev_err(dev_drv->dev, "%s ivalid gpio\n",
                        child->name);
+#else
+                   dev_err(rk_screen->dev, "%s ivalid gpio\n",
+                                           child->name);
+#endif
+
                    return -EINVAL;
                }
                pwr_ctr->pwr_ctr.atv_val = !(flags & OF_GPIO_ACTIVE_LOW);
                ret = gpio_request(pwr_ctr->pwr_ctr.gpio,
                           child->name);
                if (ret) {
+#ifndef CONFIG_SMART_DUAL_LCD
                    dev_err(dev_drv->dev,
                        "request %s gpio fail:%d\n",
                        child->name, ret);
+#else
+                   dev_err(rk_screen->dev,
+                       "request %s gpio fail:%d\n",
+                       child->name, ret);
+#endif
                }

            } else {
@@ -356,7 +414,11 @@ 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))
+#ifndef CONFIG_SMART_DUAL_LCD
                    dev_err(dev_drv->dev, "get regulator name failed!\n");
+#else
+                   dev_err(rk_screen->dev, "get regulator name failed!\n");
+#endif
                if (!of_property_read_u32(child, "rockchip,regulator_voltage", &val))
                    pwr_ctr->pwr_ctr.volt = val;
                else
@@ -368,13 +430,21 @@ 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;
+#ifndef CONFIG_SMART_DUAL_LCD
        list_add_tail(&pwr_ctr->list, &dev_drv->pwrlist_head);
+#else
+       list_add_tail(&pwr_ctr->list, rk_screen->pwrlist_head);
+#endif
    }

    of_property_read_u32(root, "rockchip,debug", &debug);

    if (debug) {
+#ifndef CONFIG_SMART_DUAL_LCD
        list_for_each(pos, &dev_drv->pwrlist_head) {
+#else
+       list_for_each(pos, rk_screen->pwrlist_head) {
+#endif
            pwr_ctr = list_entry(pos, struct rk_disp_pwr_ctr_list,
                         list);
            pr_info("pwr_ctr_name:%s\n"
@@ -400,10 +470,25 @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv)
    struct pwr_ctr *pwr_ctr;
    struct regulator *regulator_lcd = NULL;
    int count = 10;
-
+#ifndef CONFIG_SMART_DUAL_LCD
    if (list_empty(&dev_drv->pwrlist_head))
        return 0;
-   list_for_each(pos, &dev_drv->pwrlist_head) {
+#else
+   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;
+#endif
+
+#ifndef CONFIG_SMART_DUAL_LCD
+   list_for_each(pos, &dev_drv->pwrlist_head) 
+#else
+   list_for_each(pos, dev_drv->cur_screen->pwrlist_head) 
+#endif
+   {
        pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list,
                      list);
        pwr_ctr = &pwr_ctr_list->pwr_ctr;
@@ -446,9 +531,25 @@ int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv)
    struct regulator *regulator_lcd = NULL;
    int count = 10;

+#ifndef CONFIG_SMART_DUAL_LCD
    if (list_empty(&dev_drv->pwrlist_head))
        return 0;
-   list_for_each(pos, &dev_drv->pwrlist_head) {
+#else
+   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;
+#endif
+
+#ifndef CONFIG_SMART_DUAL_LCD
+   list_for_each(pos, &dev_drv->pwrlist_head) 
+#else
+   list_for_each(pos, dev_drv->cur_screen->pwrlist_head) 
+#endif
+   {
        pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list,
                      list);
        pwr_ctr = &pwr_ctr_list->pwr_ctr;
@@ -478,7 +579,7 @@ int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv)
    }
    return 0;
 }
-
+       
 int rk_fb_video_mode_from_timing(const struct display_timing *dt,
                 struct rk_screen *screen)
 {
@@ -533,7 +634,11 @@ int rk_fb_prase_timing_dt(struct device_node *np, struct rk_screen *screen)
        pr_err("parse display timing err\n");
        return -EINVAL;
    }
+#ifndef CONFIG_SMART_DUAL_LCD
    dt = display_timings_get(disp_timing, disp_timing->native_mode);
+#else
+   dt = display_timings_get(disp_timing, screen->native_mode);
+#endif
    rk_fb_video_mode_from_timing(dt, screen);

    return 0;
@@ -792,6 +897,7 @@ u64 rk_fb_get_prmry_screen_framedone_t(void)
 int rk_fb_set_prmry_screen_status(int status)
 {
    struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
+
    struct rk_screen *screen;

    if (unlikely(!dev_drv))
@@ -1657,8 +1763,14 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                    reg_win_data->reg_area_data[i].ion_handle;
                win->area[i].smem_start =
                    reg_win_data->reg_area_data[i].smem_start;
+#ifndef CONFIG_SMART_DUAL_LCD
+               if (inf->disp_mode == DUAL ||
+                   inf->disp_mode == NO_DUAL) {
+#else
                if (inf->disp_mode == DUAL ||
+                   inf->disp_mode == DUAL_LCD ||
                    inf->disp_mode == NO_DUAL) {
+#endif
                    win->area[i].xpos =
                        reg_win_data->reg_area_data[i].xpos;
                    win->area[i].ypos =
@@ -3884,7 +3996,12 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
        win = dev_drv->win[win_id];

    if (!strcmp(fbi->fix.id, "fb0")) {
+#ifndef CONFIG_SMART_DUAL_LCD
        fb_mem_size = get_fb_size(dev_drv->reserved_fb);
+#else
+       fb_mem_size = get_fb_size(dev_drv->reserved_fb, dev_drv->cur_screen);
+#endif
+
 #if defined(CONFIG_ION_ROCKCHIP)
        if (rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0)
            return -ENOMEM;
@@ -3905,8 +4022,11 @@ 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;
-
+#ifndef CONFIG_SMART_DUAL_LCD
            fb_mem_size = get_fb_size(dev_drv->reserved_fb);
+#else
+           fb_mem_size = get_fb_size(dev_drv->reserved_fb, dev_drv->cur_screen);
+#endif
 #if defined(CONFIG_ION_ROCKCHIP)
            dev_drv_prmry = rk_get_prmry_lcdc_drv();
            if (dev_drv_prmry == NULL)
@@ -4071,6 +4191,7 @@ 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);
+#ifndef CONFIG_SMART_DUAL_LCD
    rk_disp_pwr_ctr_parse_dt(dev_drv);
    if (dev_drv->prop == PRMRY) {
        rk_fb_set_prmry_screen(screen);
@@ -4079,6 +4200,11 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
    dev_drv->trsm_ops = rk_fb_trsm_ops_get(screen->type);
    if (dev_drv->prop != PRMRY)
        rk_fb_get_extern_screen(screen);
+#else
+   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);
+#endif
    dev_drv->output_color = screen->color_mode;

    return 0;
@@ -4416,16 +4542,32 @@ 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[dev_drv->fb_index_base];

        extend_fbi->var.pixclock = rk_fb->fb[0]->var.pixclock;
+#ifdef CONFIG_SMART_DUAL_LCD
+       extend_fbi->var.xres_virtual = rk_fb->fb[0]->var.xres_virtual;
+       extend_fbi->var.yres_virtual = rk_fb->fb[0]->var.yres_virtual;
+#endif
        extend_fbi->fbops->fb_open(extend_fbi, 1);
        if (dev_drv->iommu_enabled) {
            if (dev_drv->mmu_dev)
                rockchip_iovmm_set_fault_handler(dev_drv->dev,
                                 rk_fb_sysmmu_fault_handler);
+#ifdef CONFIG_SMART_DUAL_LCD
+           if (dev_drv->ops->mmu_en)
+               dev_drv->ops->mmu_en(dev_drv);
+#endif
        }
+
        rk_fb_alloc_buffer(extend_fbi);
+#ifdef CONFIG_SMART_DUAL_LCD
+       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
    }
 #endif
    return 0;
diff --git a/drivers/video/rockchip/screen/rk_screen.c b/drivers/video/rockchip/screen/rk_screen.c
index 11ff587..23e5fbe 100755
--- a/drivers/video/rockchip/screen/rk_screen.c
+++ b/drivers/video/rockchip/screen/rk_screen.c
@@ -4,14 +4,33 @@
 #include "lcd.h"
 #include "../hdmi/rockchip-hdmi.h"

+#ifndef CONFIG_SMART_DUAL_LCD
 static struct rk_screen *rk_screen;
+#else
+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");
+}
+#endif

 int rk_fb_get_extern_screen(struct rk_screen *screen)
 {
+#ifndef CONFIG_SMART_DUAL_LCD
    if (unlikely(!rk_screen) || unlikely(!screen))
        return -1;
-
    memcpy(screen, rk_screen, sizeof(struct rk_screen));
+#else
+   if (unlikely(!extend_screen) || unlikely(!screen))
+       return -1;
+   memcpy(screen, extend_screen, sizeof(struct rk_screen));
+#endif
+   
    screen->dsp_lut = NULL;
    screen->cabc_lut = NULL;
    screen->type = SCREEN_NULL;
@@ -21,13 +40,21 @@ int rk_fb_get_extern_screen(struct rk_screen *screen)

 int  rk_fb_get_prmry_screen(struct rk_screen *screen)
 {
+#ifndef CONFIG_SMART_DUAL_LCD
    if (unlikely(!rk_screen) || unlikely(!screen))
        return -1;

    memcpy(screen, rk_screen, sizeof(struct rk_screen));
+#else
+   if (unlikely(!prmry_screen) || unlikely(!screen))
+       return -1;
+   memcpy(screen, prmry_screen, sizeof(struct rk_screen));
+
+#endif
    return 0;
 }

+#ifndef CONFIG_SMART_DUAL_LCD
 int rk_fb_set_prmry_screen(struct rk_screen *screen)
 {
    if (unlikely(!rk_screen) || unlikely(!screen))
@@ -43,19 +70,87 @@ int rk_fb_set_prmry_screen(struct rk_screen *screen)
    rk_screen->overscan.bottom = screen->overscan.left;
    return 0;
 }
+#else
+int rk_fb_get_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;
+   }
+
+   memcpy(screen, cur_screen, sizeof(struct rk_screen));
+
+   return 0;
+
+}
+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;
+}
+
+#endif
+
+#ifndef CONFIG_SMART_DUAL_LCD
 size_t get_fb_size(u8 reserved_fb)
+#else
+size_t get_fb_size(u8 reserved_fb, struct rk_screen *screen)
+#endif
 {
    size_t size = 0;
    u32 xres = 0;
    u32 yres = 0;

+#ifndef CONFIG_SMART_DUAL_LCD
    if (unlikely(!rk_screen))
        return 0;
-
    xres = rk_screen->mode.xres;
    yres = rk_screen->mode.yres;
-
+#else
+   if (unlikely(!screen))
+       return 0;
+   xres = screen->mode.xres;
+   yres = screen->mode.yres;
+#endif
    /* align as 64 bytes(16*4) in an odd number of times */
    xres = ALIGN_64BYTE_ODD_TIMES(xres, ALIGN_PIXEL_64BYTE_RGB8888);
    if (reserved_fb == ONE_FB_BUFFER)
@@ -75,12 +170,19 @@ 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;

+#ifndef CONFIG_SMART_DUAL_LCD
+   int ret;
+#else
+   struct device_node *screen_np;
+   struct rk_screen *rk_screen;
+   int ret, screen_prop;
+#endif
    if (!np) {
        dev_err(&pdev->dev, "Missing device tree node.\n");
        return -EINVAL;
    }
+#ifndef CONFIG_SMART_DUAL_LCD
    rk_screen = devm_kzalloc(&pdev->dev,
            sizeof(struct rk_screen), GFP_KERNEL);
    if (!rk_screen) {
@@ -90,7 +192,44 @@ static int rk_screen_probe(struct platform_device *pdev)
    ret = rk_fb_prase_timing_dt(np, rk_screen);
    dev_info(&pdev->dev, "rockchip screen probe %s\n",
                ret ? "failed" : "success");
-   return ret;
+       return ret;
+#else
+   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");
+   }
+   dev_info(&pdev->dev, "rockchip screen probe success\n");
+   return 0;
+#endif
 }

 static const struct of_device_id rk_screen_dt_ids[] = {
diff --git a/drivers/video/rockchip/transmitter/rk32_dp.c b/drivers/video/rockchip/transmitter/rk32_dp.c
index 2b3457c..976dc8a 100755
--- a/drivers/video/rockchip/transmitter/rk32_dp.c
+++ b/drivers/video/rockchip/transmitter/rk32_dp.c
@@ -119,8 +119,11 @@ static int rk32_edp_init_edp(struct rk32_edp *edp)
    struct rk_screen *screen = &edp->screen;
    u32 val = 0;

+#ifndef CONFIG_SMART_DUAL_LCD
    rk_fb_get_prmry_screen(screen);
-
+#else
+   rk_fb_get_screen(screen, edp->prop);
+#endif
    if (cpu_is_rk3288()) {
        if (screen->lcdc_id == 1)  /*select lcdc*/
            val = EDP_SEL_VOP_LIT | (EDP_SEL_VOP_LIT << 16);
@@ -1712,17 +1715,25 @@ static int rk32_edp_probe(struct platform_device *pdev)
    struct resource *res;
    struct device_node *np = pdev->dev.of_node;
    int ret;
-
+#ifdef CONFIG_SMART_DUAL_LCD
+   int prop;
+#endif
    if (!np) {
        dev_err(&pdev->dev, "Missing device tree node.\n");
        return -EINVAL;
    }
-
+#ifdef CONFIG_SMART_DUAL_LCD
+   of_property_read_u32(np, "prop", &prop);
+   pr_info("Use EDP as %s screen\n", (prop == PRMRY) ? "primary" : "extend");
+#endif
    edp = devm_kzalloc(&pdev->dev, sizeof(struct rk32_edp), GFP_KERNEL);
    if (!edp) {
        dev_err(&pdev->dev, "no memory for state\n");
        return -ENOMEM;
    }
+#ifdef CONFIG_SMART_DUAL_LCD
+   edp->prop = prop;
+#endif
    edp->dev = &pdev->dev;
    edp->video_info.h_sync_polarity = 0;
    edp->video_info.v_sync_polarity = 0;
@@ -1734,7 +1745,11 @@ 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;
+#ifndef CONFIG_SMART_DUAL_LCD
    rk_fb_get_prmry_screen(&edp->screen);
+#else
+   rk_fb_get_screen(&edp->screen, prop);
+#endif
    if (edp->screen.type != SCREEN_EDP) {
        dev_err(&pdev->dev, "screen is not edp!\n");
        return -EINVAL;
@@ -1809,7 +1824,11 @@ static int rk32_edp_probe(struct platform_device *pdev)
    if (!support_uboot_display())
        rk32_edp_clk_disable(edp);
    rk32_edp = edp;
+#ifndef CONFIG_SMART_DUAL_LCD
    rk_fb_trsm_ops_register(&trsm_edp_ops, SCREEN_EDP);
+#else
+   rk_fb_trsm_ops_register(&trsm_edp_ops, prop);
+#endif
 #if defined(CONFIG_DEBUG_FS)
    edp->debugfs_dir = debugfs_create_dir("edp", NULL);
    if (IS_ERR(edp->debugfs_dir)) {
diff --git a/drivers/video/rockchip/transmitter/rk32_dp.h b/drivers/video/rockchip/transmitter/rk32_dp.h
index 08347b5..f58d266 100755
--- a/drivers/video/rockchip/transmitter/rk32_dp.h
+++ b/drivers/video/rockchip/transmitter/rk32_dp.h
@@ -566,6 +566,9 @@ struct rk32_edp {
    bool clk_on;
    bool edp_en;
    struct dentry *debugfs_dir;
+#ifdef CONFIG_SMART_DUAL_LCD
+   int prop;
+#endif
 };


diff --git a/drivers/video/rockchip/transmitter/rk32_lvds.c b/drivers/video/rockchip/transmitter/rk32_lvds.c
index 3e8394f..df46f46 100755
--- a/drivers/video/rockchip/transmitter/rk32_lvds.c
+++ b/drivers/video/rockchip/transmitter/rk32_lvds.c
@@ -59,8 +59,11 @@ static int rk32_lvds_en(void)
    u32 h_bp = 0;
    u32 val = 0;

+#ifndef CONFIG_SMART_DUAL_LCD
    rk_fb_get_prmry_screen(screen);
-
+#else
+   rk_fb_get_screen(screen, lvds->prop);
+#endif
    /* enable clk */
    rk32_lvds_clk_enable(lvds);

@@ -141,18 +144,29 @@ static int rk32_lvds_probe(struct platform_device *pdev)
    struct resource *res;
    struct device_node *np = pdev->dev.of_node;

+#ifdef CONFIG_SMART_DUAL_LCD
+   int prop;
+#endif
+
    if (!np) {
        dev_err(&pdev->dev, "Missing device tree node.\n");
        return -EINVAL;
    }
-
+#ifdef CONFIG_SMART_DUAL_LCD
+   of_property_read_u32(np, "prop", &prop);
+   pr_info("Use LVDS as %s screen\n", (prop == PRMRY) ? "prmry":"extend");
+#endif
    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;
+#ifndef CONFIG_SMART_DUAL_LCD
    rk_fb_get_prmry_screen(&lvds->screen);
+#else
+   rk_fb_get_screen(&lvds->screen, prop);
+#endif
    if ((lvds->screen.type != SCREEN_RGB) && 
        (lvds->screen.type != SCREEN_LVDS) &&
        (lvds->screen.type != SCREEN_DUAL_LVDS) &&
@@ -185,7 +199,12 @@ static int rk32_lvds_probe(struct platform_device *pdev)
    }

    rk32_lvds = lvds;
+#ifndef CONFIG_SMART_DUAL_LCD
    rk_fb_trsm_ops_register(&trsm_lvds_ops,SCREEN_LVDS);
+#else
+   lvds->prop = prop;
+   rk_fb_trsm_ops_register(&trsm_lvds_ops, prop);
+#endif
    dev_info(&pdev->dev, "rk32 lvds driver probe success\n");

    return 0;
diff --git a/drivers/video/rockchip/transmitter/rk32_lvds.h b/drivers/video/rockchip/transmitter/rk32_lvds.h
index ca424a7..9a1d1a0 100755
--- a/drivers/video/rockchip/transmitter/rk32_lvds.h
+++ b/drivers/video/rockchip/transmitter/rk32_lvds.h
@@ -34,6 +34,9 @@ struct rk32_lvds {
    struct clk              *pd;
    struct rk_screen    screen;
    bool            clk_on;
+#ifdef CONFIG_SMART_DUAL_LCD
+   int prop;
+#endif
 };

 static int inline lvds_writel(struct rk32_lvds *lvds, u32 offset, u32 val)
diff --git a/include/dt-bindings/rkfb/rk_fb.h b/include/dt-bindings/rkfb/rk_fb.h
index 6d75770..e4e909b 100755
--- a/include/dt-bindings/rkfb/rk_fb.h
+++ b/include/dt-bindings/rkfb/rk_fb.h
@@ -12,6 +12,10 @@
 #define NO_DUAL 0
 #define ONE_DUAL 1
 #define DUAL 2
+
+#define DUAL_LCD 3
+#define DEFAULT_MODE 0
+
 /******************************************************************** ** display output interface supported by rockchip ** ********************************************************************/
diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h
index 62647a9..b8eb90f 100755
--- a/include/linux/rk_fb.h
+++ b/include/linux/rk_fb.h
@@ -808,11 +808,25 @@ 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);
+#ifndef CONFIG_SMART_DUAL_LCD
 extern int rk_fb_get_extern_screen(struct rk_screen *screen);
+#endif
 extern int rk_fb_get_prmry_screen( struct rk_screen *screen);
+#ifndef CONFIG_SMART_DUAL_LCD
 extern int rk_fb_set_prmry_screen(struct rk_screen *screen);
+#endif
+
+#ifdef CONFIG_SMART_DUAL_LCD
+extern int rk_fb_get_screen(struct rk_screen *screen, int prop);
+extern int rk_fb_set_screen(struct rk_screen *screen, int prop);
+#endif
+
 extern u32 rk_fb_get_prmry_screen_pixclock(void);
+#ifndef CONFIG_SMART_DUAL_LCD
 extern int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv);
+#else
+extern int rk_disp_pwr_ctr_parse_dt(struct device_node *np, struct rk_screen *rk_screen);
+#endif
 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);
@@ -839,4 +853,5 @@ int rk_fb_pixel_width(int data_format);
 void trace_buffer_dump(struct device *dev,
                  struct rk_lcdc_driver *dev_drv);
 extern int rockchip_get_screen_type(void);
+
 #endif
diff --git a/include/linux/rk_screen.h b/include/linux/rk_screen.h
index af0ffe7..5419623 100644
--- a/include/linux/rk_screen.h
+++ b/include/linux/rk_screen.h
@@ -61,6 +61,13 @@ struct overscan {
 *ft: the time need to display one frame time
 */
 struct rk_screen {
+#ifdef CONFIG_SMART_DUAL_LCD
+   struct device   *dev;
+   int prop;
+   struct list_head *pwrlist_head;
+   int native_mode;
+#endif
+
    u16 type;
    u16 lvds_format; 
    u16 face;
@@ -144,8 +151,12 @@ struct rk29fb_info {
 };

 extern void set_lcd_info(struct rk_screen *screen, struct rk29lcd_info *lcd_info);
+#ifndef CONFIG_SMART_DUAL_LCD
 extern size_t get_fb_size(u8 reserved_fb);
-
+#else
+extern size_t get_fb_size(u8 reserved_fb, struct rk_screen *screen);
+extern size_t get_rotate_fb_size(struct rk_screen *screen);
+#endif
 extern void set_tv_info(struct rk_screen *screen);
 extern void set_hdmi_info(struct rk_screen *screen);