[U-Boot] [PATCH 4/4] common/lcd_console: introduce display/framebuffer rotation

Hannes Petermaier hannes at petermaier.org
Thu Mar 12 17:46:15 CET 2015


On 2015-03-12 13:26, Igor Grinberg wrote:
> Hi Hannes,
Hi Igor,
thanks for response.
>   #endif
> -	/* Paint the logo and retrieve LCD base address */
> -	debug("[LCD] Drawing the logo...\n");
> -#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
> -	console_rows = (panel_info.vl_row - BMP_LOGO_HEIGHT);
> -	console_rows /= VIDEO_FONT_HEIGHT;
> +	/* setup text-console */
> +	debug("[LCD] setting up console...\n");
> +#ifdef CONFIG_LCD_ROTATION
> +	lcd_init_console(lcd_base,
> +			 panel_info.vl_col,
> +			 panel_info.vl_row,
> +			 panel_info.vl_rot);
>   #else
> -	console_rows = panel_info.vl_row / VIDEO_FONT_HEIGHT;
> +	lcd_init_console(lcd_base,
> +			 panel_info.vl_col,
> +			 panel_info.vl_row,
> +			 0);
>   #endif
> Please, don't start the #ifdef mess here...
> just always pass the panel_info.vl_rot.
This is not possible, because 'vl_rot' does'nt exist if 
CONFIG_LCD_ROTATION is not defined. (have a look into lcd.h). I made 
this to be compatible to all who have allready initialized a panel_info 
without vl_rot.
>
>> -	console_cols = panel_info.vl_col / VIDEO_FONT_WIDTH;
>> -	lcd_init_console(lcd_base, console_rows, console_cols);
>> +	/* Paint the logo and retrieve LCD base address */
>> +	debug("[LCD] Drawing the logo...\n");
>>   	if (do_splash) {
>>   		s = getenv("splashimage");
>>   		if (s) {
>> diff --git a/common/lcd_console.c b/common/lcd_console.c
>> index cac77be..6199c9a 100644
>> --- a/common/lcd_console.c
>> +++ b/common/lcd_console.c
>> @@ -2,6 +2,7 @@
>>    * (C) Copyright 2001-2014
>>    * DENX Software Engineering -- wd at denx.de
>>    * Compulab Ltd - http://compulab.co.il/
>> + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
>>    *
>>    * SPDX-License-Identifier:	GPL-2.0+
>>    */
>> @@ -10,26 +11,27 @@
>>   #include <lcd.h>
>>   #include <video_font.h>		/* Get font data, width and height */
>>   
>> -#define CONSOLE_ROW_SIZE	(VIDEO_FONT_HEIGHT * lcd_line_length)
>> -#define CONSOLE_ROW_FIRST	cons.lcd_address
>> -#define CONSOLE_SIZE		(CONSOLE_ROW_SIZE * cons.rows)
>> +#define PIXLBYTES		(NBYTES(LCD_BPP))
>> +
>> +#if LCD_BPP == LCD_COLOR16
>> +	#define fbptr_t ushort
>> +#elif LCD_BPP == LCD_COLOR32
>> +	#define fbptr_t u32
>> +#else
>> +	#define fbptr_t uchar
>> +#endif
>>   
>>   struct console_t {
>>   	short curr_col, curr_row;
>>   	short cols, rows;
>>   	void *lcd_address;
>> +	u32 lcdsizex, lcdsizey;
>> +	void (*fp_putc_xy)(ushort x, ushort y, char c);
>> +	void (*fp_console_moverow)(u32 rowdst, u32 rowsrc);
>> +	void (*fp_console_setrow)(u32 row, int clr);
>>   };
>>   static struct console_t cons;
>>   
>> -void lcd_init_console(void *address, int rows, int cols)
>> -{
>> -	memset(&cons, 0, sizeof(cons));
>> -	cons.cols = cols;
>> -	cons.rows = rows;
>> -	cons.lcd_address = address;
>> -
>> -}
>> -
>>   void lcd_set_col(short col)
>>   {
>>   	cons.curr_col = col;
>> @@ -56,63 +58,221 @@ int lcd_get_screen_columns(void)
>>   	return cons.cols;
>>   }
>>   
>> -static void lcd_putc_xy(ushort x, ushort y, char c)
>> +static void lcd_putc_xy0(ushort x, ushort y, char c)
>>   {
>> -	uchar *dest;
>> -	ushort row;
>>   	int fg_color = lcd_getfgcolor();
>>   	int bg_color = lcd_getbgcolor();
>> +	int i, row;
>> +	uchar *dest = (uchar *)(cons.lcd_address +
>> +				y * cons.lcdsizex * PIXLBYTES +
>> +				x * PIXLBYTES);
>> +
>> +	for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
>> +		fbptr_t *d = (fbptr_t *)dest;
>> +		uchar bits;
>> +		bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
>> +		for (i = 0; i < 8; ++i) {
>> +			*d++ = (bits & 0x80) ? fg_color : bg_color;
>> +			bits <<= 1;
>> +		}
>> +		dest += cons.lcdsizex * PIXLBYTES;
>> +	}
>> +}
>> +
>> +static inline void console_setrow0(u32 row, int clr)
>> +{
>>   	int i;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			       row * VIDEO_FONT_HEIGHT *
>> +			       cons.lcdsizex * PIXLBYTES);
>>   
>> -	dest = (uchar *)(cons.lcd_address +
>> -			 y * lcd_line_length + x * NBITS(LCD_BPP) / 8);
>> +	fbptr_t *d = (fbptr_t *)dst;
>> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * cons.lcdsizex); i++)
>> +		*d++ = clr;
>> +}
>>   
>> -	for (row = 0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) {
>> -#if LCD_BPP == LCD_COLOR16
>> -		ushort *d = (ushort *)dest;
>> -#elif LCD_BPP == LCD_COLOR32
>> -		u32 *d = (u32 *)dest;
>> -#else
>> -		uchar *d = dest;
>> -#endif
>> +static inline void console_moverow0(u32 rowdst, u32 rowsrc)
>> +{
>> +	int i;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			       rowdst * VIDEO_FONT_HEIGHT *
>> +			       cons.lcdsizex * PIXLBYTES);
>> +
>> +	uchar *src = (uchar *)(cons.lcd_address +
>> +			       rowsrc * VIDEO_FONT_HEIGHT *
>> +			       cons.lcdsizex * PIXLBYTES);
>> +
>> +	fbptr_t *pdst = (fbptr_t *)dst;
>> +	fbptr_t *psrc = (fbptr_t *)src;
>> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * cons.lcdsizex); i++)
>> +		*pdst++ = *psrc++;
>> +}
>> +#ifdef CONFIG_LCD_ROTATION
>> +static void lcd_putc_xy90(ushort x, ushort y, char c)
>> +{
>> +	int fg_color = lcd_getfgcolor();
>> +	int bg_color = lcd_getbgcolor();
>> +	int i, col;
>> +	uchar *dest = (uchar *)(cons.lcd_address +
>> +				cons.lcdsizey * cons.lcdsizex * PIXLBYTES -
>> +				(x+1) * cons.lcdsizex * PIXLBYTES +
>> +				y * PIXLBYTES);
>> +
>> +	fbptr_t *d = (fbptr_t *)dest;
>> +	uchar msk = 0x80;
>> +	uchar *pfont = video_fontdata + c * VIDEO_FONT_HEIGHT;
>> +	for (col = 0; col < VIDEO_FONT_WIDTH; ++col) {
>> +		for (i = 0; i < VIDEO_FONT_HEIGHT; ++i)
>> +			*d++ = (*(pfont + i) & msk) ? fg_color : bg_color;
>> +		msk >>= 1;
>> +		d -= (cons.lcdsizex + VIDEO_FONT_HEIGHT);
>> +	}
>> +}
>> +
>> +static inline void console_setrow90(u32 row, int clr)
>> +{
>> +	int i, j;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			       row*VIDEO_FONT_HEIGHT * PIXLBYTES);
>> +
>> +	for (j = 0; j < cons.lcdsizey; j++) {
>> +		fbptr_t *pdst = (fbptr_t *)dst;
>> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
>> +			*pdst++ = clr;
>> +		dst += cons.lcdsizex * PIXLBYTES;
>> +	}
>> +}
>> +
>> +static inline void console_moverow90(u32 rowdst, u32 rowsrc)
>> +{
>> +	int i, j;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			      rowdst*VIDEO_FONT_HEIGHT * PIXLBYTES);
>> +
>> +	uchar *src = (uchar *)(cons.lcd_address +
>> +			      rowsrc*VIDEO_FONT_HEIGHT * PIXLBYTES);
>> +
>> +	for (j = 0; j < cons.lcdsizey; j++) {
>> +		fbptr_t *psrc = (fbptr_t *)src;
>> +		fbptr_t *pdst = (fbptr_t *)dst;
>> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
>> +			*pdst++ = *psrc++;
>> +		src += cons.lcdsizex * PIXLBYTES;
>> +		dst += cons.lcdsizex * PIXLBYTES;
>> +	}
>> +}
>> +
>> +static void lcd_putc_xy180(ushort x, ushort y, char c)
>> +{
>> +	int fg_color = lcd_getfgcolor();
>> +	int bg_color = lcd_getbgcolor();
>> +	int i, row;
>> +	uchar *dest = (uchar *)(cons.lcd_address +
>> +				cons.lcdsizex * PIXLBYTES +
>> +				cons.lcdsizey * cons.lcdsizex * PIXLBYTES -
>> +				y * cons.lcdsizex * PIXLBYTES -
>> +				(x+1) * PIXLBYTES);
>> +
>> +	for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
>> +		fbptr_t *d = (fbptr_t *)dest;
>>   		uchar bits;
>>   		bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
>>   
>>   		for (i = 0; i < 8; ++i) {
>> -			*d++ = (bits & 0x80) ? fg_color : bg_color;
>> +			*d-- = (bits & 0x80) ? fg_color : bg_color;
>>   			bits <<= 1;
>>   		}
>> +		dest -= cons.lcdsizex * PIXLBYTES;
>>   	}
>>   }
>>   
>> -static void console_scrollup(void)
>> +static void lcd_putc_xy270(ushort x, ushort y, char c)
>>   {
>> -	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
>> +	int fg_color = lcd_getfgcolor();
>>   	int bg_color = lcd_getbgcolor();
>> +	int col, i;
>> +	uchar *dest = (uchar *)(cons.lcd_address +
>> +				((x+1) * cons.lcdsizex) * PIXLBYTES -
>> +				y * PIXLBYTES);
>> +
>> +	fbptr_t *d = (fbptr_t *)dest;
>> +	uchar msk = 0x80;
>> +	uchar *pfont = video_fontdata + c * VIDEO_FONT_HEIGHT;
>> +	for (col = 0; col < VIDEO_FONT_WIDTH; ++col) {
>> +		for (i = 0; i < VIDEO_FONT_HEIGHT; ++i)
>> +			*d-- = (*(pfont + i) & msk) ? fg_color : bg_color;
>> +		msk >>= 1;
>> +		d += (cons.lcdsizex + VIDEO_FONT_HEIGHT);
>> +	}
>> +}
>>   
>> -	/* Copy up rows ignoring those that will be overwritten */
>> -	memcpy(CONSOLE_ROW_FIRST,
>> -	       cons.lcd_address + CONSOLE_ROW_SIZE * rows,
>> -	       CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows);
>> +static inline void console_setrow270(u32 row, int clr)
>> +{
>> +	int i, j;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			       cons.lcdsizex * PIXLBYTES -
>> +			       (row*VIDEO_FONT_HEIGHT+1) * PIXLBYTES);
>> +
>> +	for (j = 0; j < cons.lcdsizey; j++) {
>> +		fbptr_t *pdst = (fbptr_t *)dst;
>> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
>> +			*pdst-- = clr;
>> +		dst += cons.lcdsizex * PIXLBYTES;
>> +	}
>> +}
>>   
>> -	/* Clear the last rows */
>> -#if (LCD_BPP != LCD_COLOR32)
>> -	memset(lcd_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows,
>> -	       bg_color, CONSOLE_ROW_SIZE * rows);
>> -#else
>> -	u32 *ppix = cons.lcd_address +
>> -		    CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows;
>> -	u32 i;
>> -	for (i = 0;
>> -	    i < (CONSOLE_ROW_SIZE * rows) / NBYTES(panel_info.vl_bpix);
>> -	    i++) {
>> -		*ppix++ = bg_color;
>> +static inline void console_moverow270(u32 rowdst, u32 rowsrc)
>> +{
>> +	int i, j;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			      cons.lcdsizex * PIXLBYTES -
>> +			      (rowdst*VIDEO_FONT_HEIGHT+1) * PIXLBYTES);
>> +
>> +	uchar *src = (uchar *)(cons.lcd_address +
>> +			      cons.lcdsizex * PIXLBYTES -
>> +			      (rowsrc*VIDEO_FONT_HEIGHT+1) * PIXLBYTES);
>> +
>> +	for (j = 0; j < cons.lcdsizey; j++) {
>> +		fbptr_t *psrc = (fbptr_t *)src;
>> +		fbptr_t *pdst = (fbptr_t *)dst;
>> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
>> +			*pdst-- = *psrc--;
>> +		src += cons.lcdsizex * PIXLBYTES;
>> +		dst += cons.lcdsizex * PIXLBYTES;
>>   	}
>> -#endif
>> -	lcd_sync();
>> -	cons.curr_row -= rows;
>>   }
>>   
>> +static inline void console_setrow180(u32 row, int clr)
>> +{
>> +	int i;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			       (cons.rows-row-1) * VIDEO_FONT_HEIGHT *
>> +			       cons.lcdsizex * PIXLBYTES);
>> +
>> +	fbptr_t *d = (fbptr_t *)dst;
>> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * cons.lcdsizex); i++)
>> +		*d++ = clr;
>> +}
>> +
>> +static inline void console_moverow180(u32 rowdst, u32 rowsrc)
>> +{
>> +	int i;
>> +	uchar *dst = (uchar *)(cons.lcd_address +
>> +			       (cons.rows-rowdst-1) * VIDEO_FONT_HEIGHT *
>> +			       cons.lcdsizex * PIXLBYTES);
>> +
>> +	uchar *src = (uchar *)(cons.lcd_address +
>> +			       (cons.rows-rowsrc-1) * VIDEO_FONT_HEIGHT *
>> +			       cons.lcdsizex * PIXLBYTES);
>> +
>> +	fbptr_t *pdst = (fbptr_t *)dst;
>> +	fbptr_t *psrc = (fbptr_t *)src;
>> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * cons.lcdsizex); i++)
>> +		*pdst++ = *psrc++;
>> +}
>> +
>> +#endif /* CONFIG_LCD_ROTATION */
> Can't this whole thing go into a separate file?
> So, the console stuff will only define weak functions which can be overridden
> by the rotation functionality.
> This will keep the console code clean (also from ifdefs) and have the rotation
> functionality cleanly added by a CONFIG_ symbol, which will control the
> compilation for the separate file.
Might be possible, which name should we give to it ? 
lcd_console_rotation.c ?
But how we deal with the function-pointer initialization ?
>
>> +
>>   static inline void console_back(void)
>>   {
>>   	if (--cons.curr_col < 0) {
>> @@ -121,26 +281,83 @@ static inline void console_back(void)
>>   			cons.curr_row = 0;
>>   	}
>>   
>> -	lcd_putc_xy(cons.curr_col * VIDEO_FONT_WIDTH,
>> -		    cons.curr_row * VIDEO_FONT_HEIGHT, ' ');
>> +	cons.fp_putc_xy(cons.curr_col * VIDEO_FONT_WIDTH,
>> +			cons.curr_row * VIDEO_FONT_HEIGHT, ' ');
>>   }
>>   
>>   static inline void console_newline(void)
>>   {
>> +	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
>> +	int bg_color = lcd_getbgcolor();
>> +	int i;
>> +
>>   	cons.curr_col = 0;
>>   
>>   	/* Check if we need to scroll the terminal */
>> -	if (++cons.curr_row >= cons.rows)
>> -		console_scrollup();
>> -	else
>> -		lcd_sync();
>> +	if (++cons.curr_row >= cons.rows) {
>> +		for (i = 0; i < cons.rows-rows; i++)
>> +			cons.fp_console_moverow(i, i+rows);
>> +		for (i = 0; i < rows; i++)
>> +			cons.fp_console_setrow(cons.rows-i-1, bg_color);
>> +		cons.curr_row -= rows;
>> +	}
>> +	lcd_sync();
>> +}
>> +
>> +static void console_calc_rowcol(int vl_cols, int vl_rows, short *cl, short *rw)
>> +{
>> +	*cl = vl_cols / VIDEO_FONT_WIDTH;
>> +#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
>> +	*rw = (vl_rows - BMP_LOGO_HEIGHT);
>> +	*rw /= VIDEO_FONT_HEIGHT;
>> +#else
>> +	*rw = vl_rows / VIDEO_FONT_HEIGHT;
>> +#endif
>> +}
>> +
>> +void lcd_init_console(void *address, int vl_cols, int vl_rows, int vl_rot)
>> +{
>> +	memset(&cons, 0, sizeof(cons));
>> +	cons.lcd_address = address;
>> +
>> +	cons.lcdsizex = vl_cols;
>> +	cons.lcdsizey = vl_rows;
>> +
>> +	if (vl_rot == 0) {
>> +		cons.fp_putc_xy = &lcd_putc_xy0;
>> +		cons.fp_console_moverow = &console_moverow0;
>> +		cons.fp_console_setrow = &console_setrow0;
>> +		console_calc_rowcol(vl_cols, vl_rows, &cons.cols, &cons.rows);
> This call can be made after the if else structure and written only once.
No. Have a closer look to it. If display is rotated 0°/180° the 
calculation is not the same if display is rotated 90/270°
>
>> +#ifdef CONFIG_LCD_ROTATION
>> +	} else if (vl_rot == 90) {
>> +		cons.fp_putc_xy = &lcd_putc_xy90;
>> +		cons.fp_console_moverow = &console_moverow90;
>> +		cons.fp_console_setrow = &console_setrow90;
>> +		console_calc_rowcol(vl_rows, vl_cols, &cons.cols, &cons.rows);
>> +	} else if (vl_rot == 180) {
>> +		cons.fp_putc_xy = &lcd_putc_xy180;
>> +		cons.fp_console_moverow = &console_moverow180;
>> +		cons.fp_console_setrow = &console_setrow180;
>> +		console_calc_rowcol(vl_cols, vl_rows, &cons.cols, &cons.rows);
>> +	} else if (vl_rot == 270) {
>> +		cons.fp_putc_xy = &lcd_putc_xy270;
>> +		cons.fp_console_moverow = &console_moverow270;
>> +		cons.fp_console_setrow = &console_setrow270;
>> +		console_calc_rowcol(vl_rows, vl_cols, &cons.cols, &cons.rows);
>> +#endif
>> +	} else {
>> +		puts("lcd_init_console: invalid framebuffer rotation!\n");
>> +	}
> I would recommend extracting the whole if else ... structure into
> a separate function say lcd_setup_console_rot() or something and
> make the default one doing only the vl_rot == 0 stuff.
Whats the use of this ?
Should this also be in a separate file?

best regards,
Hannes


More information about the U-Boot mailing list