From b215fb3f34befbff084550b67ee15c0363e9e9de Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Tue, 11 Apr 2017 11:12:09 +0530 Subject: [PATCH 1/9] Convert CONFIG_FSL_DCU_FB to Kconfig Rename CONFIG_FSL_DCU_FB to CONFIG_VIDEO_FSL_DCU_FB and convert it to Kconfig. Signed-off-by: Sanchayan Maity Reviewed-by: Stefan Agner Reviewed-by: Alison Wang --- arch/arm/cpu/armv7/ls102xa/soc.c | 2 +- board/freescale/ls1021aiot/Makefile | 2 +- board/freescale/ls1021aqds/Makefile | 2 +- board/freescale/ls1021atwr/Makefile | 2 +- configs/ls1021aqds_ddr4_nor_defconfig | 1 + configs/ls1021aqds_ddr4_nor_lpuart_defconfig | 1 + configs/ls1021aqds_nand_defconfig | 1 + configs/ls1021aqds_nor_SECURE_BOOT_defconfig | 1 + configs/ls1021aqds_nor_defconfig | 1 + configs/ls1021aqds_nor_lpuart_defconfig | 1 + configs/ls1021aqds_qspi_defconfig | 1 + configs/ls1021aqds_sdcard_ifc_defconfig | 1 + configs/ls1021aqds_sdcard_qspi_defconfig | 1 + configs/ls1021atwr_nor_SECURE_BOOT_defconfig | 1 + configs/ls1021atwr_nor_defconfig | 1 + configs/ls1021atwr_nor_lpuart_defconfig | 1 + configs/ls1021atwr_qspi_defconfig | 1 + configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig | 1 + configs/ls1021atwr_sdcard_ifc_defconfig | 1 + configs/ls1021atwr_sdcard_qspi_defconfig | 1 + drivers/video/Kconfig | 7 +++++++ drivers/video/Makefile | 2 +- include/configs/ls1021aqds.h | 4 +--- include/configs/ls1021atwr.h | 4 +--- scripts/config_whitelist.txt | 1 - 25 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/arm/cpu/armv7/ls102xa/soc.c b/arch/arm/cpu/armv7/ls102xa/soc.c index 52fb6f8..b84a1a6 100644 --- a/arch/arm/cpu/armv7/ls102xa/soc.c +++ b/arch/arm/cpu/armv7/ls102xa/soc.c @@ -91,7 +91,7 @@ int arch_soc_init(void) out_be32(&scfg->qspi_cfg, SCFG_QSPI_CLKSEL); #endif -#ifdef CONFIG_FSL_DCU_FB +#ifdef CONFIG_VIDEO_FSL_DCU_FB out_be32(&scfg->pixclkcr, SCFG_PIXCLKCR_PXCKEN); #endif diff --git a/board/freescale/ls1021aiot/Makefile b/board/freescale/ls1021aiot/Makefile index 05709e6..6b960aa 100644 --- a/board/freescale/ls1021aiot/Makefile +++ b/board/freescale/ls1021aiot/Makefile @@ -5,5 +5,5 @@ # obj-y += ls1021aiot.o -obj-$(CONFIG_FSL_DCU_FB) += dcu.o +obj-$(CONFIG_VIDEO_FSL_DCU_FB) += dcu.o obj-$(CONFIG_ARMV7_PSCI) += psci.o diff --git a/board/freescale/ls1021aqds/Makefile b/board/freescale/ls1021aqds/Makefile index f0390c1..1e50e46 100644 --- a/board/freescale/ls1021aqds/Makefile +++ b/board/freescale/ls1021aqds/Makefile @@ -7,5 +7,5 @@ obj-y += ls1021aqds.o obj-y += ddr.o obj-y += eth.o -obj-$(CONFIG_FSL_DCU_FB) += dcu.o +obj-$(CONFIG_VIDEO_FSL_DCU_FB) += dcu.o obj-$(CONFIG_ARMV7_PSCI) += psci.o diff --git a/board/freescale/ls1021atwr/Makefile b/board/freescale/ls1021atwr/Makefile index 5238b15..d9a2f52 100644 --- a/board/freescale/ls1021atwr/Makefile +++ b/board/freescale/ls1021atwr/Makefile @@ -5,5 +5,5 @@ # obj-y += ls1021atwr.o -obj-$(CONFIG_FSL_DCU_FB) += dcu.o +obj-$(CONFIG_VIDEO_FSL_DCU_FB) += dcu.o obj-$(CONFIG_ARMV7_PSCI) += psci.o diff --git a/configs/ls1021aqds_ddr4_nor_defconfig b/configs/ls1021aqds_ddr4_nor_defconfig index 8434870..5566053 100644 --- a/configs/ls1021aqds_ddr4_nor_defconfig +++ b/configs/ls1021aqds_ddr4_nor_defconfig @@ -43,3 +43,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021aqds_ddr4_nor_lpuart_defconfig b/configs/ls1021aqds_ddr4_nor_lpuart_defconfig index ece220b..9582662 100644 --- a/configs/ls1021aqds_ddr4_nor_lpuart_defconfig +++ b/configs/ls1021aqds_ddr4_nor_lpuart_defconfig @@ -44,3 +44,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021aqds_nand_defconfig b/configs/ls1021aqds_nand_defconfig index dc547b5..73f2fb0 100644 --- a/configs/ls1021aqds_nand_defconfig +++ b/configs/ls1021aqds_nand_defconfig @@ -57,3 +57,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021aqds_nor_SECURE_BOOT_defconfig b/configs/ls1021aqds_nor_SECURE_BOOT_defconfig index d1760ed..74e1241 100644 --- a/configs/ls1021aqds_nor_SECURE_BOOT_defconfig +++ b/configs/ls1021aqds_nor_SECURE_BOOT_defconfig @@ -43,5 +43,6 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y CONFIG_RSA=y CONFIG_SPL_RSA=y diff --git a/configs/ls1021aqds_nor_defconfig b/configs/ls1021aqds_nor_defconfig index 8de90b0..14a2b7f 100644 --- a/configs/ls1021aqds_nor_defconfig +++ b/configs/ls1021aqds_nor_defconfig @@ -44,3 +44,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021aqds_nor_lpuart_defconfig b/configs/ls1021aqds_nor_lpuart_defconfig index a9efdc5..9ed301c 100644 --- a/configs/ls1021aqds_nor_lpuart_defconfig +++ b/configs/ls1021aqds_nor_lpuart_defconfig @@ -45,3 +45,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021aqds_qspi_defconfig b/configs/ls1021aqds_qspi_defconfig index 735f517..9ec21c5 100644 --- a/configs/ls1021aqds_qspi_defconfig +++ b/configs/ls1021aqds_qspi_defconfig @@ -50,3 +50,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021aqds_sdcard_ifc_defconfig b/configs/ls1021aqds_sdcard_ifc_defconfig index 027d368..492676a 100644 --- a/configs/ls1021aqds_sdcard_ifc_defconfig +++ b/configs/ls1021aqds_sdcard_ifc_defconfig @@ -55,3 +55,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021aqds_sdcard_qspi_defconfig b/configs/ls1021aqds_sdcard_qspi_defconfig index f9ea99b..ed0b17b 100644 --- a/configs/ls1021aqds_sdcard_qspi_defconfig +++ b/configs/ls1021aqds_sdcard_qspi_defconfig @@ -61,3 +61,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021atwr_nor_SECURE_BOOT_defconfig b/configs/ls1021atwr_nor_SECURE_BOOT_defconfig index 5b6ca22..6af8dbd 100644 --- a/configs/ls1021atwr_nor_SECURE_BOOT_defconfig +++ b/configs/ls1021atwr_nor_SECURE_BOOT_defconfig @@ -42,5 +42,6 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y CONFIG_RSA=y CONFIG_SPL_RSA=y diff --git a/configs/ls1021atwr_nor_defconfig b/configs/ls1021atwr_nor_defconfig index 3fb507f..93b6467 100644 --- a/configs/ls1021atwr_nor_defconfig +++ b/configs/ls1021atwr_nor_defconfig @@ -42,3 +42,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021atwr_nor_lpuart_defconfig b/configs/ls1021atwr_nor_lpuart_defconfig index 725720d..c176e83 100644 --- a/configs/ls1021atwr_nor_lpuart_defconfig +++ b/configs/ls1021atwr_nor_lpuart_defconfig @@ -43,3 +43,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021atwr_qspi_defconfig b/configs/ls1021atwr_qspi_defconfig index 46f7e26..548d574 100644 --- a/configs/ls1021atwr_qspi_defconfig +++ b/configs/ls1021atwr_qspi_defconfig @@ -50,3 +50,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig b/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig index 783787a..bd00170 100644 --- a/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig +++ b/configs/ls1021atwr_sdcard_ifc_SECURE_BOOT_defconfig @@ -57,5 +57,6 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y CONFIG_RSA=y CONFIG_SPL_RSA=y diff --git a/configs/ls1021atwr_sdcard_ifc_defconfig b/configs/ls1021atwr_sdcard_ifc_defconfig index b558e83..1070111 100644 --- a/configs/ls1021atwr_sdcard_ifc_defconfig +++ b/configs/ls1021atwr_sdcard_ifc_defconfig @@ -54,3 +54,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/configs/ls1021atwr_sdcard_qspi_defconfig b/configs/ls1021atwr_sdcard_qspi_defconfig index ef07375..5eddabd 100644 --- a/configs/ls1021atwr_sdcard_qspi_defconfig +++ b/configs/ls1021atwr_sdcard_qspi_defconfig @@ -61,3 +61,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_STORAGE=y # CONFIG_VIDEO_SW_CURSOR is not set +CONFIG_VIDEO_FSL_DCU_FB=y diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2069576..6aab8af 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -395,6 +395,13 @@ config VIDEO_IVYBRIDGE_IGD a special tool which configures the VGA ROM, but the graphics resolution can be selected in U-Boot. +config VIDEO_FSL_DCU_FB + bool "Enable Freescale Display Control Unit" + depends on VIDEO + help + This enables support for Freescale Display Control Unit (DCU4) + module found on Freescale Vybrid and QorIQ family of SoCs. + config VIDEO_ROCKCHIP bool "Enable Rockchip video support" depends on DM_VIDEO diff --git a/drivers/video/Makefile b/drivers/video/Makefile index db34904..7cd6d28 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o obj-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o obj-$(CONFIG_CFB_CONSOLE) += cfb_console.o obj-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o -obj-$(CONFIG_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o +obj-$(CONFIG_VIDEO_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o obj-$(CONFIG_L5F31188) += l5f31188.o obj-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o obj-$(CONFIG_PXA_LCD) += pxa_lcd.o diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h index b349b36..97b8127 100644 --- a/include/configs/ls1021aqds.h +++ b/include/configs/ls1021aqds.h @@ -421,9 +421,7 @@ unsigned long get_board_ddr_clk(void); /* * Video */ -#define CONFIG_FSL_DCU_FB - -#ifdef CONFIG_FSL_DCU_FB +#ifdef CONFIG_VIDEO_FSL_DCU_FB #define CONFIG_CMD_BMP #define CONFIG_VIDEO_LOGO #define CONFIG_VIDEO_BMP_LOGO diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h index fcf035b..a60b4b2 100644 --- a/include/configs/ls1021atwr.h +++ b/include/configs/ls1021atwr.h @@ -300,9 +300,7 @@ /* * Video */ -#define CONFIG_FSL_DCU_FB - -#ifdef CONFIG_FSL_DCU_FB +#ifdef CONFIG_VIDEO_FSL_DCU_FB #define CONFIG_CMD_BMP #define CONFIG_VIDEO_LOGO #define CONFIG_VIDEO_BMP_LOGO diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 330bc58..9d238bd 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1041,7 +1041,6 @@ CONFIG_FSLDMAFEC CONFIG_FSL_CADMUS CONFIG_FSL_CORENET CONFIG_FSL_CPLD -CONFIG_FSL_DCU_FB CONFIG_FSL_DCU_SII9022A CONFIG_FSL_DDR_BIST CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE From 77810e638efb5cdfed0c2f55149b59dca6f519d9 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 11 Apr 2017 11:12:10 +0530 Subject: [PATCH 2/9] video: fsl_dcu_fb: fix framebuffer to the end of memory Fix the framebuffer location to the very end of the available memory. This allows to remove the area from available memory for the kernel, which in turn allows to display the splash screen through the Linux kernel boot process. Ideas has been taken from the sunxi display driver, e.g. 20779ec3a5 ("sunxi: video: Dynamically reserve framebuffer memory") Signed-off-by: Stefan Agner Signed-off-by: Sanchayan Maity --- drivers/video/Kconfig | 8 ++++++++ drivers/video/fsl_dcu_fb.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- include/fsl_dcu_fb.h | 1 + 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6aab8af..d1b017c 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -402,6 +402,14 @@ config VIDEO_FSL_DCU_FB This enables support for Freescale Display Control Unit (DCU4) module found on Freescale Vybrid and QorIQ family of SoCs. +config VIDEO_FSL_DCU_MAX_FB_SIZE_MB + int "Freescale DCU framebuffer size" + depends on VIDEO_FSL_DCU_FB + default 4194304 + help + Set maximum framebuffer size to be used for Freescale Display + Controller Unit (DCU4). + config VIDEO_ROCKCHIP bool "Enable Rockchip video support" depends on DM_VIDEO diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c index d4cd382..7f03290 100644 --- a/drivers/video/fsl_dcu_fb.c +++ b/drivers/video/fsl_dcu_fb.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -79,6 +80,8 @@ #define BPP_24_RGB888 5 #define BPP_32_ARGB8888 6 +DECLARE_GLOBAL_DATA_PTR; + /* * This setting is used for the TWR_LCD_RGB card */ @@ -254,11 +257,19 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres, struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; unsigned int div, mode; - /* Memory allocation for framebuffer */ info.screen_size = info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8); - info.screen_base = (char *)memalign(ARCH_DMA_MINALIGN, - roundup(info.screen_size, ARCH_DMA_MINALIGN)); + + if (info.screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) { + info.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; + memset(info.screen_base, 0, info.screen_size); reset_total_layers(); @@ -305,6 +316,11 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres, return 0; } +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) { static GraphicDevice ctfb; @@ -363,3 +379,26 @@ void *video_hw_init(void) return &ctfb; } + +#if defined(CONFIG_OF_BOARD_SETUP) +int fsl_dcu_fixedfb_setup(void *blob) +{ + u64 start, size; + int ret; + + start = gd->bd->bi_dram[0].start; + size = gd->bd->bi_dram[0].size - info.screen_size; + + /* + * Align size on section size (1 MiB). + */ + size &= 0xfff00000; + ret = fdt_fixup_memory_banks(blob, &start, &size, 1); + if (ret) { + eprintf("Cannot setup fb: Error reserving memory\n"); + return ret; + } + + return 0; +} +#endif diff --git a/include/fsl_dcu_fb.h b/include/fsl_dcu_fb.h index 4263298..67e29e7 100644 --- a/include/fsl_dcu_fb.h +++ b/include/fsl_dcu_fb.h @@ -9,6 +9,7 @@ int fsl_dcu_init(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, From 32f26f56b3b918444ee2b3bf8f928bec506021b8 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 11 Apr 2017 11:12:11 +0530 Subject: [PATCH 3/9] video: fsl_dcu_fb: Enable pixel clock after initialization When enabling the DCU and pixel clock, the test mode is activated since this is the reset configuration. The test mode immediately shows a red screen on a LCD. A moment later, the DCU gets initialized properly. This patch enables the pixel clock after initialization of the DCU control register. This avoids this initial flicker on LCD screens. While at it change the polarity of pixel clock to display samples data on the rising edge. Signed-off-by: Stefan Agner Signed-off-by: Sanchayan Maity Reviewed-by: Alison Wang --- drivers/video/fsl_dcu_fb.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c index 7f03290..c6ed3c4 100644 --- a/drivers/video/fsl_dcu_fb.c +++ b/drivers/video/fsl_dcu_fb.c @@ -41,7 +41,7 @@ #define DCU_VSYN_PARA_BP(x) ((x) << 22) #define DCU_VSYN_PARA_PW(x) ((x) << 11) #define DCU_VSYN_PARA_FP(x) (x) -#define DCU_SYN_POL_INV_PXCK_FALL (0 << 6) +#define DCU_SYN_POL_INV_PXCK_FALL (1 << 6) #define DCU_SYN_POL_NEG_REMAIN (0 << 5) #define DCU_SYN_POL_INV_VS_LOW (1 << 1) #define DCU_SYN_POL_INV_HS_LOW (1) @@ -191,8 +191,6 @@ static void reset_total_layers(void) dcu_write32(®s->ctrldescl[i][9], 0); dcu_write32(®s->ctrldescl[i][10], 0); } - - dcu_write32(®s->update_mode, DCU_UPDATE_MODE_READREG); } static int layer_ctrldesc_init(int index, u32 pixel_format) @@ -246,8 +244,6 @@ static int layer_ctrldesc_init(int index, u32 pixel_format) dcu_write32(®s->ctrldescl[index][7], DCU_CTRLDESCLN_8_FG_FCOLOR(0)); dcu_write32(®s->ctrldescl[index][8], DCU_CTRLDESCLN_9_BG_BCOLOR(0)); - dcu_write32(®s->update_mode, DCU_UPDATE_MODE_READREG); - return 0; } @@ -273,8 +269,6 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres, memset(info.screen_base, 0, info.screen_size); reset_total_layers(); - div = dcu_set_pixel_clock(info.var.pixclock); - dcu_write32(®s->div_ratio, (div - 1)); dcu_write32(®s->disp_size, DCU_DISP_SIZE_DELTA_Y(info.var.yres) | @@ -313,6 +307,11 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres, layer_ctrldesc_init(0, pixel_format); + div = dcu_set_pixel_clock(info.var.pixclock); + dcu_write32(®s->div_ratio, (div - 1)); + + dcu_write32(®s->update_mode, DCU_UPDATE_MODE_READREG); + return 0; } From 7ce92a554a257d2f9ceee9ab855b878f01a5f88a Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 11 Apr 2017 11:12:12 +0530 Subject: [PATCH 4/9] video: fsl_dcu_fb: Fix DCU_MODE_BLEND_ITER setting DCU_LAYER_MAX_NUM is currently used for DCU_MODE_BLEND_ITER and it actually overflows the maximum value of BLEND_ITER for Vybrid and LS102XA. Fix this by using a default value of 2. Signed-off-by: Stefan Agner Signed-off-by: Sanchayan Maity --- drivers/video/fsl_dcu_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c index c6ed3c4..9fd9218 100644 --- a/drivers/video/fsl_dcu_fb.c +++ b/drivers/video/fsl_dcu_fb.c @@ -294,7 +294,7 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres, DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0)); dcu_write32(®s->mode, - DCU_MODE_BLEND_ITER(DCU_LAYER_MAX_NUM) | + DCU_MODE_BLEND_ITER(2) | DCU_MODE_RASTER_EN); dcu_write32(®s->threshold, From 7a2d533eec571ae815455048e8ef4986725c9f87 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 11 Apr 2017 11:12:13 +0530 Subject: [PATCH 5/9] video: fsl_dcu_fb: add additional modes for DCU Add common widescreen modes 800x480 and 1024x600. Signed-off-by: Stefan Agner Signed-off-by: Sanchayan Maity Reviewed-by: Alison Wang --- drivers/video/fsl_dcu_fb.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c index 9fd9218..01e4a40 100644 --- a/drivers/video/fsl_dcu_fb.c +++ b/drivers/video/fsl_dcu_fb.c @@ -104,7 +104,7 @@ static struct fb_videomode fsl_dcu_mode_480_272 = { /* * This setting is used for Siliconimage SiI9022A HDMI */ -static struct fb_videomode fsl_dcu_mode_640_480 = { +static struct fb_videomode fsl_dcu_cea_mode_640_480 = { .name = "640x480-60", .refresh = 60, .xres = 640, @@ -120,6 +120,54 @@ static struct fb_videomode fsl_dcu_mode_640_480 = { .vmode = FB_VMODE_NONINTERLACED, }; +static struct fb_videomode fsl_dcu_mode_640_480 = { + .name = "640x480-60", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 25175, + .left_margin = 40, + .right_margin = 24, + .upper_margin = 32, + .lower_margin = 11, + .hsync_len = 96, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_videomode fsl_dcu_mode_800_480 = { + .name = "800x480-60", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = 33260, + .left_margin = 216, + .right_margin = 40, + .upper_margin = 35, + .lower_margin = 10, + .hsync_len = 128, + .vsync_len = 2, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_videomode fsl_dcu_mode_1024_600 = { + .name = "1024x600-60", + .refresh = 60, + .xres = 1024, + .yres = 600, + .pixclock = 48000, + .left_margin = 104, + .right_margin = 43, + .upper_margin = 24, + .lower_margin = 20, + .hsync_len = 5, + .vsync_len = 5, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +}; + /* * DCU register map */ @@ -342,7 +390,16 @@ void *video_hw_init(void) fsl_dcu_mode_db = &fsl_dcu_mode_480_272; break; case RESOLUTION(640, 480): - fsl_dcu_mode_db = &fsl_dcu_mode_640_480; + if (!strncmp(options, "monitor=hdmi", 12)) + fsl_dcu_mode_db = &fsl_dcu_cea_mode_640_480; + else + fsl_dcu_mode_db = &fsl_dcu_mode_640_480; + break; + case RESOLUTION(800, 480): + fsl_dcu_mode_db = &fsl_dcu_mode_800_480; + break; + case RESOLUTION(1024, 600): + fsl_dcu_mode_db = &fsl_dcu_mode_1024_600; break; default: printf("unsupported resolution %ux%u\n", From 80b9c3bb80bfcb3959b7042efea272b259e9a995 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 11 Apr 2017 11:12:14 +0530 Subject: [PATCH 6/9] board: toradex: colibri_vf: Add DCU support for Colibri Vybrid The Vybrid SoC family has the same display controller unit (DCU) like the LS1021A SoC. This patch adds platform data, pinmux defines and clock control to enable the driver for Toradex Colibri Vybrid module. Signed-off-by: Stefan Agner Signed-off-by: Sanchayan Maity Reviewed-by: Stefano Babic --- arch/arm/include/asm/arch-vf610/crm_regs.h | 14 +++++ arch/arm/include/asm/arch-vf610/imx-regs.h | 2 + arch/arm/include/asm/arch-vf610/iomux-vf610.h | 31 +++++++++++ arch/arm/include/asm/imx-common/iomux-v3.h | 3 ++ board/toradex/colibri_vf/Makefile | 1 + board/toradex/colibri_vf/colibri_vf.c | 76 +++++++++++++++++++++------ board/toradex/colibri_vf/dcu.c | 38 ++++++++++++++ configs/colibri_vf_defconfig | 4 ++ include/configs/colibri_vf.h | 13 +++++ 9 files changed, 166 insertions(+), 16 deletions(-) create mode 100644 board/toradex/colibri_vf/dcu.c diff --git a/arch/arm/include/asm/arch-vf610/crm_regs.h b/arch/arm/include/asm/arch-vf610/crm_regs.h index a46e396..73b1dd2 100644 --- a/arch/arm/include/asm/arch-vf610/crm_regs.h +++ b/arch/arm/include/asm/arch-vf610/crm_regs.h @@ -9,6 +9,8 @@ #ifndef __ASSEMBLY__ +#include + /* Clock Controller Module (CCM) */ struct ccm_reg { u32 ccr; @@ -150,6 +152,9 @@ struct anadig_reg { #define CCM_CACRR_ARM_CLK_DIV_MASK 0x7 #define CCM_CACRR_ARM_CLK_DIV(v) ((v) & 0x7) +#define CCM_CSCMR1_DCU1_CLK_SEL (1 << 29) +#define CCM_CSCMR1_DCU0_CLK_SEL (1 << 28) + #define CCM_CSCMR1_QSPI0_CLK_SEL_OFFSET 22 #define CCM_CSCMR1_QSPI0_CLK_SEL_MASK (0x3 << 22) #define CCM_CSCMR1_QSPI0_CLK_SEL(v) (((v) & 0x3) << 22) @@ -174,6 +179,13 @@ struct anadig_reg { #define CCM_CSCDR2_ESDHC1_CLK_DIV_MASK (0xf << 20) #define CCM_CSCDR2_ESDHC1_CLK_DIV(v) (((v) & 0xf) << 20) +#define CCM_CSCDR3_DCU1_EN (1 << 23) +#define CCM_CSCDR3_DCU1_DIV_MASK (0x7 << 20) +#define CCM_CSCDR3_DCU1_DIV(v) (((v) & 0x7) << 20) +#define CCM_CSCDR3_DCU0_EN (1 << 19) +#define CCM_CSCDR3_DCU0_DIV_MASK (0x7 << 16) +#define CCM_CSCDR3_DCU0_DIV(v) (((v) & 0x7) << 16) + #define CCM_CSCDR3_NFC_PRE_DIV_OFFSET 13 #define CCM_CSCDR3_NFC_PRE_DIV_MASK (0x7 << 13) #define CCM_CSCDR3_NFC_PRE_DIV(v) (((v) & 0x7) << 13) @@ -193,6 +205,7 @@ struct anadig_reg { #define CCM_CCGR0_DSPI1_CTRL_MASK (0x3 << 26) #define CCM_CCGR1_USBC0_CTRL_MASK (0x3 << 8) #define CCM_CCGR1_PIT_CTRL_MASK (0x3 << 14) +#define CCM_CCGR1_TCON0_CTRL_MASK (0x3 << 26) #define CCM_CCGR1_WDOGA5_CTRL_MASK (0x3 << 28) #define CCM_CCGR2_QSPI0_CTRL_MASK (0x3 << 8) #define CCM_CCGR2_IOMUXC_CTRL_MASK (0x3 << 16) @@ -203,6 +216,7 @@ struct anadig_reg { #define CCM_CCGR2_PORTE_CTRL_MASK (0x3 << 26) #define CCM_CCGR3_ANADIG_CTRL_MASK 0x3 #define CCM_CCGR3_SCSC_CTRL_MASK (0x3 << 4) +#define CCM_CCGR3_DCU0_CTRL_MASK (0x3 << 16) #define CCM_CCGR4_WKUP_CTRL_MASK (0x3 << 20) #define CCM_CCGR4_CCM_CTRL_MASK (0x3 << 22) #define CCM_CCGR4_GPC_CTRL_MASK (0x3 << 24) diff --git a/arch/arm/include/asm/arch-vf610/imx-regs.h b/arch/arm/include/asm/arch-vf610/imx-regs.h index cac68ef..ca97462 100644 --- a/arch/arm/include/asm/arch-vf610/imx-regs.h +++ b/arch/arm/include/asm/arch-vf610/imx-regs.h @@ -69,6 +69,7 @@ #define USB_PHY0_BASE_ADDR (AIPS0_BASE_ADDR + 0x00050800) #define USB_PHY1_BASE_ADDR (AIPS0_BASE_ADDR + 0x00050C00) #define SCSC_BASE_ADDR (AIPS0_BASE_ADDR + 0x00052000) +#define DCU0_BASE_ADDR (AIPS0_BASE_ADDR + 0x00058000) #define ASRC_BASE_ADDR (AIPS0_BASE_ADDR + 0x00060000) #define SPDIF_BASE_ADDR (AIPS0_BASE_ADDR + 0x00061000) #define ESAI_BASE_ADDR (AIPS0_BASE_ADDR + 0x00062000) @@ -98,6 +99,7 @@ #define USBC1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00034000) #define ENET_BASE_ADDR (AIPS1_BASE_ADDR + 0x00050000) #define ENET1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00051000) +#define DCU1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00058000) #define NFC_BASE_ADDR (AIPS1_BASE_ADDR + 0x00060000) #define QSPI0_AMBA_BASE 0x20000000 diff --git a/arch/arm/include/asm/arch-vf610/iomux-vf610.h b/arch/arm/include/asm/arch-vf610/iomux-vf610.h index a140be0..5af071a 100644 --- a/arch/arm/include/asm/arch-vf610/iomux-vf610.h +++ b/arch/arm/include/asm/arch-vf610/iomux-vf610.h @@ -40,6 +40,8 @@ PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_HIGH) #define VF610_DSPI_SIN_PAD_CTRL (PAD_CTL_IBE_ENABLE | PAD_CTL_DSE_20ohm | \ PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_HIGH) +#define VF610_DCU_PAD_CTRL (PAD_CTL_SPEED_MED | PAD_CTL_SRE | \ + PAD_CTL_DSE_37ohm | PAD_CTL_OBE_ENABLE) enum { VF610_PAD_PTA6__RMII0_CLKIN = IOMUX_PAD(0x0000, 0x0000, 2, __NA_, 0, VF610_ENET_PAD_CTRL), @@ -166,6 +168,35 @@ enum { VF610_PAD_PTC28__NF_CLE = IOMUX_PAD(0x0194, 0x0194, 6, __NA_, 0, VF610_NFC_CN_PAD_CTRL), + VF610_PAD_PTE0__DCU0_HSYNC = IOMUX_PAD(0x01a4, 0x01a4, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE1__DCU0_VSYNC = IOMUX_PAD(0x01a8, 0x01a8, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE2__DCU0_PCLK = IOMUX_PAD(0x01ac, 0x01ac, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE4__DCU0_DE = IOMUX_PAD(0x01b4, 0x01b4, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE5__DCU0_R0 = IOMUX_PAD(0x01b8, 0x01b8, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE6__DCU0_R1 = IOMUX_PAD(0x01bc, 0x01bc, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE7__DCU0_R2 = IOMUX_PAD(0x01c0, 0x01c0, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE8__DCU0_R3 = IOMUX_PAD(0x01c4, 0x01c4, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE9__DCU0_R4 = IOMUX_PAD(0x01c8, 0x01c8, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE10__DCU0_R5 = IOMUX_PAD(0x01cc, 0x01cc, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE11__DCU0_R6 = IOMUX_PAD(0x01d0, 0x01d0, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE12__DCU0_R7 = IOMUX_PAD(0x01d4, 0x01d4, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE13__DCU0_G0 = IOMUX_PAD(0x01d8, 0x01d8, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE14__DCU0_G1 = IOMUX_PAD(0x01dc, 0x01dc, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE15__DCU0_G2 = IOMUX_PAD(0x01e0, 0x01e0, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE16__DCU0_G3 = IOMUX_PAD(0x01e4, 0x01e4, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE17__DCU0_G4 = IOMUX_PAD(0x01e8, 0x01e8, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE18__DCU0_G5 = IOMUX_PAD(0x01ec, 0x01ec, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE19__DCU0_G6 = IOMUX_PAD(0x01f0, 0x01f0, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE20__DCU0_G7 = IOMUX_PAD(0x01f4, 0x01f4, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE21__DCU0_B0 = IOMUX_PAD(0x01f8, 0x01f8, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE22__DCU0_B1 = IOMUX_PAD(0x01fc, 0x01fc, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE23__DCU0_B2 = IOMUX_PAD(0x0200, 0x0200, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE24__DCU0_B3 = IOMUX_PAD(0x0204, 0x0204, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE25__DCU0_B4 = IOMUX_PAD(0x0208, 0x0208, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE26__DCU0_B5 = IOMUX_PAD(0x020c, 0x020c, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE27__DCU0_B6 = IOMUX_PAD(0x0210, 0x0210, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_PTE28__DCU0_B7 = IOMUX_PAD(0x0214, 0x0214, 1, __NA_, 0, VF610_DCU_PAD_CTRL), + VF610_PAD_DDR_RESETB = IOMUX_PAD(0x021c, 0x021c, 0, __NA_, 0, VF610_DDR_PAD_CTRL), VF610_PAD_DDR_A15__DDR_A_15 = IOMUX_PAD(0x0220, 0x0220, 0, __NA_, 0, VF610_DDR_PAD_CTRL), VF610_PAD_DDR_A14__DDR_A_14 = IOMUX_PAD(0x0224, 0x0224, 0, __NA_, 0, VF610_DDR_PAD_CTRL), diff --git a/arch/arm/include/asm/imx-common/iomux-v3.h b/arch/arm/include/asm/imx-common/iomux-v3.h index 7587cbb..ba0ed43 100644 --- a/arch/arm/include/asm/imx-common/iomux-v3.h +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -165,7 +165,10 @@ typedef u64 iomux_v3_cfg_t; #define PAD_CTL_ODE (1 << 10) #define PAD_CTL_DSE_150ohm (1 << 6) +#define PAD_CTL_DSE_75ohm (2 << 6) #define PAD_CTL_DSE_50ohm (3 << 6) +#define PAD_CTL_DSE_37ohm (4 << 6) +#define PAD_CTL_DSE_30ohm (5 << 6) #define PAD_CTL_DSE_25ohm (6 << 6) #define PAD_CTL_DSE_20ohm (7 << 6) diff --git a/board/toradex/colibri_vf/Makefile b/board/toradex/colibri_vf/Makefile index c7e5134..4d6287f 100644 --- a/board/toradex/colibri_vf/Makefile +++ b/board/toradex/colibri_vf/Makefile @@ -5,3 +5,4 @@ # obj-y := colibri_vf.o +obj-$(CONFIG_VIDEO_FSL_DCU_FB) += dcu.o diff --git a/board/toradex/colibri_vf/colibri_vf.c b/board/toradex/colibri_vf/colibri_vf.c index 7b74eb7..46dd15b 100644 --- a/board/toradex/colibri_vf/colibri_vf.c +++ b/board/toradex/colibri_vf/colibri_vf.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -295,6 +296,49 @@ static void setup_iomux_gpio(void) } #endif +#ifdef CONFIG_VIDEO_FSL_DCU_FB +static void setup_iomux_fsl_dcu(void) +{ + static const iomux_v3_cfg_t dcu0_pads[] = { + VF610_PAD_PTE0__DCU0_HSYNC, + VF610_PAD_PTE1__DCU0_VSYNC, + VF610_PAD_PTE2__DCU0_PCLK, + VF610_PAD_PTE4__DCU0_DE, + VF610_PAD_PTE5__DCU0_R0, + VF610_PAD_PTE6__DCU0_R1, + VF610_PAD_PTE7__DCU0_R2, + VF610_PAD_PTE8__DCU0_R3, + VF610_PAD_PTE9__DCU0_R4, + VF610_PAD_PTE10__DCU0_R5, + VF610_PAD_PTE11__DCU0_R6, + VF610_PAD_PTE12__DCU0_R7, + VF610_PAD_PTE13__DCU0_G0, + VF610_PAD_PTE14__DCU0_G1, + VF610_PAD_PTE15__DCU0_G2, + VF610_PAD_PTE16__DCU0_G3, + VF610_PAD_PTE17__DCU0_G4, + VF610_PAD_PTE18__DCU0_G5, + VF610_PAD_PTE19__DCU0_G6, + VF610_PAD_PTE20__DCU0_G7, + VF610_PAD_PTE21__DCU0_B0, + VF610_PAD_PTE22__DCU0_B1, + VF610_PAD_PTE23__DCU0_B2, + VF610_PAD_PTE24__DCU0_B3, + VF610_PAD_PTE25__DCU0_B4, + VF610_PAD_PTE26__DCU0_B5, + VF610_PAD_PTE27__DCU0_B6, + VF610_PAD_PTE28__DCU0_B7, + }; + + imx_iomux_v3_setup_multiple_pads(dcu0_pads, ARRAY_SIZE(dcu0_pads)); +} + +static void setup_tcon(void) +{ + setbits_le32(TCON0_BASE_ADDR, (1 << 29)); +} +#endif + #ifdef CONFIG_FSL_ESDHC struct fsl_esdhc_cfg esdhc_cfg[1] = { {ESDHC1_BASE_ADDR}, @@ -431,6 +475,11 @@ static void clock_init(void) CCM_CSCDR3_NFC_PRE_DIV(3)); clrsetbits_le32(&ccm->cscmr2, CCM_REG_CTRL_MASK, CCM_CSCMR2_RMII_CLK_SEL(2)); + +#ifdef CONFIG_VIDEO_FSL_DCU_FB + setbits_le32(&ccm->ccgr1, CCM_CCGR1_TCON0_CTRL_MASK); + setbits_le32(&ccm->ccgr3, CCM_CCGR3_DCU0_CTRL_MASK); +#endif } static void mscm_init(void) @@ -470,6 +519,11 @@ int board_early_init_f(void) setup_iomux_dspi(); #endif +#ifdef CONFIG_VIDEO_FSL_DCU_FB + setup_tcon(); + setup_iomux_fsl_dcu(); +#endif + return 0; } @@ -478,22 +532,6 @@ int board_late_init(void) { struct src *src = (struct src *)SRC_BASE_ADDR; - /* Default memory arguments */ - if (!getenv("memargs")) { - switch (gd->ram_size) { - case 0x08000000: - /* 128 MB */ - setenv("memargs", "mem=128M"); - break; - case 0x10000000: - /* 256 MB */ - setenv("memargs", "mem=256M"); - break; - default: - printf("Failed detecting RAM size.\n"); - } - } - if (((src->sbmr2 & SRC_SBMR2_BMOD_MASK) >> SRC_SBMR2_BMOD_SHIFT) == SRC_SBMR2_BMOD_SERIAL) { printf("Serial Downloader recovery mode, disable autoboot\n"); @@ -541,6 +579,7 @@ int checkboard(void) #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) int ft_board_setup(void *blob, bd_t *bd) { + int ret = 0; #ifdef CONFIG_FDT_FIXUP_PARTITIONS static struct node_info nodes[] = { { "fsl,vf610-nfc", MTD_DEV_TYPE_NAND, }, /* NAND flash */ @@ -550,6 +589,11 @@ 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 + ret = fsl_dcu_fixedfb_setup(blob); + if (ret) + return ret; +#endif return ft_common_board_setup(blob, bd); } diff --git a/board/toradex/colibri_vf/dcu.c b/board/toradex/colibri_vf/dcu.c new file mode 100644 index 0000000..3fa6a76 --- /dev/null +++ b/board/toradex/colibri_vf/dcu.c @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Toradex AG + * + * FSL DCU platform driver + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include "div64.h" + +DECLARE_GLOBAL_DATA_PTR; + +unsigned int dcu_set_pixel_clock(unsigned int pixclock) +{ + struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; + unsigned long long div; + + clrbits_le32(&ccm->cscmr1, CCM_CSCMR1_DCU0_CLK_SEL); + clrsetbits_le32(&ccm->cscdr3, + CCM_CSCDR3_DCU0_DIV_MASK | CCM_CSCDR3_DCU0_EN, + CCM_CSCDR3_DCU0_DIV(0) | CCM_CSCDR3_DCU0_EN); + div = (unsigned long long)(PLL1_PFD2_FREQ / 1000); + do_div(div, pixclock); + + return div; +} + +int platform_dcu_init(unsigned int xres, unsigned int yres, + const char *port, + struct fb_videomode *dcu_fb_videomode) +{ + fsl_dcu_init(xres, yres, 32); + + return 0; +} diff --git a/configs/colibri_vf_defconfig b/configs/colibri_vf_defconfig index 0474abc..1f0f929 100644 --- a/configs/colibri_vf_defconfig +++ b/configs/colibri_vf_defconfig @@ -52,3 +52,7 @@ CONFIG_G_DNL_MANUFACTURER="Toradex" CONFIG_G_DNL_VENDOR_NUM=0x1b67 CONFIG_G_DNL_PRODUCT_NUM=0x4000 CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_VIDEO=y +CONFIG_VIDEO_FSL_DCU_FB=y +CONFIG_SYS_CONSOLE_FG_COL=0x00 +CONFIG_SYS_CONSOLE_BG_COL=0x00 diff --git a/include/configs/colibri_vf.h b/include/configs/colibri_vf.h index 73b43bd..5dc5ed0 100644 --- a/include/configs/colibri_vf.h +++ b/include/configs/colibri_vf.h @@ -25,6 +25,17 @@ #define CONFIG_MXC_OCOTP #endif +#ifdef CONFIG_VIDEO_FSL_DCU_FB +#define CONFIG_CMD_BMP +#define CONFIG_SPLASH_SCREEN_ALIGN +#define CONFIG_VIDEO_LOGO +#define CONFIG_VIDEO_BMP_LOGO +#define CONFIG_SYS_FSL_DCU_LE + +#define CONFIG_SYS_DCU_ADDR DCU0_BASE_ADDR +#define DCU_LAYER_MAX_NUM 64 +#endif + /* Size of malloc() pool */ #define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 2 * 1024 * 1024) @@ -130,6 +141,8 @@ "setupdate=run setsdupdate || run setusbupdate\0" \ "mtdparts=" MTDPARTS_DEFAULT "\0" \ "dfu_alt_info=" DFU_ALT_NAND_INFO "\0" \ + "video-mode=dcufb:640x480-16@60,monitor=lcd\0" \ + "splashpos=m,m\0" \ SD_BOOTCMD \ NFS_BOOTCMD \ UBI_BOOTCMD From 7927831e21a1ec2f44e0e0eb142ca24be807d202 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Tue, 11 Apr 2017 16:33:30 +0800 Subject: [PATCH 7/9] at91: video: Support driver-model for the HLCD driver Add driver-model support to this driver. Signed-off-by: Songjun Wu --- drivers/video/Kconfig | 6 + drivers/video/atmel_hlcdfb.c | 482 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 417 insertions(+), 71 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d1b017c..19e9745 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -371,6 +371,12 @@ config DISPLAY The devices provide a simple interface to start up the display, read display information and enable it. +config ATMEL_HLCD + bool "Enable ATMEL video support using HLCDC" + depends on DM_VIDEO + help + HLCDC supports video output to an attached LCD panel. + config VIDEO_BROADWELL_IGD bool "Enable Intel Broadwell integrated graphics device" depends on X86 diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c index 960b474..59b9c45 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -10,13 +10,22 @@ #include #include #include +#include +#include +#include #include +#include +#include #include #if defined(CONFIG_LCD_LOGO) #include #endif +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_DM_VIDEO + /* configurable parameters */ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 #define ATMEL_LCDC_DMA_BURST_LEN 8 @@ -26,19 +35,16 @@ #define ATMEL_LCDC_FIFO_SIZE 512 -#define lcdc_readl(reg) __raw_readl((reg)) -#define lcdc_writel(reg, val) __raw_writel((val), (reg)) - /* * the CLUT register map as following * RCLUT(24 ~ 16), GCLUT(15 ~ 8), BCLUT(7 ~ 0) */ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) { - lcdc_writel(((red << LCDC_BASECLUT_RCLUT_Pos) & LCDC_BASECLUT_RCLUT_Msk) - | ((green << LCDC_BASECLUT_GCLUT_Pos) & LCDC_BASECLUT_GCLUT_Msk) - | ((blue << LCDC_BASECLUT_BCLUT_Pos) & LCDC_BASECLUT_BCLUT_Msk), - panel_info.mmio + ATMEL_LCDC_LUT(regno)); + writel(panel_info.mmio + ATMEL_LCDC_LUT(regno), + ((red << LCDC_BASECLUT_RCLUT_Pos) & LCDC_BASECLUT_RCLUT_Msk) + | ((green << LCDC_BASECLUT_GCLUT_Pos) & LCDC_BASECLUT_GCLUT_Msk) + | ((blue << LCDC_BASECLUT_BCLUT_Pos) & LCDC_BASECLUT_BCLUT_Msk)); } ushort *configuration_get_cmap(void) @@ -55,6 +61,7 @@ void lcd_ctrl_init(void *lcdbase) unsigned long value; struct lcd_dma_desc *desc; struct atmel_hlcd_regs *regs; + int ret; if (!has_lcdc()) return; /* No lcdc */ @@ -62,21 +69,29 @@ void lcd_ctrl_init(void *lcdbase) regs = (struct atmel_hlcd_regs *)panel_info.mmio; /* Disable DISP signal */ - lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_DISPDIS); - while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS)) - udelay(1); + writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable synchronization */ - lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_SYNCDIS); - while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS)) - udelay(1); + writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable pixel clock */ - lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_CLKDIS); - while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS)) - udelay(1); + writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Disable PWM */ - lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_PWMDIS); - while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) - udelay(1); + writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Set pixel clock */ value = get_lcdc_clk_rate(0) / panel_info.vl_clk; @@ -85,23 +100,23 @@ void lcd_ctrl_init(void *lcdbase) if (value < 1) { /* Using system clock as pixel clock */ - lcdc_writel(®s->lcdc_lcdcfg0, - LCDC_LCDCFG0_CLKDIV(0) - | LCDC_LCDCFG0_CGDISHCR - | LCDC_LCDCFG0_CGDISHEO - | LCDC_LCDCFG0_CGDISOVR1 - | LCDC_LCDCFG0_CGDISBASE - | panel_info.vl_clk_pol - | LCDC_LCDCFG0_CLKSEL); + writel(LCDC_LCDCFG0_CLKDIV(0) + | LCDC_LCDCFG0_CGDISHCR + | LCDC_LCDCFG0_CGDISHEO + | LCDC_LCDCFG0_CGDISOVR1 + | LCDC_LCDCFG0_CGDISBASE + | panel_info.vl_clk_pol + | LCDC_LCDCFG0_CLKSEL, + ®s->lcdc_lcdcfg0); } else { - lcdc_writel(®s->lcdc_lcdcfg0, - LCDC_LCDCFG0_CLKDIV(value - 2) - | LCDC_LCDCFG0_CGDISHCR - | LCDC_LCDCFG0_CGDISHEO - | LCDC_LCDCFG0_CGDISOVR1 - | LCDC_LCDCFG0_CGDISBASE - | panel_info.vl_clk_pol); + writel(LCDC_LCDCFG0_CLKDIV(value - 2) + | LCDC_LCDCFG0_CGDISHCR + | LCDC_LCDCFG0_CGDISHEO + | LCDC_LCDCFG0_CGDISOVR1 + | LCDC_LCDCFG0_CGDISBASE + | panel_info.vl_clk_pol, + ®s->lcdc_lcdcfg0); } /* Initialize control register 5 */ @@ -134,50 +149,50 @@ void lcd_ctrl_init(void *lcdbase) value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME); value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); - lcdc_writel(®s->lcdc_lcdcfg5, value); + writel(value, ®s->lcdc_lcdcfg5); /* Vertical & Horizontal Timing */ value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1); value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1); - lcdc_writel(®s->lcdc_lcdcfg1, value); + writel(value, ®s->lcdc_lcdcfg1); value = LCDC_LCDCFG2_VBPW(panel_info.vl_upper_margin); value |= LCDC_LCDCFG2_VFPW(panel_info.vl_lower_margin - 1); - lcdc_writel(®s->lcdc_lcdcfg2, value); + writel(value, ®s->lcdc_lcdcfg2); value = LCDC_LCDCFG3_HBPW(panel_info.vl_left_margin - 1); value |= LCDC_LCDCFG3_HFPW(panel_info.vl_right_margin - 1); - lcdc_writel(®s->lcdc_lcdcfg3, value); + writel(value, ®s->lcdc_lcdcfg3); /* Display size */ value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1); value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1); - lcdc_writel(®s->lcdc_lcdcfg4, value); + writel(value, ®s->lcdc_lcdcfg4); - lcdc_writel(®s->lcdc_basecfg0, - LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO); + writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO, + ®s->lcdc_basecfg0); switch (NBITS(panel_info.vl_bpix)) { case 16: - lcdc_writel(®s->lcdc_basecfg1, - LCDC_BASECFG1_RGBMODE_16BPP_RGB_565); + writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565, + ®s->lcdc_basecfg1); break; case 32: - lcdc_writel(®s->lcdc_basecfg1, - LCDC_BASECFG1_RGBMODE_24BPP_RGB_888); + writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888, + ®s->lcdc_basecfg1); break; default: BUG(); break; } - lcdc_writel(®s->lcdc_basecfg2, LCDC_BASECFG2_XSTRIDE(0)); - lcdc_writel(®s->lcdc_basecfg3, 0); - lcdc_writel(®s->lcdc_basecfg4, LCDC_BASECFG4_DMA); + writel(LCDC_BASECFG2_XSTRIDE(0), ®s->lcdc_basecfg2); + writel(0, ®s->lcdc_basecfg3); + writel(LCDC_BASECFG4_DMA, ®s->lcdc_basecfg4); /* Disable all interrupts */ - lcdc_writel(®s->lcdc_lcdidr, ~0UL); - lcdc_writel(®s->lcdc_baseidr, ~0UL); + writel(~0UL, ®s->lcdc_lcdidr); + writel(~0UL, ®s->lcdc_baseidr); /* Setup the DMA descriptor, this descriptor will loop to itself */ desc = (struct lcd_dma_desc *)(lcdbase - 16); @@ -191,30 +206,355 @@ void lcd_ctrl_init(void *lcdbase) /* Flush the DMA descriptor if we enabled dcache */ flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); - lcdc_writel(®s->lcdc_baseaddr, desc->address); - lcdc_writel(®s->lcdc_basectrl, desc->control); - lcdc_writel(®s->lcdc_basenext, desc->next); - lcdc_writel(®s->lcdc_basecher, LCDC_BASECHER_CHEN | - LCDC_BASECHER_UPDATEEN); + writel(desc->address, ®s->lcdc_baseaddr); + writel(desc->control, ®s->lcdc_basectrl); + writel(desc->next, ®s->lcdc_basenext); + writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN, + ®s->lcdc_basecher); /* Enable LCD */ - value = lcdc_readl(®s->lcdc_lcden); - lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_CLKEN); - while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS)) - udelay(1); - value = lcdc_readl(®s->lcdc_lcden); - lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_SYNCEN); - while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS)) - udelay(1); - value = lcdc_readl(®s->lcdc_lcden); - lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_DISPEN); - while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS)) - udelay(1); - value = lcdc_readl(®s->lcdc_lcden); - lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_PWMEN); - while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) - udelay(1); + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); /* Enable flushing if we enabled dcache */ lcd_set_flush_dcache(1); } + +#else + +enum { + LCD_MAX_WIDTH = 1024, + LCD_MAX_HEIGHT = 768, + LCD_MAX_LOG2_BPP = VIDEO_BPP16, +}; + +struct atmel_hlcdc_priv { + struct atmel_hlcd_regs *regs; + struct display_timing timing; + unsigned int vl_bpix; + unsigned int output_mode; + unsigned int guard_time; + ulong clk_rate; +}; + +static int at91_hlcdc_enable_clk(struct udevice *dev) +{ + struct atmel_hlcdc_priv *priv = dev_get_priv(dev); + struct clk clk; + ulong clk_rate; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return -EINVAL; + + ret = clk_enable(&clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(&clk); + if (!clk_rate) { + clk_disable(&clk); + return -ENODEV; + } + + priv->clk_rate = clk_rate; + + clk_free(&clk); + + return 0; +} + +static void atmel_hlcdc_init(struct udevice *dev) +{ + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); + struct atmel_hlcdc_priv *priv = dev_get_priv(dev); + struct atmel_hlcd_regs *regs = priv->regs; + struct display_timing *timing = &priv->timing; + struct lcd_dma_desc *desc; + unsigned long value, vl_clk_pol; + int ret; + + /* Disable DISP signal */ + writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + /* Disable synchronization */ + writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + /* Disable pixel clock */ + writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + /* Disable PWM */ + writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + false, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + + /* Set pixel clock */ + value = priv->clk_rate / timing->pixelclock.typ; + if (priv->clk_rate % timing->pixelclock.typ) + value++; + + vl_clk_pol = 0; + if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) + vl_clk_pol = LCDC_LCDCFG0_CLKPOL; + + if (value < 1) { + /* Using system clock as pixel clock */ + writel(LCDC_LCDCFG0_CLKDIV(0) + | LCDC_LCDCFG0_CGDISHCR + | LCDC_LCDCFG0_CGDISHEO + | LCDC_LCDCFG0_CGDISOVR1 + | LCDC_LCDCFG0_CGDISBASE + | vl_clk_pol + | LCDC_LCDCFG0_CLKSEL, + ®s->lcdc_lcdcfg0); + + } else { + writel(LCDC_LCDCFG0_CLKDIV(value - 2) + | LCDC_LCDCFG0_CGDISHCR + | LCDC_LCDCFG0_CGDISHEO + | LCDC_LCDCFG0_CGDISOVR1 + | LCDC_LCDCFG0_CGDISBASE + | vl_clk_pol, + ®s->lcdc_lcdcfg0); + } + + /* Initialize control register 5 */ + value = 0; + + if (!(timing->flags & DISPLAY_FLAGS_HSYNC_HIGH)) + value |= LCDC_LCDCFG5_HSPOL; + if (!(timing->flags & DISPLAY_FLAGS_VSYNC_HIGH)) + value |= LCDC_LCDCFG5_VSPOL; + + switch (priv->output_mode) { + case 12: + value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; + break; + case 16: + value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; + break; + case 18: + value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; + break; + case 24: + value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; + break; + default: + BUG(); + break; + } + + value |= LCDC_LCDCFG5_GUARDTIME(priv->guard_time); + value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); + writel(value, ®s->lcdc_lcdcfg5); + + /* Vertical & Horizontal Timing */ + value = LCDC_LCDCFG1_VSPW(timing->vsync_len.typ - 1); + value |= LCDC_LCDCFG1_HSPW(timing->hsync_len.typ - 1); + writel(value, ®s->lcdc_lcdcfg1); + + value = LCDC_LCDCFG2_VBPW(timing->vback_porch.typ); + value |= LCDC_LCDCFG2_VFPW(timing->vfront_porch.typ - 1); + writel(value, ®s->lcdc_lcdcfg2); + + value = LCDC_LCDCFG3_HBPW(timing->hback_porch.typ - 1); + value |= LCDC_LCDCFG3_HFPW(timing->hfront_porch.typ - 1); + writel(value, ®s->lcdc_lcdcfg3); + + /* Display size */ + value = LCDC_LCDCFG4_RPF(timing->vactive.typ - 1); + value |= LCDC_LCDCFG4_PPL(timing->hactive.typ - 1); + writel(value, ®s->lcdc_lcdcfg4); + + writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO, + ®s->lcdc_basecfg0); + + switch (VNBITS(priv->vl_bpix)) { + case 16: + writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565, + ®s->lcdc_basecfg1); + break; + case 32: + writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888, + ®s->lcdc_basecfg1); + break; + default: + BUG(); + break; + } + + writel(LCDC_BASECFG2_XSTRIDE(0), ®s->lcdc_basecfg2); + writel(0, ®s->lcdc_basecfg3); + writel(LCDC_BASECFG4_DMA, ®s->lcdc_basecfg4); + + /* Disable all interrupts */ + writel(~0UL, ®s->lcdc_lcdidr); + writel(~0UL, ®s->lcdc_baseidr); + + /* Setup the DMA descriptor, this descriptor will loop to itself */ + desc = (struct lcd_dma_desc *)(uc_plat->base - 16); + + desc->address = (u32)uc_plat->base; + + /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ + desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN + | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; + desc->next = (u32)desc; + + /* Flush the DMA descriptor if we enabled dcache */ + flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); + + writel(desc->address, ®s->lcdc_baseaddr); + writel(desc->control, ®s->lcdc_basectrl); + writel(desc->next, ®s->lcdc_basenext); + writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN, + ®s->lcdc_basecher); + + /* Enable LCD */ + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); + value = readl(®s->lcdc_lcden); + writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); + ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, + true, 1000, false); + if (ret) + printf("%s: %d: Timeout!\n", __func__, __LINE__); +} + +static int atmel_hlcdc_probe(struct udevice *dev) +{ + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct atmel_hlcdc_priv *priv = dev_get_priv(dev); + int ret; + + ret = at91_hlcdc_enable_clk(dev); + if (ret) + return ret; + + atmel_hlcdc_init(dev); + + uc_priv->xsize = priv->timing.hactive.typ; + uc_priv->ysize = priv->timing.vactive.typ; + uc_priv->bpix = priv->vl_bpix; + + /* Enable flushing if we enabled dcache */ + video_set_flush_dcache(dev, true); + + return 0; +} + +static int atmel_hlcdc_ofdata_to_platdata(struct udevice *dev) +{ + struct atmel_hlcdc_priv *priv = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + + priv->regs = (struct atmel_hlcd_regs *)dev_get_addr(dev); + if (!priv->regs) { + debug("%s: No display controller address\n", __func__); + return -EINVAL; + } + + if (fdtdec_decode_display_timing(blob, dev->of_offset, + 0, &priv->timing)) { + debug("%s: Failed to decode display timing\n", __func__); + return -EINVAL; + } + + if (priv->timing.hactive.typ > LCD_MAX_WIDTH) + priv->timing.hactive.typ = LCD_MAX_WIDTH; + + if (priv->timing.vactive.typ > LCD_MAX_HEIGHT) + priv->timing.vactive.typ = LCD_MAX_HEIGHT; + + priv->vl_bpix = fdtdec_get_int(blob, node, "atmel,vl-bpix", 0); + if (!priv->vl_bpix) { + debug("%s: Failed to get bits per pixel\n", __func__); + return -EINVAL; + } + + priv->output_mode = fdtdec_get_int(blob, node, "atmel,output-mode", 24); + priv->guard_time = fdtdec_get_int(blob, node, "atmel,guard-time", 1); + + return 0; +} + +static int atmel_hlcdc_bind(struct udevice *dev) +{ + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); + + uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * + (1 << LCD_MAX_LOG2_BPP) / 8; + + debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); + + return 0; +} + +static const struct udevice_id atmel_hlcdc_ids[] = { + { .compatible = "atmel,sama5d2-hlcdc" }, + { .compatible = "atmel,at91sam9x5-hlcdc" }, + { } +}; + +U_BOOT_DRIVER(atmel_hlcdfb) = { + .name = "atmel_hlcdfb", + .id = UCLASS_VIDEO, + .of_match = atmel_hlcdc_ids, + .bind = atmel_hlcdc_bind, + .probe = atmel_hlcdc_probe, + .ofdata_to_platdata = atmel_hlcdc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct atmel_hlcdc_priv), +}; + +#endif From e6a419c5f772f3379fdf834352190a90358022ab Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Tue, 11 Apr 2017 16:33:31 +0800 Subject: [PATCH 8/9] at91: video: DT binding for HLCDC driver DT binding documentation for atmel HLCDC driver. Signed-off-by: Songjun Wu --- doc/device-tree-bindings/video/atmel-hlcdc.txt | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 doc/device-tree-bindings/video/atmel-hlcdc.txt diff --git a/doc/device-tree-bindings/video/atmel-hlcdc.txt b/doc/device-tree-bindings/video/atmel-hlcdc.txt new file mode 100644 index 0000000..b378cbf --- /dev/null +++ b/doc/device-tree-bindings/video/atmel-hlcdc.txt @@ -0,0 +1,42 @@ +Atmel HLCDC Framebuffer +----------------------------------------------------- +Required properties: +- compatible : + "atmel,sama5d2-hlcdc", "atmel,at91sam9x5-hlcdc". +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: phandles to input clocks. +- atmel,vl-bpix: Bits per pixel. +- atmel,output-mode: LCD Controller Output Mode, + The unit is bits per pixel, there are four values, + <12>, <16>, <18>, <24>, the default value is <24>. +- atmel,guard-time: lcd guard time (Delay in frame periods). +- display-timings: please refer the displaymode.txt. + +Example: +hlcdc: hlcdc@f0000000 { + u-boot,dm-pre-reloc; + compatible = "atmel,sama5d2-hlcdc"; + reg = <0xf0000000 0x2000>; + clocks = <&lcdc_clk>; + atmel,vl-bpix = <4>; + atmel,output-mode = <24>; + atmel,guard-time = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_pwm &pinctrl_lcd_rgb666>; + status = "okay"; + + display-timings { + 480x272 { + clock-frequency = <9000000>; + hactive = <480>; + vactive = <272>; + hsync-len = <41>; + hfront-porch = <2>; + hback-porch = <2>; + vfront-porch = <2>; + vback-porch = <2>; + vsync-len = <11>; + }; + }; +}; From 7682736c891d2b6f0cce167f4ecd55d2df0f562f Mon Sep 17 00:00:00 2001 From: "eric.gao@rock-chips.com" Date: Mon, 10 Apr 2017 10:02:20 +0800 Subject: [PATCH 9/9] video: Fix crash when scroll screen After enabling log printing to lcd, when the screen starts scrolling, system crashes. Log is shown as bellow: "Synchronous Abort" handler, esr 0x96000045 "Synchronous Abort" handler, esr 0x96000045 Checking the source code, we found that the variable "pixels" gets a wrong value: int pixels = VIDEO_FONT_HEIGHT * vid_priv->line_length; "pixels" here means the value of pixels for a character, rather than the bytes for a character. So the variable "pixels" is 4 times bigger than it's exact value, which will cause the memory overflow when the cpu runs the following code: for (i = 0; i < pixels; i++) *dst++ = clr; <<---- Signed-off-by: Eric Gao --- drivers/video/console_normal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 89a55dd..b627d48 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -18,7 +18,7 @@ static int console_normal_set_row(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); void *line; - int pixels = VIDEO_FONT_HEIGHT * vid_priv->line_length; + int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize; int i; line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * vid_priv->line_length;