From a6eedb670d56fe0d8784f2f5737077d79d96a4e5 Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Mon, 10 Jun 2019 14:47:49 +0300 Subject: [PATCH 01/17] video: fsl_dcu_fb: refactor init functions Move dcu-related code to fsl_dcu_probe_common, keep in video_hw_init() only legacy video stack (filling GraphicPanel struct etc.). Add wrappers for all init functions, that will let to provide struct fb_info as an additional param (needed for further moving it from the global scope to driver private data struct in DM converted driver). Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- board/freescale/ls1021aiot/dcu.c | 9 +-- board/freescale/ls1021aqds/dcu.c | 6 +- board/freescale/ls1021atwr/dcu.c | 5 +- board/toradex/colibri_vf/dcu.c | 6 +- drivers/video/fsl_dcu_fb.c | 107 +++++++++++++++++-------------- include/fsl_dcu_fb.h | 12 +++- 6 files changed, 85 insertions(+), 60 deletions(-) diff --git a/board/freescale/ls1021aiot/dcu.c b/board/freescale/ls1021aiot/dcu.c index 9aeee0eac9a..77732a6ab15 100644 --- a/board/freescale/ls1021aiot/dcu.c +++ b/board/freescale/ls1021aiot/dcu.c @@ -23,9 +23,10 @@ unsigned int dcu_set_pixel_clock(unsigned int pixclock) return div; } -int platform_dcu_init(unsigned int xres, unsigned int yres, - const char *port, - struct fb_videomode *dcu_fb_videomode) +int platform_dcu_init(struct fb_info *fbinfo, + unsigned int xres, unsigned int yres, + const char *port, + struct fb_videomode *dcu_fb_videomode) { const char *name; unsigned int pixel_format; @@ -40,7 +41,7 @@ int platform_dcu_init(unsigned int xres, unsigned int yres, printf("DCU: Switching to %s monitor @ %ux%u\n", name, xres, yres); pixel_format = 32; - fsl_dcu_init(xres, yres, pixel_format); + fsl_dcu_init(fbinfo, xres, yres, pixel_format); return 0; } diff --git a/board/freescale/ls1021aqds/dcu.c b/board/freescale/ls1021aqds/dcu.c index 14855ea1d90..c4eac5e3025 100644 --- a/board/freescale/ls1021aqds/dcu.c +++ b/board/freescale/ls1021aqds/dcu.c @@ -39,7 +39,9 @@ unsigned int dcu_set_pixel_clock(unsigned int pixclock) return div; } -int platform_dcu_init(unsigned int xres, unsigned int yres, +int platform_dcu_init(struct fb_info *fbinfo, + unsigned int xres, + unsigned int yres, const char *port, struct fb_videomode *dcu_fb_videomode) { @@ -85,7 +87,7 @@ int platform_dcu_init(unsigned int xres, unsigned int yres, printf("DCU: Switching to %s monitor @ %ux%u\n", name, xres, yres); pixel_format = 32; - fsl_dcu_init(xres, yres, pixel_format); + fsl_dcu_init(fbinfo, xres, yres, pixel_format); return 0; } diff --git a/board/freescale/ls1021atwr/dcu.c b/board/freescale/ls1021atwr/dcu.c index e1191f134cb..bdf7f7645c2 100644 --- a/board/freescale/ls1021atwr/dcu.c +++ b/board/freescale/ls1021atwr/dcu.c @@ -23,7 +23,8 @@ unsigned int dcu_set_pixel_clock(unsigned int pixclock) return div; } -int platform_dcu_init(unsigned int xres, unsigned int yres, +int platform_dcu_init(struct fb_info *fbinfo, + unsigned int xres, unsigned int yres, const char *port, struct fb_videomode *dcu_fb_videomode) { @@ -40,7 +41,7 @@ int platform_dcu_init(unsigned int xres, unsigned int yres, printf("DCU: Switching to %s monitor @ %ux%u\n", name, xres, yres); pixel_format = 32; - fsl_dcu_init(xres, yres, pixel_format); + fsl_dcu_init(fbinfo, xres, yres, pixel_format); return 0; } diff --git a/board/toradex/colibri_vf/dcu.c b/board/toradex/colibri_vf/dcu.c index c36e90cd22e..c688ed79ffd 100644 --- a/board/toradex/colibri_vf/dcu.c +++ b/board/toradex/colibri_vf/dcu.c @@ -26,11 +26,13 @@ unsigned int dcu_set_pixel_clock(unsigned int pixclock) return div; } -int platform_dcu_init(unsigned int xres, unsigned int yres, +int platform_dcu_init(struct fb_info *fbinfo, + unsigned int xres, + unsigned int yres, const char *port, struct fb_videomode *dcu_fb_videomode) { - fsl_dcu_init(xres, yres, 32); + fsl_dcu_init(fbinfo, xres, yres, 32); return 0; } diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c index 9f6e7f83b0f..f789ec597d3 100644 --- a/drivers/video/fsl_dcu_fb.c +++ b/drivers/video/fsl_dcu_fb.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2014 Freescale Semiconductor, Inc. + * Copyright 2019 Toradex AG * * FSL DCU Framebuffer driver */ @@ -240,20 +241,22 @@ static void reset_total_layers(void) } } -static int layer_ctrldesc_init(int index, u32 pixel_format) +static int layer_ctrldesc_init(struct fb_info fbinfo, + int index, u32 pixel_format) { struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; unsigned int bpp = BPP_24_RGB888; dcu_write32(®s->ctrldescl[index][0], - DCU_CTRLDESCLN_1_HEIGHT(info.var.yres) | - DCU_CTRLDESCLN_1_WIDTH(info.var.xres)); + DCU_CTRLDESCLN_1_HEIGHT(fbinfo.var.yres) | + DCU_CTRLDESCLN_1_WIDTH(fbinfo.var.xres)); dcu_write32(®s->ctrldescl[index][1], DCU_CTRLDESCLN_2_POSY(0) | DCU_CTRLDESCLN_2_POSX(0)); - dcu_write32(®s->ctrldescl[index][2], (unsigned int)info.screen_base); + dcu_write32(®s->ctrldescl[index][2], + (unsigned int)fbinfo.screen_base); switch (pixel_format) { case 16: @@ -294,42 +297,42 @@ static int layer_ctrldesc_init(int index, u32 pixel_format) return 0; } -int fsl_dcu_init(unsigned int xres, unsigned int yres, - unsigned int pixel_format) +int fsl_dcu_init(struct fb_info *fbinfo, unsigned int xres, + unsigned int yres, unsigned int pixel_format) { struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; unsigned int div, mode; - info.screen_size = - info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8); + fbinfo->screen_size = fbinfo->var.xres * fbinfo->var.yres * + (fbinfo->var.bits_per_pixel / 8); - if (info.screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) { - info.screen_size = 0; + if (fbinfo->screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) { + fbinfo->screen_size = 0; return -ENOMEM; } /* Reserve framebuffer at the end of memory */ gd->fb_base = gd->bd->bi_dram[0].start + - gd->bd->bi_dram[0].size - info.screen_size; - info.screen_base = (char *)gd->fb_base; + gd->bd->bi_dram[0].size - fbinfo->screen_size; + fbinfo->screen_base = (char *)gd->fb_base; - memset(info.screen_base, 0, info.screen_size); + memset(fbinfo->screen_base, 0, fbinfo->screen_size); reset_total_layers(); dcu_write32(®s->disp_size, - DCU_DISP_SIZE_DELTA_Y(info.var.yres) | - DCU_DISP_SIZE_DELTA_X(info.var.xres / 16)); + DCU_DISP_SIZE_DELTA_Y(fbinfo->var.yres) | + DCU_DISP_SIZE_DELTA_X(fbinfo->var.xres / 16)); dcu_write32(®s->hsyn_para, - DCU_HSYN_PARA_BP(info.var.left_margin) | - DCU_HSYN_PARA_PW(info.var.hsync_len) | - DCU_HSYN_PARA_FP(info.var.right_margin)); + DCU_HSYN_PARA_BP(fbinfo->var.left_margin) | + DCU_HSYN_PARA_PW(fbinfo->var.hsync_len) | + DCU_HSYN_PARA_FP(fbinfo->var.right_margin)); dcu_write32(®s->vsyn_para, - DCU_VSYN_PARA_BP(info.var.upper_margin) | - DCU_VSYN_PARA_PW(info.var.vsync_len) | - DCU_VSYN_PARA_FP(info.var.lower_margin)); + DCU_VSYN_PARA_BP(fbinfo->var.upper_margin) | + DCU_VSYN_PARA_PW(fbinfo->var.vsync_len) | + DCU_VSYN_PARA_FP(fbinfo->var.lower_margin)); dcu_write32(®s->synpol, DCU_SYN_POL_INV_PXCK_FALL | @@ -352,9 +355,9 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres, mode = dcu_read32(®s->mode); dcu_write32(®s->mode, mode | DCU_MODE_NORMAL); - layer_ctrldesc_init(0, pixel_format); + layer_ctrldesc_init(*fbinfo, 0, pixel_format); - div = dcu_set_pixel_clock(info.var.pixclock); + div = dcu_set_pixel_clock(fbinfo->var.pixclock); dcu_write32(®s->div_ratio, (div - 1)); dcu_write32(®s->update_mode, DCU_UPDATE_MODE_READREG); @@ -367,24 +370,26 @@ ulong board_get_usable_ram_top(ulong total_size) return gd->ram_top - CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB; } -void *video_hw_init(void) +int fsl_probe_common(struct fb_info *fbinfo, unsigned int *win_x, + unsigned int *win_y) { - static GraphicDevice ctfb; const char *options; unsigned int depth = 0, freq = 0; + struct fb_videomode *fsl_dcu_mode_db = &fsl_dcu_mode_480_272; - if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq, + if (!video_get_video_mode(win_x, win_y, &depth, &freq, &options)) - return NULL; + return -EINVAL; /* Find the monitor port, which is a required option */ if (!options) - return NULL; - if (strncmp(options, "monitor=", 8) != 0) - return NULL; + return -EINVAL; - switch (RESOLUTION(ctfb.winSizeX, ctfb.winSizeY)) { + if (strncmp(options, "monitor=", 8) != 0) + return -EINVAL; + + switch (RESOLUTION(*win_x, *win_y)) { case RESOLUTION(480, 272): fsl_dcu_mode_db = &fsl_dcu_mode_480_272; break; @@ -402,25 +407,33 @@ void *video_hw_init(void) break; default: printf("unsupported resolution %ux%u\n", - ctfb.winSizeX, ctfb.winSizeY); + *win_x, *win_y); } - info.var.xres = fsl_dcu_mode_db->xres; - info.var.yres = fsl_dcu_mode_db->yres; - info.var.bits_per_pixel = 32; - info.var.pixclock = fsl_dcu_mode_db->pixclock; - info.var.left_margin = fsl_dcu_mode_db->left_margin; - info.var.right_margin = fsl_dcu_mode_db->right_margin; - info.var.upper_margin = fsl_dcu_mode_db->upper_margin; - info.var.lower_margin = fsl_dcu_mode_db->lower_margin; - info.var.hsync_len = fsl_dcu_mode_db->hsync_len; - info.var.vsync_len = fsl_dcu_mode_db->vsync_len; - info.var.sync = fsl_dcu_mode_db->sync; - info.var.vmode = fsl_dcu_mode_db->vmode; - info.fix.line_length = info.var.xres * info.var.bits_per_pixel / 8; + fbinfo->var.xres = fsl_dcu_mode_db->xres; + fbinfo->var.yres = fsl_dcu_mode_db->yres; + fbinfo->var.bits_per_pixel = 32; + fbinfo->var.pixclock = fsl_dcu_mode_db->pixclock; + fbinfo->var.left_margin = fsl_dcu_mode_db->left_margin; + fbinfo->var.right_margin = fsl_dcu_mode_db->right_margin; + fbinfo->var.upper_margin = fsl_dcu_mode_db->upper_margin; + fbinfo->var.lower_margin = fsl_dcu_mode_db->lower_margin; + fbinfo->var.hsync_len = fsl_dcu_mode_db->hsync_len; + fbinfo->var.vsync_len = fsl_dcu_mode_db->vsync_len; + fbinfo->var.sync = fsl_dcu_mode_db->sync; + fbinfo->var.vmode = fsl_dcu_mode_db->vmode; + fbinfo->fix.line_length = fbinfo->var.xres * + fbinfo->var.bits_per_pixel / 8; - if (platform_dcu_init(ctfb.winSizeX, ctfb.winSizeY, - options + 8, fsl_dcu_mode_db) < 0) + return platform_dcu_init(fbinfo, *win_x, *win_y, + options + 8, fsl_dcu_mode_db); +} + +void *video_hw_init(void) +{ + static GraphicDevice ctfb; + + if (fsl_probe_common(&info, &ctfb.winSizeX, &ctfb.winSizeY) < 0) return NULL; ctfb.frameAdrs = (unsigned int)info.screen_base; diff --git a/include/fsl_dcu_fb.h b/include/fsl_dcu_fb.h index 2dd5f54c3e0..7a5347a9247 100644 --- a/include/fsl_dcu_fb.h +++ b/include/fsl_dcu_fb.h @@ -6,11 +6,17 @@ */ #include -int fsl_dcu_init(unsigned int xres, unsigned int yres, +int fsl_dcu_init(struct fb_info *fbinfo, + unsigned int xres, + unsigned int yres, unsigned int pixel_format); + int fsl_dcu_fixedfb_setup(void *blob); /* Prototypes for external board-specific functions */ -int platform_dcu_init(unsigned int xres, unsigned int yres, - const char *port, struct fb_videomode *dcu_fb_videomode); +int platform_dcu_init(struct fb_info *fbinfo, + unsigned int xres, + unsigned int yres, + const char *port, + struct fb_videomode *dcu_fb_videomode); unsigned int dcu_set_pixel_clock(unsigned int pixclock); From be3f1a56bf87bef19ac9e129ab8f20ab960f310e Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Mon, 10 Jun 2019 14:47:50 +0300 Subject: [PATCH 02/17] video: fsl_dcu_fb: add DM_VIDEO support Extend the driver to build with DM_VIDEO enabled. DTS files must additionally include 'u-boot,dm-pre-reloc' property in soc and child nodes to enable driver binding to fsl_dcu_fb device. Currently display timings aren't obtained from DT. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- board/toradex/colibri_vf/colibri_vf.c | 4 +- drivers/video/Kconfig | 2 +- drivers/video/fsl_dcu_fb.c | 118 +++++++++++++++++++++----- 3 files changed, 100 insertions(+), 24 deletions(-) diff --git a/board/toradex/colibri_vf/colibri_vf.c b/board/toradex/colibri_vf/colibri_vf.c index 9d63fbf3bd1..dad754b31fa 100644 --- a/board/toradex/colibri_vf/colibri_vf.c +++ b/board/toradex/colibri_vf/colibri_vf.c @@ -430,7 +430,9 @@ int checkboard(void) #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) int ft_board_setup(void *blob, bd_t *bd) { +#ifndef CONFIG_DM_VIDEO int ret = 0; +#endif #ifdef CONFIG_FDT_FIXUP_PARTITIONS static const struct node_info nodes[] = { { "fsl,vf610-nfc", MTD_DEV_TYPE_NAND, }, /* NAND flash */ @@ -440,7 +442,7 @@ int ft_board_setup(void *blob, bd_t *bd) puts(" Updating MTD partitions...\n"); fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); #endif -#ifdef CONFIG_VIDEO_FSL_DCU_FB +#if defined(CONFIG_VIDEO_FSL_DCU_FB) && !defined(CONFIG_DM_VIDEO) ret = fsl_dcu_fixedfb_setup(blob); if (ret) return ret; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c3781b160d9..261fa985171 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -484,7 +484,7 @@ config VIDEO_IVYBRIDGE_IGD config VIDEO_FSL_DCU_FB bool "Enable Freescale Display Control Unit" - depends on VIDEO + depends on VIDEO || DM_VIDEO help This enables support for Freescale Display Control Unit (DCU4) module found on Freescale Vybrid and QorIQ family of SoCs. diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c index f789ec597d3..add64b85b59 100644 --- a/drivers/video/fsl_dcu_fb.c +++ b/drivers/video/fsl_dcu_fb.c @@ -8,10 +8,12 @@ #include #include +#include #include #include #include #include +#include #include #include "videomodes.h" @@ -219,8 +221,6 @@ struct dcu_reg { u32 ctrldescl[DCU_LAYER_MAX_NUM][16]; }; -static struct fb_info info; - static void reset_total_layers(void) { struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; @@ -302,7 +302,11 @@ int fsl_dcu_init(struct fb_info *fbinfo, unsigned int xres, { struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; unsigned int div, mode; - +/* + * When DM_VIDEO is enabled reservation of framebuffer is done + * in advance during bind() call. + */ +#if !CONFIG_IS_ENABLED(DM_VIDEO) fbinfo->screen_size = fbinfo->var.xres * fbinfo->var.yres * (fbinfo->var.bits_per_pixel / 8); @@ -310,13 +314,13 @@ int fsl_dcu_init(struct fb_info *fbinfo, unsigned int xres, fbinfo->screen_size = 0; return -ENOMEM; } - /* Reserve framebuffer at the end of memory */ gd->fb_base = gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - fbinfo->screen_size; fbinfo->screen_base = (char *)gd->fb_base; memset(fbinfo->screen_base, 0, fbinfo->screen_size); +#endif reset_total_layers(); @@ -429,24 +433,8 @@ int fsl_probe_common(struct fb_info *fbinfo, unsigned int *win_x, options + 8, fsl_dcu_mode_db); } -void *video_hw_init(void) -{ - static GraphicDevice ctfb; - - if (fsl_probe_common(&info, &ctfb.winSizeX, &ctfb.winSizeY) < 0) - return NULL; - - ctfb.frameAdrs = (unsigned int)info.screen_base; - ctfb.plnSizeX = ctfb.winSizeX; - ctfb.plnSizeY = ctfb.winSizeY; - - ctfb.gdfBytesPP = 4; - ctfb.gdfIndex = GDF_32BIT_X888RGB; - - ctfb.memSize = info.screen_size; - - return &ctfb; -} +#ifndef CONFIG_DM_VIDEO +static struct fb_info info; #if defined(CONFIG_OF_BOARD_SETUP) int fsl_dcu_fixedfb_setup(void *blob) @@ -470,3 +458,89 @@ int fsl_dcu_fixedfb_setup(void *blob) return 0; } #endif + +void *video_hw_init(void) +{ + static GraphicDevice ctfb; + + if (fsl_probe_common(&info, &ctfb.winSizeX, &ctfb.winSizeY) < 0) + return NULL; + + ctfb.frameAdrs = (unsigned int)info.screen_base; + ctfb.plnSizeX = ctfb.winSizeX; + ctfb.plnSizeY = ctfb.winSizeY; + + ctfb.gdfBytesPP = 4; + ctfb.gdfIndex = GDF_32BIT_X888RGB; + + ctfb.memSize = info.screen_size; + + return &ctfb; +} + +#else /* ifndef CONFIG_DM_VIDEO */ + +static int fsl_dcu_video_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct fb_info fbinfo = { 0 }; + unsigned int win_x; + unsigned int win_y; + u32 fb_start, fb_end; + int ret = 0; + + fb_start = plat->base & ~(MMU_SECTION_SIZE - 1); + fb_end = plat->base + plat->size; + fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT); + + fbinfo.screen_base = (char *)fb_start; + fbinfo.screen_size = plat->size; + + ret = fsl_probe_common(&fbinfo, &win_x, &win_y); + if (ret < 0) + return ret; + + uc_priv->bpix = VIDEO_BPP32; + uc_priv->xsize = win_x; + uc_priv->ysize = win_y; + + /* Enable dcache for the frame buffer */ + mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start, + DCACHE_WRITEBACK); + video_set_flush_dcache(dev, true); + return ret; +} + +static int fsl_dcu_video_bind(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + unsigned int win_x; + unsigned int win_y; + unsigned int depth = 0, freq = 0; + const char *options; + int ret = 0; + + ret = video_get_video_mode(&win_x, &win_y, &depth, &freq, &options); + if (ret < 0) + return ret; + + plat->size = win_x * win_y * 32; + + return 0; +} + +static const struct udevice_id fsl_dcu_video_ids[] = { + { .compatible = "fsl,vf610-dcu" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(fsl_dcu_video) = { + .name = "fsl_dcu_video", + .id = UCLASS_VIDEO, + .of_match = fsl_dcu_video_ids, + .bind = fsl_dcu_video_bind, + .probe = fsl_dcu_video_probe, + .flags = DM_FLAG_PRE_RELOC, +}; +#endif /* ifndef CONFIG_DM_VIDEO */ From 750c68a7a7d92b3229cc5db12dd806d4fdc520da Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Mon, 10 Jun 2019 14:47:51 +0300 Subject: [PATCH 03/17] ARM: dts: colibri_vf: Add dcu0 node Add dumb node for NXP Display Control Unit0(DCU), which permits DM_ENABLED converted driver to be probed. Currently no display timings are provided in this node. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- arch/arm/dts/vf-colibri-u-boot.dtsi | 4 ++++ arch/arm/dts/vf-colibri.dtsi | 5 +++++ arch/arm/dts/vf.dtsi | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/arch/arm/dts/vf-colibri-u-boot.dtsi b/arch/arm/dts/vf-colibri-u-boot.dtsi index db86739805d..2294ee9551e 100644 --- a/arch/arm/dts/vf-colibri-u-boot.dtsi +++ b/arch/arm/dts/vf-colibri-u-boot.dtsi @@ -21,3 +21,7 @@ &uart0 { u-boot,dm-pre-reloc; }; + +&dcu0 { + u-boot,dm-pre-reloc; +}; diff --git a/arch/arm/dts/vf-colibri.dtsi b/arch/arm/dts/vf-colibri.dtsi index 91ca4e4ddd3..9de4b28e870 100644 --- a/arch/arm/dts/vf-colibri.dtsi +++ b/arch/arm/dts/vf-colibri.dtsi @@ -14,6 +14,7 @@ aliases { usb0 = &ehci0; /* required for ums */ + display1 = &dcu0; }; reg_usbh_vbus: regulator-usbh-vbus { @@ -241,3 +242,7 @@ pinctrl-0 = <&pinctrl_uart0>; status = "okay"; }; + +&dcu0 { + status = "okay"; +}; diff --git a/arch/arm/dts/vf.dtsi b/arch/arm/dts/vf.dtsi index 5e3b2c5b9dc..5f69d0fd6e6 100644 --- a/arch/arm/dts/vf.dtsi +++ b/arch/arm/dts/vf.dtsi @@ -145,6 +145,12 @@ #gpio-cells = <2>; }; + dcu0: dcu@40058000 { + compatible = "fsl,vf610-dcu"; + reg = <0x40058000 0x1200>; + status = "disabled"; + }; + ehci0: ehci@40034000 { compatible = "fsl,vf610-usb"; reg = <0x40034000 0x800>; From 632e9af551f1c22193976529bb1dbb3b45491aac Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Mon, 10 Jun 2019 14:47:52 +0300 Subject: [PATCH 04/17] colibri_vf: enable DM_VIDEO Enable DM_VIDEO for Colibri VF. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- configs/colibri_vf_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/colibri_vf_defconfig b/configs/colibri_vf_defconfig index 1d48fc966ee..d11104a77d6 100644 --- a/configs/colibri_vf_defconfig +++ b/configs/colibri_vf_defconfig @@ -89,7 +89,7 @@ CONFIG_USB_GADGET_PRODUCT_NUM=0x4000 CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_VIDEO_FSL_DCU_FB=y -CONFIG_VIDEO=y +CONFIG_DM_VIDEO=y CONFIG_SYS_CONSOLE_FG_COL=0x00 CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_FDT_FIXUP_PARTITIONS=y From e19441ecbc24beecced1340be2942b70b6d63d2a Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Wed, 19 Jun 2019 11:47:05 +0300 Subject: [PATCH 05/17] video: mxsfb: fix mxsfb fbdev binding issues Add support for display and bits-per-pixel properties. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- drivers/video/mxsfb.c | 74 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index f02ba201384..6c9a7c05e82 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -271,6 +271,42 @@ dealloc_fb: } #else /* ifndef CONFIG_DM_VIDEO */ +static int mxs_of_get_timings(struct udevice *dev, + struct display_timing *timings, + u32 *bpp) +{ + int ret = 0; + u32 display_phandle; + ofnode display_node; + + ret = ofnode_read_u32(dev_ofnode(dev), "display", &display_phandle); + if (ret) { + dev_err(dev, "required display property isn't provided\n"); + return -EINVAL; + } + + display_node = ofnode_get_by_phandle(display_phandle); + if (!ofnode_valid(display_node)) { + dev_err(dev, "failed to find display subnode\n"); + return -EINVAL; + } + + ret = ofnode_read_u32(display_node, "bits-per-pixel", bpp); + if (ret) { + dev_err(dev, + "required bits-per-pixel property isn't provided\n"); + return -EINVAL; + } + + ret = ofnode_decode_display_timing(display_node, 0, timings); + if (ret) { + dev_err(dev, "failed to get any display timings\n"); + return -EINVAL; + } + + return ret; +} + static int mxs_video_probe(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); @@ -278,18 +314,16 @@ static int mxs_video_probe(struct udevice *dev) struct ctfb_res_modes mode; struct display_timing timings; - int bpp = -1; + u32 bpp = 0; u32 fb_start, fb_end; int ret; debug("%s() plat: base 0x%lx, size 0x%x\n", __func__, plat->base, plat->size); - ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings); - if (ret) { - dev_err(dev, "failed to get any display timings\n"); - return -EINVAL; - } + ret = mxs_of_get_timings(dev, &timings, &bpp); + if (ret) + return ret; mode.xres = timings.hactive.typ; mode.yres = timings.vactive.typ; @@ -301,13 +335,12 @@ static int mxs_video_probe(struct udevice *dev) mode.vsync_len = timings.vsync_len.typ; mode.pixclock = HZ2PS(timings.pixelclock.typ); - bpp = BITS_PP; - ret = mxs_probe_common(&mode, bpp, plat->base); if (ret) return ret; switch (bpp) { + case 32: case 24: case 18: uc_priv->bpix = VIDEO_BPP32; @@ -341,15 +374,32 @@ static int mxs_video_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); struct display_timing timings; + u32 bpp = 0; + u32 bytes_pp = 0; int ret; - ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings); - if (ret) { - dev_err(dev, "failed to get any display timings\n"); + ret = mxs_of_get_timings(dev, &timings, &bpp); + if (ret) + return ret; + + switch (bpp) { + case 32: + case 24: + case 18: + bytes_pp = 4; + break; + case 16: + bytes_pp = 2; + break; + case 8: + bytes_pp = 1; + break; + default: + dev_err(dev, "invalid bpp specified (bpp = %i)\n", bpp); return -EINVAL; } - plat->size = timings.hactive.typ * timings.vactive.typ * BYTES_PP; + plat->size = timings.hactive.typ * timings.vactive.typ * bytes_pp; return 0; } From 34b773d50730a85a8d0ea277f50dbbbea7ec91dd Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Wed, 19 Jun 2019 11:47:06 +0300 Subject: [PATCH 06/17] ARM: dts: colibri_imx7: Fix lcdif node definition Fix lcdif DT node and make it conform to the structure defined in the Linux devicetree bindings [1]. Currently there is support only for old style lcdif node definitions. [1] https://www.kernel.org/doc/Documentation/devicetree/bindings/display/mxsfb.txt Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- arch/arm/dts/imx7-colibri.dtsi | 43 +++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/arch/arm/dts/imx7-colibri.dtsi b/arch/arm/dts/imx7-colibri.dtsi index 81717c233d1..308e0b2a63f 100644 --- a/arch/arm/dts/imx7-colibri.dtsi +++ b/arch/arm/dts/imx7-colibri.dtsi @@ -113,29 +113,34 @@ }; &lcdif { - u-boot,dm-pre-reloc; status = "okay"; + display = <&display0>; + u-boot,dm-pre-reloc; - display-timings { - native-mode = <&timing_vga>; + display0: display0 { + bits-per-pixel = <18>; + bus-width = <24>; + status = "okay"; - /* Standard VGA timing */ - timing_vga: 640x480 { - u-boot,dm-pre-reloc; - clock-frequency = <25175000>; - hactive = <640>; - vactive = <480>; - hback-porch = <48>; - hfront-porch = <16>; - vback-porch = <33>; - vfront-porch = <10>; - hsync-len = <96>; - vsync-len = <2>; + display-timings { + native-mode = <&timing_vga>; + timing_vga: 640x480 { + u-boot,dm-pre-reloc; + clock-frequency = <25175000>; + hactive = <640>; + vactive = <480>; + hback-porch = <48>; + hfront-porch = <16>; + vback-porch = <33>; + vfront-porch = <10>; + hsync-len = <96>; + vsync-len = <2>; - de-active = <1>; - hsync-active = <0>; - vsync-active = <0>; - pixelclk-active = <0>; + de-active = <1>; + hsync-active = <0>; + vsync-active = <0>; + pixelclk-active = <0>; + }; }; }; }; From 2b600bb83378f67920c9982e7dadd2f062b51cf6 Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Wed, 19 Jun 2019 11:47:07 +0300 Subject: [PATCH 07/17] configs: colibri_imx7: enable DM_VIDEO Enable DM_VIDEO support for Colibri iMX7 NAND version. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- configs/colibri_imx7_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/colibri_imx7_defconfig b/configs/colibri_imx7_defconfig index c303c06464d..8e769cd70e6 100644 --- a/configs/colibri_imx7_defconfig +++ b/configs/colibri_imx7_defconfig @@ -74,6 +74,6 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x1b67 CONFIG_USB_GADGET_PRODUCT_NUM=0x4000 CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y -CONFIG_VIDEO=y +CONFIG_DM_VIDEO=y CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_FDT_FIXUP_PARTITIONS=y From 9de5eb23dc7972b9e382327b9a485335b24d3b4a Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Wed, 19 Jun 2019 11:47:08 +0300 Subject: [PATCH 08/17] colibri-imx6ull: support building with DM_VIDEO=y 1. This fixes linking issues when building with DM_VIDEO enabled mxsfb driver. 2. Provide proper defines for both VIDEO=y and DM_VIDEO=y. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- arch/arm/mach-imx/mx6/soc.c | 2 +- include/configs/colibri-imx6ull.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/mx6/soc.c b/arch/arm/mach-imx/mx6/soc.c index 4084ab76729..075d2467ce4 100644 --- a/arch/arm/mach-imx/mx6/soc.c +++ b/arch/arm/mach-imx/mx6/soc.c @@ -554,7 +554,7 @@ const struct boot_mode soc_boot_modes[] = { void reset_misc(void) { #ifndef CONFIG_SPL_BUILD -#ifdef CONFIG_VIDEO_MXS +#if defined(CONFIG_VIDEO_MXS) && !defined(CONFIG_DM_VIDEO) lcdif_power_down(); #endif #endif diff --git a/include/configs/colibri-imx6ull.h b/include/configs/colibri-imx6ull.h index 2c43862800a..05af222a1fa 100644 --- a/include/configs/colibri-imx6ull.h +++ b/include/configs/colibri-imx6ull.h @@ -170,7 +170,7 @@ #define CONFIG_SYS_DFU_DATA_BUF_SIZE SZ_16M #define DFU_DEFAULT_POLL_TIMEOUT 300 -#ifdef CONFIG_VIDEO +#if defined(CONFIG_VIDEO) || defined(CONFIG_DM_VIDEO) #define CONFIG_VIDEO_MXS #define MXS_LCDIF_BASE MX6UL_LCDIF1_BASE_ADDR #define CONFIG_VIDEO_LOGO From 1c7bade847a67738945bfe5321895c25126799fa Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Wed, 19 Jun 2019 11:47:09 +0300 Subject: [PATCH 09/17] ARM: dts: colibri-imx6ull: extend lcdif node Provide proper display timings for lcdif node, used by mxsfb DM_VIDEO enabled framebuffer driver. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- arch/arm/dts/imx6ull-colibri.dts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/arm/dts/imx6ull-colibri.dts b/arch/arm/dts/imx6ull-colibri.dts index 6c847ab7921..262205ac5e8 100644 --- a/arch/arm/dts/imx6ull-colibri.dts +++ b/arch/arm/dts/imx6ull-colibri.dts @@ -12,8 +12,10 @@ compatible = "toradex,colibri-imx6ull", "fsl,imx6ull"; aliases { + u-boot,dm-pre-reloc; mmc0 = &usdhc1; usb0 = &usbotg1; /* required for ums */ + display0 = &lcdif; }; chosen { @@ -156,6 +158,36 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcdif_dat &pinctrl_lcdif_ctrl>; + status = "okay"; + display = <&display0>; + u-boot,dm-pre-reloc; + + display0: display0 { + bits-per-pixel = <18>; + bus-width = <24>; + status = "okay"; + + display-timings { + native-mode = <&timing_vga>; + timing_vga: 640x480 { + u-boot,dm-pre-reloc; + clock-frequency = <25175000>; + hactive = <640>; + vactive = <480>; + hback-porch = <48>; + hfront-porch = <16>; + vback-porch = <33>; + vfront-porch = <10>; + hsync-len = <96>; + vsync-len = <2>; + + de-active = <1>; + hsync-active = <0>; + vsync-active = <0>; + pixelclk-active = <0>; + }; + }; + }; }; /* PWM */ From 6be815d6dd571aa838a7ed65cb2c9e6dc70ac821 Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Wed, 19 Jun 2019 11:47:10 +0300 Subject: [PATCH 10/17] configs: colibri-imx6ull: switch to DM_VIDEO Use CONFIG_DM_VIDEO=y by default for Colibri iMX6ULL. Signed-off-by: Igor Opaniuk Reviewed-by: Oleksandr Suvorov --- configs/colibri-imx6ull_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/colibri-imx6ull_defconfig b/configs/colibri-imx6ull_defconfig index 2b57b5e41ef..e1842237730 100644 --- a/configs/colibri-imx6ull_defconfig +++ b/configs/colibri-imx6ull_defconfig @@ -78,6 +78,6 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x1b67 CONFIG_USB_GADGET_PRODUCT_NUM=0x4000 CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y -CONFIG_VIDEO=y +CONFIG_DM_VIDEO=y CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_FDT_FIXUP_PARTITIONS=y From 85288ffee6826bf24b035a43866d8badfe107fc9 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Mon, 27 May 2019 08:14:39 +0200 Subject: [PATCH 11/17] video, simple_panel: add lg,lb070wv8 display add "lg,lb070wv8" display to compatible node. Signed-off-by: Heiko Schocher --- drivers/video/simple_panel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index 7a968e740c5..c3c0e847327 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -105,6 +105,7 @@ static const struct udevice_id simple_panel_ids[] = { { .compatible = "auo,b133xtn01" }, { .compatible = "auo,b116xw03" }, { .compatible = "auo,b133htn01" }, + { .compatible = "lg,lb070wv8" }, { } }; From 245b1029e1af8b2e71c6d7aebc7d68bdebd644d3 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Thu, 13 Jun 2019 05:12:38 +0200 Subject: [PATCH 12/17] bmp_logo: support CONFIG_DM_VIDEO in case of bmp_logo, the video_bmp driver is used for drawing a bmp logo. This driver supports only "full" bmp data. Adding a logo with the bmp_logo tool to u-boot binary adds currently only real data and drops the bmp header. This patch adds now the full bmp data to the u-boot binary, so video_bmp driver works with the logo embedded into u-boot. Fixed also some checkpatch error poping up with this patch. Signed-off-by: Heiko Schocher --- tools/Makefile | 6 ++++++ tools/bmp_logo.c | 42 +++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index 87d81a3d416..c7afe8a4b3f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -269,8 +269,14 @@ __build: $(LOGO-y) $(LOGO_H): $(obj)/bmp_logo $(LOGO_BMP) $(obj)/bmp_logo --gen-info $(LOGO_BMP) > $@ +ifeq ($(CONFIG_DM_VIDEO),y) +$(LOGO_DATA_H): $(obj)/bmp_logo $(LOGO_BMP) + $(obj)/bmp_logo --gen-bmp $(LOGO_BMP) > $@ +else $(LOGO_DATA_H): $(obj)/bmp_logo $(LOGO_BMP) $(obj)/bmp_logo --gen-data $(LOGO_BMP) > $@ +#endif +endif # Let clean descend into subdirs subdir- += env diff --git a/tools/bmp_logo.c b/tools/bmp_logo.c index 55f833fb9b8..74fcadca63e 100644 --- a/tools/bmp_logo.c +++ b/tools/bmp_logo.c @@ -2,7 +2,8 @@ enum { MODE_GEN_INFO, - MODE_GEN_DATA + MODE_GEN_DATA, + MODE_GEN_BMP }; typedef struct bitmap_s { /* bitmap description */ @@ -16,7 +17,8 @@ typedef struct bitmap_s { /* bitmap description */ void usage(const char *prog) { - fprintf(stderr, "Usage: %s [--gen-info|--gen-data] file\n", prog); + fprintf(stderr, "Usage: %s [--gen-info|--gen-data|--gen-bmp] file\n", + prog); } /* @@ -73,6 +75,7 @@ void gen_info(bitmap_t *b, uint16_t n_colors) int main (int argc, char *argv[]) { int mode, i, x; + int size; FILE *fp; bitmap_t bmp; bitmap_t *b = &bmp; @@ -87,6 +90,8 @@ int main (int argc, char *argv[]) mode = MODE_GEN_INFO; else if (!strcmp(argv[1], "--gen-data")) mode = MODE_GEN_DATA; + else if (!strcmp(argv[1], "--gen-bmp")) + mode = MODE_GEN_BMP; else { usage(argv[0]); exit(EXIT_FAILURE); @@ -131,6 +136,7 @@ int main (int argc, char *argv[]) b->width = le_short(b->width); b->height = le_short(b->height); n_colors = le_short(n_colors); + size = b->width * b->height; /* assume we are working with an 8-bit file */ if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) { @@ -152,10 +158,6 @@ int main (int argc, char *argv[]) "#ifndef __BMP_LOGO_DATA_H__\n" "#define __BMP_LOGO_DATA_H__\n\n"); - /* allocate memory */ - if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL) - error ("Error allocating memory for file", fp); - /* read and print the palette information */ printf("unsigned short bmp_logo_palette[] = {\n"); @@ -175,21 +177,39 @@ int main (int argc, char *argv[]) } /* seek to offset indicated by file header */ - fseek(fp, (long)data_offset, SEEK_SET); + if (mode == MODE_GEN_BMP) { + /* copy full bmp file */ + fseek(fp, 0L, SEEK_END); + size = ftell(fp); + fseek(fp, 0L, SEEK_SET); + } else { + fseek(fp, (long)data_offset, SEEK_SET); + } + + /* allocate memory */ + b->data = (uint8_t *)malloc(size); + if (!b->data) + error("Error allocating memory for file", fp); /* read the bitmap; leave room for default color map */ printf ("\n"); printf ("};\n"); printf ("\n"); printf("unsigned char bmp_logo_bitmap[] = {\n"); - for (i=(b->height-1)*b->width; i>=0; i-=b->width) { - for (x = 0; x < b->width; x++) { - b->data[i + x] = (uint8_t) fgetc(fp) + if (mode == MODE_GEN_BMP) { + /* write full bmp */ + for (i = 0; i < size; i++) + b->data[i] = (uint8_t)fgetc(fp); + } else { + for (i = (b->height - 1) * b->width; i >= 0; i -= b->width) { + for (x = 0; x < b->width; x++) { + b->data[i + x] = (uint8_t)fgetc(fp) + DEFAULT_CMAP_SIZE; + } } } - for (i=0; i<(b->height*b->width); ++i) { + for (i = 0; i < size; ++i) { if ((i%8) == 0) putchar ('\t'); printf ("0x%02X,%c", From 1c1ed441b0d1d7d5fbf02cf89a390c04b18f8ba3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 4 Jul 2019 15:52:06 +0200 Subject: [PATCH 13/17] edid: add edid_get_timing_validate() variant to filter out edid modes The original edid_get_timing() function returns the first valid timing, but on some plaforms, we could only supports a subset of the listed monitot's navite timing. Let's introduce a edid_get_timing_validate() adding a mode_valid callback including a private cookie pointer. If the callback returns false, the current timing is discared and the next one is checked. If no valid & supported timings are found, the function would return an error. Signed-off-by: Neil Armstrong --- common/edid.c | 22 +++++++++++++++++++--- include/edid.h | 22 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/common/edid.c b/common/edid.c index 90d1167f6ee..f244d26e04b 100644 --- a/common/edid.c +++ b/common/edid.c @@ -168,8 +168,12 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info) return false; } -int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing, - int *panel_bits_per_colourp) +int edid_get_timing_validate(u8 *buf, int buf_size, + struct display_timing *timing, + int *panel_bits_per_colourp, + bool (*mode_valid)(void *priv, + const struct display_timing *timing), + void *mode_valid_priv) { struct edid1_info *edid = (struct edid1_info *)buf; bool timing_done; @@ -193,7 +197,11 @@ int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing, desc = &edid->monitor_details.descriptor[i]; if (desc->zero_flag_1 != 0) { decode_timing((u8 *)desc, timing); - timing_done = true; + if (mode_valid) + timing_done = mode_valid(mode_valid_priv, + timing); + else + timing_done = true; break; } } @@ -225,6 +233,14 @@ int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing, return 0; } +int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing, + int *panel_bits_per_colourp) +{ + return edid_get_timing_validate(buf, buf_size, timing, + panel_bits_per_colourp, NULL, NULL); +} + + /** * Snip the tailing whitespace/return of a string. * diff --git a/include/edid.h b/include/edid.h index f05d2b82f24..2562733061c 100644 --- a/include/edid.h +++ b/include/edid.h @@ -306,6 +306,28 @@ int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, struct display_timing; +/** + * edid_get_timing_validate() - Get basic digital display parameters with + * mode selection callback + * + * @param buf Buffer containing EDID data + * @param buf_size Size of buffer in bytes + * @param timing Place to put preferring timing information + * @param panel_bits_per_colourp Place to put the number of bits per + * colour supported by the panel. This will be set to + * -1 if not available + * @param mode_valid Callback validating mode, returning true is mode is + * supported, false otherwise. + * @parem valid_priv Pointer to private data for mode_valid callback + * @return 0 if timings are OK, -ve on error + */ +int edid_get_timing_validate(u8 *buf, int buf_size, + struct display_timing *timing, + int *panel_bits_per_colourp, + bool (*mode_valid)(void *priv, + const struct display_timing *timing), + void *mode_valid_priv); + /** * edid_get_timing() - Get basic digital display parameters * From eb4ee4e436287a69de7a87ea3070fa52bd327602 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 4 Jul 2019 15:52:07 +0200 Subject: [PATCH 14/17] video: display: use edid_get_timing_validate() variant to filter supported EDID modes Introduce a new display op, mode_valid() to be used with the newly introduced edid_get_timing_validate() function, to filter supported monitor timings if handled by the display driver. Signed-off-by: Neil Armstrong --- drivers/video/display-uclass.c | 15 ++++++++++++++- include/display.h | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/video/display-uclass.c b/drivers/video/display-uclass.c index 99ef5e76f54..1a29ce5d858 100644 --- a/drivers/video/display-uclass.c +++ b/drivers/video/display-uclass.c @@ -37,6 +37,17 @@ int display_enable(struct udevice *dev, int panel_bpp, return 0; } +static bool display_mode_valid(void *priv, const struct display_timing *timing) +{ + struct udevice *dev = priv; + struct dm_display_ops *ops = display_get_ops(dev); + + if (ops && ops->mode_valid) + return ops->mode_valid(dev, timing); + + return true; +} + int display_read_timing(struct udevice *dev, struct display_timing *timing) { struct dm_display_ops *ops = display_get_ops(dev); @@ -53,7 +64,9 @@ int display_read_timing(struct udevice *dev, struct display_timing *timing) if (ret < 0) return ret; - return edid_get_timing(buf, ret, timing, &panel_bits_per_colour); + return edid_get_timing_validate(buf, ret, timing, + &panel_bits_per_colour, + display_mode_valid, dev); } bool display_in_use(struct udevice *dev) diff --git a/include/display.h b/include/display.h index 16f317c9c8c..66294616ea2 100644 --- a/include/display.h +++ b/include/display.h @@ -80,6 +80,16 @@ struct dm_display_ops { */ int (*enable)(struct udevice *dev, int panel_bpp, const struct display_timing *timing); + + /** + * mode_valid() - Check if mode is supported + * + * @dev: Device to enable + * @timing: Display timings + * @return true if supported, false if not + */ + bool (*mode_valid)(struct udevice *dev, + const struct display_timing *timing); }; #define display_get_ops(dev) ((struct dm_display_ops *)(dev)->driver->ops) From 233358c46a753438d9f0c26dc67dad3ddecca1e9 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 4 Jul 2019 15:52:08 +0200 Subject: [PATCH 15/17] video: meson: dw-hdmi: add EDID mode filtering to only select supported modes Add support for the new mode_valid() display op to filter out unsupported display DMT timings. This is useful when connected to 4k displays, since we only support DMT monitors up to 1920x1080, the 4k native timings are discarded to select supported timings. Signed-off-by: Neil Armstrong --- drivers/video/meson/meson_dw_hdmi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c index 483c93f6b6c..617f75724b5 100644 --- a/drivers/video/meson/meson_dw_hdmi.c +++ b/drivers/video/meson/meson_dw_hdmi.c @@ -426,9 +426,16 @@ static int meson_dw_hdmi_probe(struct udevice *dev) return ret; } +static bool meson_dw_hdmi_mode_valid(struct udevice *dev, + const struct display_timing *timing) +{ + return meson_venc_hdmi_supported_mode(timing); +} + static const struct dm_display_ops meson_dw_hdmi_ops = { .read_edid = meson_dw_hdmi_read_edid, .enable = meson_dw_hdmi_enable, + .mode_valid = meson_dw_hdmi_mode_valid, }; static const struct udevice_id meson_dw_hdmi_ids[] = { From 60a62acfb07afb0815f28abe6f49a9b906a7c3f4 Mon Sep 17 00:00:00 2001 From: Niklas Schulze Date: Sat, 27 Jul 2019 12:07:13 +0000 Subject: [PATCH 16/17] video: dw_hdmi: Add support for ddc-i2c-bus property Add support for the ddc-i2c-bus device tree property which allows for using an external i2c master for reading the display's EDID. Signed-off-by: Niklas Schulze --- drivers/video/dw_hdmi.c | 13 +++++++++++++ drivers/video/meson/meson_dw_hdmi.c | 3 +++ drivers/video/rockchip/rk_hdmi.c | 3 +++ drivers/video/sunxi/sunxi_dw_hdmi.c | 3 +++ include/dw_hdmi.h | 1 + 5 files changed, 23 insertions(+) diff --git a/drivers/video/dw_hdmi.c b/drivers/video/dw_hdmi.c index 463436edf3e..bf74d6adf20 100644 --- a/drivers/video/dw_hdmi.c +++ b/drivers/video/dw_hdmi.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "dw_hdmi.h" @@ -812,6 +813,18 @@ static int hdmi_read_edid(struct dw_hdmi *hdmi, int block, u8 *buff) u32 trytime = 5; u32 n; + if (CONFIG_IS_ENABLED(DM_I2C) && hdmi->ddc_bus) { + struct udevice *chip; + + edid_read_err = i2c_get_chip(hdmi->ddc_bus, + HDMI_I2CM_SLAVE_DDC_ADDR, + 1, &chip); + if (edid_read_err) + return edid_read_err; + + return dm_i2c_read(chip, shift, buff, HDMI_EDID_BLOCK_SIZE); + } + /* set ddc i2c clk which devided from ddc_clk to 100khz */ hdmi_write(hdmi, hdmi->i2c_clk_high, HDMI_I2CM_SS_SCL_HCNT_0_ADDR); hdmi_write(hdmi, hdmi->i2c_clk_low, HDMI_I2CM_SS_SCL_LCNT_0_ADDR); diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c index 617f75724b5..9831d978fca 100644 --- a/drivers/video/meson/meson_dw_hdmi.c +++ b/drivers/video/meson/meson_dw_hdmi.c @@ -375,6 +375,9 @@ static int meson_dw_hdmi_probe(struct udevice *dev) } #endif + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", + &priv->hdmi.ddc_bus); + ret = reset_get_bulk(dev, &resets); if (ret) return ret; diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c index 51931ceefae..5b44a7e8c97 100644 --- a/drivers/video/rockchip/rk_hdmi.c +++ b/drivers/video/rockchip/rk_hdmi.c @@ -93,6 +93,9 @@ int rk_hdmi_ofdata_to_platdata(struct udevice *dev) priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", + &hdmi->ddc_bus); + return 0; } diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 6fe1aa7ee46..cec23295b5c 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -373,6 +373,9 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg; priv->mux = uc_plat->source_id; + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", + &priv->hdmi.ddc_bus); + dw_hdmi_init(&priv->hdmi); return 0; diff --git a/include/dw_hdmi.h b/include/dw_hdmi.h index 90fb64bc998..8acae3839fb 100644 --- a/include/dw_hdmi.h +++ b/include/dw_hdmi.h @@ -542,6 +542,7 @@ struct dw_hdmi { u8 i2c_clk_low; u8 reg_io_width; struct hdmi_data_info hdmi_data; + struct udevice *ddc_bus; int (*phy_set)(struct dw_hdmi *hdmi, uint mpixelclock); void (*write_reg)(struct dw_hdmi *hdmi, u8 val, int offset); From 970baf16d1322d3930a57fc78ddfb15d594d690c Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Thu, 11 Jul 2019 16:56:24 +0200 Subject: [PATCH 17/17] video: arm: rpi: Bail out early if querying video information fails When probing we query for the width and hight of the display. If the firmware does not report any connected display the system will crash. See https://github.com/raspberrypi/firmware/issues/1157 for details. Signed-off-by: Fabian Vogt [mb: update commit message] Signed-off-by: Matthias Brugger Reviewed-by: Andre Przywara Tested-by: Andre Przywara --- drivers/video/bcm2835.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index bc41090aed7..1d2eda084c8 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -19,13 +19,15 @@ static int bcm2835_video_probe(struct udevice *dev) debug("bcm2835: Query resolution...\n"); ret = bcm2835_get_video_size(&w, &h); - if (ret) + if (ret || w == 0 || h == 0) return -EIO; debug("bcm2835: Setting up display for %d x %d\n", w, h); ret = bcm2835_set_video_params(&w, &h, 32, BCM2835_MBOX_PIXEL_ORDER_RGB, BCM2835_MBOX_ALPHA_MODE_IGNORED, &fb_base, &fb_size, &pitch); + if (ret) + return -EIO; debug("bcm2835: Final resolution is %d x %d\n", w, h);