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
--- a/kernel/arch/arm/boot/dts/lcd-NV116FH1.dtsi
+++ b/kernel/arch/arm/boot/dts/lcd-NV116FH1.dtsi
@@ -, +, @@
*
*/ -/ {
-
- 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 = <>;
@@ -, +, @@
swap-gb = <>;
};
};
-};

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
new mode
index fc6385c..58f999be
--- a/kernel/arch/arm/boot/dts/lcd-ZJ080NA-08A.dtsi
+++ b/kernel/arch/arm/boot/dts/lcd-ZJ080NA-08A.dtsi
@@ -, +, @@
*
*/ -/ { - 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>;
@@ -, +, @@
swap-gb = <>;
};
};
-};

(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
--- a/kernel/arch/arm/boot/dts/rk3288-tb_8846.dts
+++ b/kernel/arch/arm/boot/dts/rk3288-tb_8846.dts
@@ -, +, @@ clock-frequency = <>;
}; &fb {
- rockchip,disp-mode = <DUAL>;
- rockchip,uboot-logo-on = <>;
+ rockchip,disp-mode = <DUAL_LCD>;
+ rockchip,uboot-logo-on = <>;
}; &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 = <>;
+ };
+ /*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 = <>;
+ };
+ /*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)*/
@@ -, +, @@ clock-frequency = <>;
rockchip,delay = <>;
};*/ - 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!\n",
- __func__, type);
- break;
- }
+ if (type == PRMRY)
+ trsm_prmry_ops = ops;
+ else if (type == EXTEND)
+ trsm_extend_ops = ops;
+ else
+ pr_err("%s, type:%d\n", __func__, type);
return 0;
} struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type)
{
struct rk_fb_trsm_ops *ops;
- switch (type) {
- case SCREEN_RGB:
- case SCREEN_LVDS:
- case SCREEN_DUAL_LVDS:
- case SCREEN_LVDS_10BIT:
- case SCREEN_DUAL_LVDS_10BIT:
- ops = trsm_lvds_ops;
- break;
- case SCREEN_EDP:
- ops = trsm_edp_ops;
- break;
- case SCREEN_MIPI:
- case SCREEN_DUAL_MIPI:
- ops = trsm_mipi_ops;
- break;
- default:
- ops = NULL;
- printk(KERN_WARNING "%s:un supported transmitter:%d!\n",
- __func__, type);
- break;
- }
+ if (type == PRMRY)
+ ops = trsm_prmry_ops;
+ else if (type == EXTEND)
+ ops = trsm_extend_ops;
+ else
+ pr_err("%s, type:%d\n", __func__, type);
return ops;
} @@ -318,10 +288,10 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
/*
* rk display power control parse from dts
*/
-int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
+int rk_disp_pwr_ctr_parse_dt(struct device_node *np,
+ struct rk_screen *rk_screen)
{
- struct device_node *root = of_get_child_by_name(dev_drv->dev->of_node,
- "power_ctr");
+ struct device_node *root = of_get_child_by_name(np, "power_ctr");
struct device_node *child;
struct rk_disp_pwr_ctr_list *pwr_ctr;
struct list_head *pos;
@@ -, +, @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
u32 debug = ;
int ret; - INIT_LIST_HEAD(&dev_drv->pwrlist_head);
+ INIT_LIST_HEAD(rk_screen->pwrlist_head);
if (!root) {
- dev_err(dev_drv->dev, "can't find power_ctr node for lcdc%d\n",
- dev_drv->id);
+ dev_err(rk_screen->dev, "can't find power_ctr node for lcdc%d\n",
+ rk_screen->lcdc_id);
return -ENODEV;
} @@ -, +, @@ 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, , &flags);
if (!gpio_is_valid(pwr_ctr->pwr_ctr.gpio)) {
- dev_err(dev_drv->dev, "%s ivalid gpio\n",
+ dev_err(rk_screen->dev, "%s ivalid gpio\n",
child->name);
return -EINVAL;
}
@@ -, +, @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
ret = gpio_request(pwr_ctr->pwr_ctr.gpio,
child->name);
if (ret) {
- dev_err(dev_drv->dev,
+ dev_err(rk_screen->dev,
"request %s gpio fail:%d\n",
child->name, ret);
}
@@ -, +, @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
ret = of_property_read_string(child, "rockchip,regulator_name",
&(pwr_ctr->pwr_ctr.rgl_name));
if (ret || IS_ERR_OR_NULL(pwr_ctr->pwr_ctr.rgl_name))
- dev_err(dev_drv->dev, "get regulator name failed!\n");
+ dev_err(rk_screen->dev, "get regulator name failed!\n");
if (!of_property_read_u32(child, "rockchip,regulator_voltage", &val))
pwr_ctr->pwr_ctr.volt = val;
else
@@ -, +, @@ 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 = ;
- list_add_tail(&pwr_ctr->list, &dev_drv->pwrlist_head);
+ list_add_tail(&pwr_ctr->list, rk_screen->pwrlist_head);
} of_property_read_u32(root, "rockchip,debug", &debug); if (debug) {
- list_for_each(pos, &dev_drv->pwrlist_head) {
+ list_for_each(pos, rk_screen->pwrlist_head) {
pwr_ctr = list_entry(pos, struct rk_disp_pwr_ctr_list,
list);
printk(KERN_INFO "pwr_ctr_name:%s\n"
@@ -, +, @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv)
struct regulator *regulator_lcd = NULL;
int count = ; - if (list_empty(&dev_drv->pwrlist_head))
+ if (!dev_drv->cur_screen->pwrlist_head) {
+ pr_info("error: %s, lcdc%d screen pwrlist null\n",
+ __func__, dev_drv->id);
+ return ;
+ }
+ if (list_empty(dev_drv->cur_screen->pwrlist_head))
return ;
- 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;
@@ -, +, @@ int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv)
struct regulator *regulator_lcd = NULL;
int count = ; - if (list_empty(&dev_drv->pwrlist_head))
+ if (!dev_drv->cur_screen->pwrlist_head) {
+ pr_info("error: %s, lcdc%d screen pwrlist null\n",
+ __func__, dev_drv->id);
return ;
- list_for_each(pos, &dev_drv->pwrlist_head) {
+ }
+ if (list_empty(dev_drv->cur_screen->pwrlist_head))
+ return ;
+ 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;
@@ -, +, @@ int rk_fb_prase_timing_dt(struct device_node *np, struct rk_screen *screen)
pr_err("parse display timing err\n");
return -EINVAL;
}
- dt = display_timings_get(disp_timing, disp_timing->native_mode);
+ dt = display_timings_get(disp_timing, screen->native_mode);
rk_fb_video_mode_from_timing(dt, screen);
return ; @@ -, +, @@ 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;
@@ -, +, @@ 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) < )
return -ENOMEM;
@@ -, +, @@ 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)
@@ -, +, @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
dev_drv->area_support[i] = ;
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 ;
@@ -, +, @@ 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 >> ];
- extend_fbi->var.pixclock = rk_fb->fb[]->var.pixclock;
+ struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> ];
+ extend_fbi->var.pixclock = rk_fb->fb[]->var.pixclock;
+ extend_fbi->var.xres_virtual = rk_fb->fb[]->var.xres_virtual;
+ extend_fbi->var.yres_virtual = rk_fb->fb[]->var.yres_virtual;
extend_fbi->fbops->fb_open(extend_fbi, );
-#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 ;
diff --git a/kernel/drivers/video/rockchip/screen/rk_screen.c b/kernel/drivers/video/rockchip/screen/rk_screen.c
index d5e3b15..87a82d9
--- a/kernel/drivers/video/rockchip/screen/rk_screen.c
+++ b/kernel/drivers/video/rockchip/screen/rk_screen.c
@@ -, +, @@
#include "lcd.h"
#include "../hdmi/rockchip-hdmi.h" -static struct rk_screen *rk_screen;
+static struct rk_screen *prmry_screen;
+static struct rk_screen *extend_screen;
+
+static void rk_screen_info_error(struct rk_screen *screen, int prop)
+{
+ pr_err(">>>>>>>>>>>>>>>>>>>>error<<<<<<<<<<<<<<<<<<<<\n");
+ pr_err(">>please init %s screen info in dtsi file<<\n",
+ (prop == PRMRY) ? "prmry" : "extend");
+ pr_err(">>>>>>>>>>>>>>>>>>>>error<<<<<<<<<<<<<<<<<<<<\n");
+} int rk_fb_get_extern_screen(struct rk_screen *screen)
{
- if (unlikely(!rk_screen) || unlikely(!screen))
+ if (unlikely(!extend_screen) || unlikely(!screen))
return -; - 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;
@@ -, +, @@ int rk_fb_get_extern_screen(struct rk_screen *screen)
return ;
} -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 -; - memcpy(screen, rk_screen, sizeof(struct rk_screen));
+ memcpy(screen, prmry_screen, sizeof(struct rk_screen));
return ;
} -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 -; - 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 -;
+ }
+ cur_screen = prmry_screen;
+ } else {
+ if (unlikely(!extend_screen)) {
+ rk_screen_info_error(screen, prop);
+ return -;
+ }
+ cur_screen = extend_screen;
+ }
+
+ memcpy(screen, cur_screen, sizeof(struct rk_screen));
+
return ;
} -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 -;
+ if (prop == PRMRY) {
+ if (unlikely(!prmry_screen)) {
+ rk_screen_info_error(screen, prop);
+ return -;
+ }
+ cur_screen = prmry_screen;
+ } else {
+ if (unlikely(!extend_screen)) {
+ rk_screen_info_error(screen, prop);
+ return -;
+ }
+ 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 ;
+}
+
+size_t get_fb_size(u8 reserved_fb, struct rk_screen *screen)
{
size_t size = ;
u32 xres = ;
u32 yres = ; - if (unlikely(!rk_screen))
+ if (unlikely(!screen))
return ; - 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);
@@ -, +, @@ size_t get_fb_size(u8 reserved_fb)
static int rk_screen_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- int ret;
+ struct device_node *screen_np;
+ struct rk_screen *rk_screen;
+ int ret, screen_prop; if (!np) {
dev_err(&pdev->dev, "Missing device tree node.\n");
return -EINVAL;
}
- rk_screen = devm_kzalloc(&pdev->dev,
- sizeof(struct rk_screen), GFP_KERNEL);
- if (!rk_screen) {
- dev_err(&pdev->dev, "kmalloc for rk screen fail!");
- return -ENOMEM;
+
+ for_each_child_of_node(np, screen_np) {
+ rk_screen = devm_kzalloc(&pdev->dev,
+ sizeof(struct rk_screen), GFP_KERNEL);
+ if (!rk_screen) {
+ dev_err(&pdev->dev, "kmalloc for rk screen fail!");
+ return -ENOMEM;
+ }
+ rk_screen->pwrlist_head = devm_kzalloc(&pdev->dev,
+ sizeof(struct list_head), GFP_KERNEL);
+ if (!rk_screen->pwrlist_head) {
+ dev_err(&pdev->dev, "kmalloc for rk_screen pwrlist_head fail!");
+ return -ENOMEM;
+ }
+ of_property_read_u32(screen_np, "screen_prop", &screen_prop);
+ if (screen_prop == PRMRY)
+ prmry_screen = rk_screen;
+ else if (screen_prop == EXTEND)
+ extend_screen = rk_screen;
+ else
+ dev_err(&pdev->dev, "unknow screen prop: %d\n",
+ screen_prop);
+ rk_screen->prop = screen_prop;
+ of_property_read_u32(screen_np, "native-mode", &rk_screen->native_mode);
+ rk_screen->dev = &pdev->dev;
+ ret = rk_fb_prase_timing_dt(screen_np, rk_screen);
+ pr_info("%s screen timing parse %s\n",
+ (screen_prop == PRMRY) ? "prmry" : "extend",
+ ret ? "failed" : "success");
+ ret = rk_disp_pwr_ctr_parse_dt(screen_np, rk_screen);
+ pr_info("%s screen power ctrl parse %s\n",
+ (screen_prop == PRMRY) ? "prmry" : "extend",
+ ret ? "failed" : "success");
}
- ret = rk_fb_prase_timing_dt(np, rk_screen);
- dev_info(&pdev->dev, "rockchip screen probe %s\n",
- ret ? "failed" : "success");
- return ret;
+
+ dev_info(&pdev->dev, "rockchip screen probe success\n");
+ return ;
} 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
--- a/kernel/drivers/video/rockchip/transmitter/rk32_dp.c
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_dp.c
@@ -, +, @@ static int rk32_edp_init_edp(struct rk32_edp *edp)
struct rk_screen *screen = &edp->screen;
u32 val = ; - rk_fb_get_prmry_screen(screen);
+ rk_fb_get_screen(screen, edp->prop); if (cpu_is_rk3288()) {
if (screen->lcdc_id == ) /*select lcdc*/
@@ -, +, @@ static int rk32_edp_probe(struct platform_device *pdev)
struct resource *res;
struct device_node *np = pdev->dev.of_node;
int ret;
+ int prop; if (!np) {
dev_err(&pdev->dev, "Missing device tree node.\n");
return -EINVAL;
}
+ of_property_read_u32(np, "prop", &prop);
+ pr_info("Use EDP as %s screen\n", (prop == PRMRY) ? "prmry" : "extend"); edp = devm_kzalloc(&pdev->dev, sizeof(struct rk32_edp), GFP_KERNEL);
if (!edp) {
dev_err(&pdev->dev, "no memory for state\n");
return -ENOMEM;
}
+ edp->prop = prop;
edp->dev = &pdev->dev;
edp->video_info.h_sync_polarity = ;
edp->video_info.v_sync_polarity = ;
@@ -, +, @@ static int rk32_edp_probe(struct platform_device *pdev) edp->video_info.link_rate = LINK_RATE_1_62GBPS;
edp->video_info.lane_count = LANE_CNT4;
- rk_fb_get_prmry_screen(&edp->screen);
+ rk_fb_get_screen(&edp->screen, prop);
if (edp->screen.type != SCREEN_EDP) {
dev_err(&pdev->dev, "screen is not edp!\n");
return -EINVAL;
@@ -, +, @@ 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
--- a/kernel/drivers/video/rockchip/transmitter/rk32_dp.h
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_dp.h
@@ -, +, @@ 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..
--- a/kernel/drivers/video/rockchip/transmitter/rk32_lvds.c
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_lvds.c
@@ -, +, @@ static int rk32_lvds_en(void)
u32 val = ;
u32 delay_times = ; - rk_fb_get_prmry_screen(screen);
+ rk_fb_get_screen(screen, lvds->prop); /* enable clk */
rk32_lvds_clk_enable(lvds);
@@ -, +, @@ static int rk32_lvds_probe(struct platform_device *pdev)
struct rk32_lvds *lvds;
struct resource *res;
struct device_node *np = pdev->dev.of_node;
+ int prop; if (!np) {
dev_err(&pdev->dev, "Missing device tree node.\n");
return -EINVAL;
} + of_property_read_u32(np, "prop", &prop);
+ pr_info("Use LVDS as %s screen\n", (prop == PRMRY) ? "prmry":"extend");
lvds = devm_kzalloc(&pdev->dev, sizeof(struct rk32_lvds), GFP_KERNEL);
if (!lvds) {
dev_err(&pdev->dev, "no memory for state\n");
return -ENOMEM;
}
lvds->dev = &pdev->dev;
- rk_fb_get_prmry_screen(&lvds->screen);
+ rk_fb_get_screen(&lvds->screen, prop);
if ((lvds->screen.type != SCREEN_RGB) &&
(lvds->screen.type != SCREEN_LVDS) &&
(lvds->screen.type != SCREEN_DUAL_LVDS) &&
@@ -, +, @@ static int rk32_lvds_probe(struct platform_device *pdev)
} rk32_lvds = lvds;
- rk_fb_trsm_ops_register(&trsm_lvds_ops,SCREEN_LVDS);
+ lvds->prop = prop;
+ rk_fb_trsm_ops_register(&trsm_lvds_ops, prop);
dev_info(&pdev->dev, "rk32 lvds driver probe success\n"); return ;
diff --git a/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h b/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h
index 198311a..0a8dd45
--- a/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h
+++ b/kernel/drivers/video/rockchip/transmitter/rk32_lvds.h
@@ -, +, @@ 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
--- a/kernel/include/dt-bindings/rkfb/rk_fb.h
+++ b/kernel/include/dt-bindings/rkfb/rk_fb.h
@@ -, +, @@
#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
@@ -, +, @@
#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;
@@ -, +, @@ 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
--- a/hardware/rockchip/hwcomposer/rk_hwcomposer.cpp
+++ b/hardware/rockchip/hwcomposer/rk_hwcomposer.cpp
@@ -, +, @@ 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);
@@ -, +, @@ int hotplug_get_config(int flag){
int outX = ;
int outY = ;
hotplug_parse_mode(&outX, &outY);
+ if (hwc_get_int_property("ro.htg.force", ""))
+ hwc_parse_screen_info(&outX, &outY);
+ else
+ hotplug_parse_mode(&outX, &outY);
info.xres = outX;
info.yres = outY;
info.yres_virtual = info.yres * ;
@@ -, +, @@ OnError: } +int hwc_parse_screen_info(int *outX, int *outY)
+{
+ char buf[];
+ int width = ;
+ int height = ;
+ int fdExternal = -;
+ fdExternal = open("/sys/class/graphics/fb4/screen_info", O_RDONLY);
+ if(fdExternal < ){
+ ALOGE("hotplug_get_config:open fb screen_info error,cvbsfd=%d",fdExternal);
+ return -errno;
+ }
+ if(read(fdExternal,buf,sizeof(buf)) < ){
+ ALOGE("error reading fb screen_info: %s", strerror(errno));
+ return -;
+ }
+ 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 ;
+}
+
int hotplug_parse_mode(int *outX, int *outY)
{
int fd = open("/sys/class/display/HDMI/mode", O_RDONLY);
@@ -, +, @@ void *hotplug_try_register(void *arg)
if(getHdmiMode() == ){
handle_hotplug_event(, );
ALOGI("hotplug_try_register at line = %d",__LINE__);
- }else{
+ } else if (hwc_get_int_property("ro.htg.force", "")) {
+ hotplug_free_dimbuffer();
+ hotplug_get_config();
+ handle_hotplug_event(, );
+ ALOGI("hotplug_try_register at line = %d",__LINE__);
+ } else {
#if (defined(RK3368_BOX) || defined(RK3288_BOX))
#if RK3288_BOX
if(context->mLcdcNum == ){

hardware 补丁

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

diff --git a/frameworks/base/api/current.txt b/frameworks/base/api/current.txt
index c537823..c1cc9a6
--- a/frameworks/base/api/current.txt
+++ b/frameworks/base/api/current.txt
@@ -, +, @@ 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);
@@ -, +, @@ 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 = ; // 0x1
@@ -, +, @@ 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[]);
@@ -, +, @@ 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[]);
@@ -, +, @@ 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[]);
@@ -, +, @@ 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();
@@ -, +, @@ 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
--- a/frameworks/base/api/system-current.txt
+++ b/frameworks/base/api/system-current.txt
@@ -, +, @@ 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);
@@ -, +, @@ 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 = ; // 0x1
@@ -, +, @@ 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[]);
@@ -, +, @@ 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[]);
@@ -, +, @@ 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[]);
@@ -, +, @@ 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);
@@ -, +, @@ 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..
--- a/frameworks/base/core/java/android/app/Activity.java
+++ b/frameworks/base/core/java/android/app/Activity.java
@@ -, +, @@ 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
--- a/frameworks/base/core/java/android/app/ContextImpl.java
+++ b/frameworks/base/core/java/android/app/ContextImpl.java
@@ -, +, @@ 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;
@@ -, +, @@ class ContextImpl extends Context {
return mDisplayAdjustments;
} + @Override
+ public void setDualScreen(boolean enable) {
+
+ int value = ;
+ if (enable) {
+ value = ;
+ } else {
+ Settings.System.putInt(getContentResolver(), Settings.System.DUAL_SCREEN_ICON_USED, );
+ }
+ 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
--- a/frameworks/base/core/java/android/content/Context.java
+++ b/frameworks/base/core/java/android/content/Context.java
@@ -, +, @@ 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
--- a/frameworks/base/core/java/android/content/ContextWrapper.java
+++ b/frameworks/base/core/java/android/content/ContextWrapper.java
@@ -, +, @@ 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..
--- a/frameworks/base/core/java/android/view/IWindowSession.aidl
+++ b/frameworks/base/core/java/android/view/IWindowSession.aidl
@@ -, +, @@ 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
--- a/frameworks/base/core/java/android/view/Window.java
+++ b/frameworks/base/core/java/android/view/Window.java
@@ -, +, @@ 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
--- a/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -, +, @@ 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(),-);
+ } 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
--- a/frameworks/base/services/core/java/com/android/server/wm/Session.java
+++ b/frameworks/base/services/core/java/com/android/server/wm/Session.java
@@ -, +, @@ 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
--- a/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -, +, @@ public class WindowManagerService extends IWindowManager.Stub
public static final int SET_MULTIWINDOW_MODE_ACTION = ;
public static final int DO_TASK_DISPLAY_CHANGED = ;
public static final int MULTIWINDOW_MOVE_BACK_ACTION = ;
+ public static final int MOVE_APP_TO_DISPLAY = ;
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -, +, @@ 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");
@@ -, +, @@ 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() <= ){
+ return;
+ }
+ final int displayCount = mDisplayContents.size();
+ DisplayContent defaultContent = getDefaultDisplayContentLocked();
+ int displayId = ;
+ boolean hasTargetDisplay = false;
+ for(int i = ; 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, );
+ 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 = -;
+ synchronized(mWindowMap){
+ if(mDisplayContents == null || mDisplayContents.size() <= ) {
+ return;
+ }
+ DisplayContent defaultContent = getDefaultDisplayContentLocked();
+ int defaultDisplayId = defaultContent.getDisplayId();
+ final int displayCount = mDisplayContents.size();
+ int displayId = ;
+ DisplayContent currentContent = null;
+ DisplayContent targetContent = null;
+ for(int i = ; 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 = ;
+ int countOfTwoScreen = ;
+ WindowList defaultWindows = defaultContent.getWindowList();
+ HashMap<Integer,AppWindowToken> visibleAppsOfTwoScreen = new HashMap<Integer,AppWindowToken>();
+ ArrayList<AppWindowToken> pendingRemoveOfTwoScreen = new ArrayList<AppWindowToken>();
+ for(int j = ; 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() > ){
+ for(int k =;k < pendingRemoveOfTwoScreen.size(); k++){
+ int removeTaskId = pendingRemoveOfTwoScreen.get(k).groupId;
+ for(int m = ; 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 = ;
+ final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+ final int numTasks = tasks.size();
+ for (int taskNdx = ; 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()-; i >= ; 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 = ;
+ final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+
+ final int numTasks = tasks.size();
+ for (int taskNdx = ; taskNdx < numTasks; ++taskNdx) {
+ if (tasks.get(taskNdx).taskId != win.taskId) continue;
+ final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+ for (int n = ; 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(, win);
+ }
+ }
+ targetDisplayWindows.addAll(targetDisplayAddList);
+ } else {
+ // external screen -> external screen
+ }
+
+ for (int i = ; 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 = -;
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 ..cd24654
--- a/frameworks/base/test-runner/src/android/test/mock/MockContext.java
+++ b/frameworks/base/test-runner/src/android/test/mock/MockContext.java
@@ -, +, @@ 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:: 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.
error
make: *** [out/target/common/obj/APPS/CtsViewTestCases_intermediates/classes-full-debug.jar] Error
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 (: (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
--- a/cts/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/cts/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -, +, @@ 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
--- a/device/rockchip/rk3288/system.prop
+++ b/device/rockchip/rk3288/system.prop
@@ -, +, @@ rild.libpath=/system/lib/libril-rk29-dataonly.so
rild.libargs=-d /dev/ttyACM0
persist.tegra.nvmmlite =
ro.audio.monitorOrientation=true
+ro.htg.force= #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 = <>;
hactive = <>;
vactive = <>;

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

 lcd_en {
rockchip,power_type = <GPIO>;
gpios = <&gpio7 GPIO_A5 GPIO_ACTIVE_HIGH>;
- rockchip,delay = <>;
+ rockchip,delay = <>;
};
05-08 14:51