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