at91: video: add driver for Atmel HLCD controller
Subsystems (2)
v2 cover at91: video: add driver for Atmel HLCD controller
The i2c driver includes two parts.
1) Driver code to implement the HLCD function.
2) Device tree binding documentation, it describes how to add the HLCD in device tree.
Changes in v2:
- Due to the peripheral clock driver improvement, remove the unneccessary clock calling.
Songjun Wu (2):
at91: video: Support driver-model for the HLCD driver
at91: video: DT binding for HLCDC driver
board/atmel/at91sam9n12ek/at91sam9n12ek.c | 2 + board/atmel/at91sam9x5ek/at91sam9x5ek.c | 2 + board/atmel/sama5d2_xplained/sama5d2_xplained.c | 2 + board/atmel/sama5d3xek/sama5d3xek.c | 2 + board/atmel/sama5d4_xplained/sama5d4_xplained.c | 2 + board/atmel/sama5d4ek/sama5d4ek.c | 2 + doc/device-tree-bindings/video/atme-hlcdc.txt | 38 +++ drivers/video/Kconfig | 9 + drivers/video/atmel_hlcdfb.c | 314 +++++++++++++++++++++++- include/configs/at91sam9n12ek.h | 4 + include/configs/at91sam9x5ek.h | 4 + include/configs/ma5d4evk.h | 4 + include/configs/sama5d2_xplained.h | 4 + include/configs/sama5d3xek.h | 4 + include/configs/sama5d4_xplained.h | 4 + include/configs/sama5d4ek.h | 4 + 16 files changed, 398 insertions(+), 3 deletions(-) create mode 100644 doc/device-tree-bindings/video/atme-hlcdc.txt
Signature · 1 line
2.11.0
PATCH v2 1/2 at91: video: Support driver-model for the HLCD driver
Add driver-model support to this driver.
---
Changes in v2:
- Due to the peripheral clock driver improvement, remove the unneccessary clock calling.
board/atmel/at91sam9n12ek/at91sam9n12ek.c | 2 + board/atmel/at91sam9x5ek/at91sam9x5ek.c | 2 + board/atmel/sama5d2_xplained/sama5d2_xplained.c | 2 + board/atmel/sama5d3xek/sama5d3xek.c | 2 + board/atmel/sama5d4_xplained/sama5d4_xplained.c | 2 + board/atmel/sama5d4ek/sama5d4ek.c | 2 + drivers/video/Kconfig | 9 + drivers/video/atmel_hlcdfb.c | 314 +++++++++++++++++++++++- include/configs/at91sam9n12ek.h | 4 + include/configs/at91sam9x5ek.h | 4 + include/configs/ma5d4evk.h | 4 + include/configs/sama5d2_xplained.h | 4 + include/configs/sama5d3xek.h | 4 + include/configs/sama5d4_xplained.h | 4 + include/configs/sama5d4ek.h | 4 + 15 files changed, 360 insertions(+), 3 deletions(-)
board/atmel/at91sam9n12ek/at91sam9n12ek.c +2 -0
@@ -79,6 +79,7 @@ static void at91sam9n12ek_nand_hw_init(void)#endif #ifdef CONFIG_LCD +#ifndef CONFIG_DM_VIDEO vidinfo_t panel_info = { .vl_col =480 , .vl_row = 272,
@@ -104,6 +105,7 @@ void lcd_disable(void) {at91_set_pio_output (AT91_PIO_PORTC ,25 ,1 );/* power down */ } +#endif #ifdef CONFIG_LCD_INFO void lcd_show_board_info (void )
board/atmel/at91sam9x5ek/at91sam9x5ek.c +2 -0
@@ -108,6 +108,7 @@ int board_eth_init(bd_t *bis) }#ifdef CONFIG_LCD +#ifndef CONFIG_DM_VIDEO vidinfo_t panel_info = { .vl_col =800 , .vl_row = 480,
@@ -136,6 +137,7 @@ void lcd_disable(void)if (has_lcdc ()) at91_set_a_periph(AT91_PIO_PORTC, 29, 0); /* power down */ } +#endif static void at91sam9x5ek_lcd_hw_init (void ) {
board/atmel/sama5d2_xplained/sama5d2_xplained.c +2 -0
@@ -34,6 +34,7 @@ static void board_usb_hw_init(void) }#ifdef CONFIG_LCD +#ifndef CONFIG_DM_VIDEO vidinfo_t panel_info = { .vl_col =480 , .vl_row = 272,
@@ -57,6 +58,7 @@ unsigned int has_lcdc(void) {return 1 ; } +#endif static void board_lcd_hw_init (void ) {
board/atmel/sama5d3xek/sama5d3xek.c +2 -0
@@ -142,6 +142,7 @@ static void sama5d3xek_mci_hw_init(void)#endif #ifdef CONFIG_LCD +#ifndef CONFIG_DM_VIDEO vidinfo_t panel_info = { .vl_col =800 , .vl_row = 480,
@@ -164,6 +165,7 @@ void lcd_enable(void)void lcd_disable (void ) { } +#endif static void sama5d3xek_lcd_hw_init (void ) {
board/atmel/sama5d4_xplained/sama5d4_xplained.c +2 -0
@@ -108,6 +108,7 @@ static void sama5d4_xplained_usb_hw_init(void)#endif #ifdef CONFIG_LCD +#ifndef CONFIG_DM_VIDEO vidinfo_t panel_info = { .vl_col =480 , .vl_row = 272,
@@ -131,6 +132,7 @@ unsigned int has_lcdc(void) {return 1 ; } +#endif static void sama5d4_xplained_lcd_hw_init (void ) {
board/atmel/sama5d4ek/sama5d4ek.c +2 -0
@@ -109,6 +109,7 @@ static void sama5d4ek_usb_hw_init(void)#endif #ifdef CONFIG_LCD +#ifndef CONFIG_DM_VIDEO vidinfo_t panel_info = { .vl_col =800 , .vl_row = 480,
@@ -132,6 +133,7 @@ unsigned int has_lcdc(void) {return 1 ; } +#endif static void sama5d4ek_lcd_hw_init (void ) {
drivers/video/Kconfig +9 -0
@@ -371,6 +371,15 @@ 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 as well as + other options such as HDMI. At present only LCD is supported by + U-Boot. This option enables this support which can be used on + devices which have an LCD display connected. + config VIDEO_BROADWELL_IGD bool "Enable Intel Broadwell integrated graphics device" depends on X86
drivers/video/atmel_hlcdfb.c +311 -3
336 lines not on this page · raw message
include/configs/at91sam9n12ek.h +4 -0
@@ -44,7 +44,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD +#endif +#define CONFIG_ATMEL_LCD_RGB565
include/configs/at91sam9x5ek.h +4 -0
@@ -40,7 +40,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD +#endif +#define CONFIG_ATMEL_LCD_RGB565
include/configs/ma5d4evk.h +4 -0
@@ -77,9 +77,13 @@#define CONFIG_BMP_32BPP #define LCD_BPP LCD_COLOR16#define LCD_OUTPUT_BPP 24 + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD #endif +#endif +/* * SD/MMC */
include/configs/sama5d2_xplained.h +4 -0
@@ -62,7 +62,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD +#endif +#define CONFIG_ATMEL_LCD_RGB565 #endif
include/configs/sama5d3xek.h +4 -0
@@ -40,7 +40,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD +#endif +#define CONFIG_ATMEL_LCD_RGB565 /* board specific (not enough SRAM) */
include/configs/sama5d4_xplained.h +4 -0
@@ -92,7 +92,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD +#endif +#define CONFIG_ATMEL_LCD_RGB565 #endif
include/configs/sama5d4ek.h +4 -0
@@ -91,7 +91,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD +#endif +#define CONFIG_ATMEL_LCD_RGB565 #ifdef CONFIG_SYS_USE_SERIALFLASH
Signature · 1 line
2.11.0
PATCH v2 1/2 at91: video: Support driver-model for the HLCD driver
Quoted 9 lines · Songjun Wu
Add driver-model support to this driver.
Signed-off-by Songjun Wu <[email protected]>---
Changes in v2:
- Due to the peripheral clock driver improvement, remove the unneccessary clock calling.
Quoted 8 lines
board/atmel/at91sam9n12ek/at91sam9n12ek.c | 2 + board/atmel/at91sam9x5ek/at91sam9x5ek.c | 2 + board/atmel/sama5d2_xplained/sama5d2_xplained.c | 2 + board/atmel/sama5d3xek/sama5d3xek.c | 2 + board/atmel/sama5d4_xplained/sama5d4_xplained.c | 2 + board/atmel/sama5d4ek/sama5d4ek.c | 2 + drivers/video/Kconfig | 9 + drivers/video/atmel_hlcdfb.c | 314 +++++++++++++++++++++++-
Split the driver from board changes.
Quoted 8 lines
include/configs/at91sam9n12ek.h | 4 + include/configs/at91sam9x5ek.h | 4 + include/configs/ma5d4evk.h | 4 + include/configs/sama5d2_xplained.h | 4 + include/configs/sama5d3xek.h | 4 + include/configs/sama5d4_xplained.h | 4 + include/configs/sama5d4ek.h | 4 + 15 files changed, 360 insertions(+), 3 deletions(-)
[...]
Quoted 13 lines
drivers/video/atmel_hlcdfb.c +4
-0@@ -10,13 +10,24 @@#include <asm/io.h> #include <asm/arch/gpio.h> #include <asm/arch/clk.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> #include <lcd.h> +#include <video.h>
drivers/video/atmel_hlcdfb.c line 27
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +4
-0#include <atmel_hlcdc.h> #if defined(CONFIG_LCD_LOGO )#include <bmp_logo.h> #endif +DECLARE_GLOBAL_DATA_PTR ; + +#define lcdc_readl (reg) __raw_readl((reg)) +#define lcdc_writel (reg, val) __raw_writel((val), (reg))
Really ? Do we REALLY need more new accessors ? Just use readl/writel ...
Quoted 44 lines
drivers/video/atmel_hlcdfb.c +27
-3+#ifndef CONFIG_DM_VIDEO +/* configurable parameters */ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8#define ATMEL_LCDC_DMA_BURST_LEN 8@@ -26,9 +37,6 @@#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) @@ -218,3 +226,303 @@ void lcd_ctrl_init(void *lcdbase)/* 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 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);
drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 263
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+if (ret) +return -EINVAL ; + + ret =clk_enable (&clk); +if (ret) +return ret; + + clk_rate =clk_get_rate (&clk); +if (!clk_rate) +return -ENODEV ;
Clock are still enabled if you fail here ...
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+ 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);
drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 284
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+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; + +/* Disable DISP signal */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_DISPDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_DISPSTS )) +udelay (1 );
wait_for_bit(), fix globally ... and don't use unbounded loops ...
Quoted 13 lines
drivers/video/atmel_hlcdfb.c +13
-0+/* Disable synchronization */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_SYNCDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_LCDSTS )) +udelay (1 ); +/* Disable pixel clock */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_CLKDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_CLKSTS )) +udelay (1 ); +/* Disable PWM */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_PWMDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_PWMSTS )) +udelay (1 ); +
drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 307
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+/* 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 ) {
I guess I'd just introduce a variable and ORR it with either CLKSEL or whatever bits based on the value to reduce this lengthy condition here. ie u32 foo = LCDC_BAR | LCDC_BAZ;
if (value < 1)
foo |= LCDC_QUUX;
else
...
writel(...);
Quoted 19 lines
drivers/video/atmel_hlcdfb.c +19
-0+/* 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 + | vl_clk_pol + |LCDC_LCDCFG0_CLKSEL ); + + }else { +lcdc_writel (®s->lcdc_lcdcfg0, +LCDC_LCDCFG0_CLKDIV (value -2 ) + |LCDC_LCDCFG0_CGDISHCR + |LCDC_LCDCFG0_CGDISHEO + |LCDC_LCDCFG0_CGDISOVR1 + |LCDC_LCDCFG0_CGDISBASE + | vl_clk_pol); + }
drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 336
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+ +/* 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 ; + +#ifndef LCD_OUTPUT_BPP
Just make sure that's always defined . If possible, get this from DT.
Quoted 83 lines
drivers/video/atmel_hlcdfb.c +83
-0+/* Output is 24bpp */ + value |=LCDC_LCDCFG5_MODE_OUTPUT_24BPP ; +#else +switch (LCD_OUTPUT_BPP ) { +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 ; + } +#endif + + value |=LCDC_LCDCFG5_GUARDTIME (priv->guard_time); + value |= (LCDC_LCDCFG5_DISPDLY |LCDC_LCDCFG5_VSPDLYS ); +lcdc_writel (®s->lcdc_lcdcfg5, value); + +/* Vertical & Horizontal Timing */ + value =LCDC_LCDCFG1_VSPW (timing->vsync_len.typ -1 ); + value |=LCDC_LCDCFG1_HSPW (timing->hsync_len.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg1, value); + + value =LCDC_LCDCFG2_VBPW (timing->vback_porch.typ); + value |=LCDC_LCDCFG2_VFPW (timing->vfront_porch.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg2, value); + + value =LCDC_LCDCFG3_HBPW (timing->hback_porch.typ -1 ); + value |=LCDC_LCDCFG3_HFPW (timing->hfront_porch.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg3, value); + +/* Display size */ + value =LCDC_LCDCFG4_RPF (timing->vactive.typ -1 ); + value |=LCDC_LCDCFG4_PPL (timing->hactive.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg4, value); + +lcdc_writel (®s->lcdc_basecfg0, +LCDC_BASECFG0_BLEN_AHB_INCR4 |LCDC_BASECFG0_DLBO ); + +switch (VNBITS (priv->vl_bpix)) { +case 16 : +lcdc_writel (®s->lcdc_basecfg1, +LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 ); +break ; +case 32 : +lcdc_writel (®s->lcdc_basecfg1, +LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 ); +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 ); + +/* Disable all interrupts */ +lcdc_writel (®s->lcdc_lcdidr, ~0UL ); +lcdc_writel (®s->lcdc_baseidr, ~0UL ); + +/* 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)); + +lcdc_writel (®s->lcdc_baseaddr, desc->address);
drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 429
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+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 ); + +/* 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 );
wait_for_bit() ...
Quoted 99 lines
drivers/video/atmel_hlcdfb.c +99
-0+ 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 ); +} + +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->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" }, + { } +}; + +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
[...]
include/configs/sama5d4ek.h line 96
Quoted 11 lines
include/configs/sama5d4ek.h +2
-0@@ -91,7 +91,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD
This should use Kconfig ...
Quoted 6 lines
include/configs/sama5d4ek.h +2
-0+#endif +#define CONFIG_ATMEL_LCD_RGB565 #ifdef CONFIG_SYS_USE_SERIALFLASH
Signature · 2 lines
Best regards, Marek Vasut
Wu
PATCH v2 1/2 at91: video: Support driver-model for the HLCD driver
Hi Marek,
Thank you for your comments.
I will fix these issues in next patch.
Quoted 424 lines · Marek Vasut
Quoted 9 lines · Songjun Wu
Add driver-model support to this driver.
Signed-off-by Songjun Wu <[email protected]>---
Changes in v2:
- Due to the peripheral clock driver improvement, remove the unneccessary clock calling.Quoted 8 lines
board/atmel/at91sam9n12ek/at91sam9n12ek.c | 2 + board/atmel/at91sam9x5ek/at91sam9x5ek.c | 2 + board/atmel/sama5d2_xplained/sama5d2_xplained.c | 2 + board/atmel/sama5d3xek/sama5d3xek.c | 2 + board/atmel/sama5d4_xplained/sama5d4_xplained.c | 2 + board/atmel/sama5d4ek/sama5d4ek.c | 2 + drivers/video/Kconfig | 9 + drivers/video/atmel_hlcdfb.c | 314 +++++++++++++++++++++++-Split the driver from board changes.
Quoted 8 lines
include/configs/at91sam9n12ek.h | 4 + include/configs/at91sam9x5ek.h | 4 + include/configs/ma5d4evk.h | 4 + include/configs/sama5d2_xplained.h | 4 + include/configs/sama5d3xek.h | 4 + include/configs/sama5d4_xplained.h | 4 + include/configs/sama5d4ek.h | 4 + 15 files changed, 360 insertions(+), 3 deletions(-)[...]
Quoted 13 lines
drivers/video/atmel_hlcdfb.c +4
-0@@ -10,13 +10,24 @@#include <asm/io.h> #include <asm/arch/gpio.h> #include <asm/arch/clk.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> #include <lcd.h> +#include <video.h> drivers/video/atmel_hlcdfb.c line 27
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +4
-0#include <atmel_hlcdc.h> #if defined(CONFIG_LCD_LOGO )#include <bmp_logo.h> #endif +DECLARE_GLOBAL_DATA_PTR ; + +#define lcdc_readl (reg) __raw_readl((reg)) +#define lcdc_writel (reg, val) __raw_writel((val), (reg))Really ? Do we REALLY need more new accessors ? Just use readl/writel ...
Quoted 44 lines
drivers/video/atmel_hlcdfb.c +27
-3+#ifndef CONFIG_DM_VIDEO +/* configurable parameters */ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8#define ATMEL_LCDC_DMA_BURST_LEN 8@@ -26,9 +37,6 @@#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) @@ -218,3 +226,303 @@ void lcd_ctrl_init(void *lcdbase)/* 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 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);drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 263
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+if (ret) +return -EINVAL ; + + ret =clk_enable (&clk); +if (ret) +return ret; + + clk_rate =clk_get_rate (&clk); +if (!clk_rate) +return -ENODEV ;Clock are still enabled if you fail here ...
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+ 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);drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 284
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+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; + +/* Disable DISP signal */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_DISPDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_DISPSTS )) +udelay (1 );
wait_for_bit(), fix globally ... and don't use unbounded loops ...Quoted 13 lines
drivers/video/atmel_hlcdfb.c +13
-0+/* Disable synchronization */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_SYNCDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_LCDSTS )) +udelay (1 ); +/* Disable pixel clock */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_CLKDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_CLKSTS )) +udelay (1 ); +/* Disable PWM */ +lcdc_writel (®s->lcdc_lcddis,LCDC_LCDDIS_PWMDIS ); +while ((lcdc_readl (®s->lcdc_lcdsr) &LCDC_LCDSR_PWMSTS )) +udelay (1 ); +drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 307
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+/* 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 ) {I guess I'd just introduce a variable and ORR it with either CLKSEL or whatever bits based on the value to reduce this lengthy condition here. ie u32 foo =
LCDC_BAR|LCDC_BAZ;
if (value < 1)
foo |=LCDC_QUUX;
else
...writel(...);
Quoted 19 lines
drivers/video/atmel_hlcdfb.c +19
-0+/* 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 + | vl_clk_pol + |LCDC_LCDCFG0_CLKSEL ); + + }else { +lcdc_writel (®s->lcdc_lcdcfg0, +LCDC_LCDCFG0_CLKDIV (value -2 ) + |LCDC_LCDCFG0_CGDISHCR + |LCDC_LCDCFG0_CGDISHEO + |LCDC_LCDCFG0_CGDISOVR1 + |LCDC_LCDCFG0_CGDISBASE + | vl_clk_pol); + }drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 336
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+ +/* 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 ; + +#ifndef LCD_OUTPUT_BPP Just make sure that's always defined . If possible, get this from DT.
Quoted 83 lines
drivers/video/atmel_hlcdfb.c +83
-0+/* Output is 24bpp */ + value |=LCDC_LCDCFG5_MODE_OUTPUT_24BPP ; +#else +switch (LCD_OUTPUT_BPP ) { +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 ; + } +#endif + + value |=LCDC_LCDCFG5_GUARDTIME (priv->guard_time); + value |= (LCDC_LCDCFG5_DISPDLY |LCDC_LCDCFG5_VSPDLYS ); +lcdc_writel (®s->lcdc_lcdcfg5, value); + +/* Vertical & Horizontal Timing */ + value =LCDC_LCDCFG1_VSPW (timing->vsync_len.typ -1 ); + value |=LCDC_LCDCFG1_HSPW (timing->hsync_len.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg1, value); + + value =LCDC_LCDCFG2_VBPW (timing->vback_porch.typ); + value |=LCDC_LCDCFG2_VFPW (timing->vfront_porch.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg2, value); + + value =LCDC_LCDCFG3_HBPW (timing->hback_porch.typ -1 ); + value |=LCDC_LCDCFG3_HFPW (timing->hfront_porch.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg3, value); + +/* Display size */ + value =LCDC_LCDCFG4_RPF (timing->vactive.typ -1 ); + value |=LCDC_LCDCFG4_PPL (timing->hactive.typ -1 ); +lcdc_writel (®s->lcdc_lcdcfg4, value); + +lcdc_writel (®s->lcdc_basecfg0, +LCDC_BASECFG0_BLEN_AHB_INCR4 |LCDC_BASECFG0_DLBO ); + +switch (VNBITS (priv->vl_bpix)) { +case 16 : +lcdc_writel (®s->lcdc_basecfg1, +LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 ); +break ; +case 32 : +lcdc_writel (®s->lcdc_basecfg1, +LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 ); +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 ); + +/* Disable all interrupts */ +lcdc_writel (®s->lcdc_lcdidr, ~0UL ); +lcdc_writel (®s->lcdc_baseidr, ~0UL ); + +/* 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)); + +lcdc_writel (®s->lcdc_baseaddr, desc->address);drivers/video/atmel_hlcdfb.c void lcd_ctrl_init(void *lcdbase) · line 429
Quoted 10 lines
drivers/video/atmel_hlcdfb.c +10
-0+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 ); + +/* 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 );
wait_for_bit()...Quoted 99 lines
drivers/video/atmel_hlcdfb.c +99
-0+ 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 ); +} + +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->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" }, + { } +}; + +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 [...]
include/configs/sama5d4ek.h line 96
Quoted 11 lines
include/configs/sama5d4ek.h +2
-0@@ -91,7 +91,11 @@#define CONFIG_LCD_INFO #define CONFIG_LCD_INFO_BELOW_LOGO #define CONFIG_SYS_WHITE_ON_BLACK + +#ifndef CONFIG_DM_VIDEO #define CONFIG_ATMEL_HLCD This should use
Kconfig...Quoted 6 lines
include/configs/sama5d4ek.h +2
-0+#endif +#define CONFIG_ATMEL_LCD_RGB565 #ifdef CONFIG_SYS_USE_SERIALFLASH
PATCH v2 2/2 at91: video: DT binding for HLCDC driver
In reply to Songjun WuDT binding documentation for atmel HLCDC driver.
---
Changes in v2: None
doc/device-tree-bindings/video/atme-hlcdc.txt | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 doc/device-tree-bindings/video/atme-hlcdc.txt
doc/device-tree-bindings/video/atme-hlcdc.txt new file +38 -0
@@ -0,0 +1,38 @@ +Atmel HLCDC Framebuffer +----------------------------------------------------- +Required properties: +- compatible : + "atmel,sama5d2-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,guard-time: lcd guard time (Delay in frame periods). +- display-timings: please refer the displaymode.txt. + +Example: +hlcdc: hlcdc at f0000000 { + u-boot,dm-pre-reloc; + compatible = "atmel,sama5d2-hlcdc"; + reg = <0xf0000000 0x2000>; + clocks = <&lcdc_clk>; + atmel,vl-bpix = <4>; + 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>; + }; + }; +};
Signature · 1 line
2.11.0