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

Igor Grinberg grinberg at compulab.co.il
Wed Mar 18 13:56:49 CET 2015


Hi Hannes,

On 03/18/15 09:37, Hannes Petermaier wrote:
> From: Hannes Petermaier <hannes.petermaier at br-automation.com>
> 
> Sometimes, for example if the display is mounted in portrait mode or even if it
> mounted landscape but rotated by 180 degrees, we need to rotate our content of
> the display respectively the framebuffer, so that user can read the messages
> who are printed out.
> 
> For this we introduce the feature called "CONFIG_LCD_ROTATION", this may be
> defined in the board-configuration if needed. After this the lcd_console will
> be initialized with a given rotation from "vl_rot" out of "vidinfo_t" which is
> provided by the board specific code.
> 
> If CONFIG_LCD_ROTATION is not defined, the console will be initialized with
> 0 degrees rotation.
> 
> Signed-off-by: Hannes Petermaier <hannes.petermaier at br-automation.com>
> Signed-off-by: Hannes Petermaier <oe5hpm at oevsv.at>

[...]

> diff --git a/common/lcd_console.c b/common/lcd_console.c
> index cac77be..14fd890 100644
> --- a/common/lcd_console.c
> +++ b/common/lcd_console.c

[...]

> @@ -10,26 +11,16 @@
>  #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)
> +#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;
> -};
>  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,61 +47,50 @@ 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(struct console_t *pcons, ushort x, ushort y, char c)
>  {
> -	uchar *dest;
> -	ushort row;
>  	int fg_color = lcd_getfgcolor();
>  	int bg_color = lcd_getbgcolor();
> -	int i;
> -
> -	dest = (uchar *)(cons.lcd_address +
> -			 y * lcd_line_length + x * NBITS(LCD_BPP) / 8);
> -
> -	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
> -		uchar bits;
> -		bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
> -
> -		for (i = 0; i < 8; ++i) {
> -			*d++ = (bits & 0x80) ? fg_color : bg_color;
> +	int i, row;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  y * pcons->lcdsizex +
> +				  x;
> +
> +	for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
> +		uchar bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
> +		for (i = 0; i < VIDEO_FONT_WIDTH; ++i) {
> +			*dst++ = (bits & 0x80) ? fg_color : bg_color;
>  			bits <<= 1;
>  		}
> +		dst += (pcons->lcdsizex - VIDEO_FONT_WIDTH);
>  	}
>  }
>  
> -static void console_scrollup(void)
> +static inline void console_setrow0(struct console_t *pcons, u32 row, int clr)
>  {
> -	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
> -	int bg_color = lcd_getbgcolor();
> +	int i;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  row * VIDEO_FONT_HEIGHT *
> +				  pcons->lcdsizex;
>  
> -	/* 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);
> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
> +		*dst++ = clr;
> +}
>  
> -	/* 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;
> -	}
> -#endif
> -	lcd_sync();
> -	cons.curr_row -= rows;
> +static inline void console_moverow0(struct console_t *pcons,
> +				    u32 rowdst, u32 rowsrc)
> +{
> +	int i;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  rowdst * VIDEO_FONT_HEIGHT *
> +				  pcons->lcdsizex;
> +
> +	fbptr_t *src = (fbptr_t *)pcons->lcd_address +
> +				  rowsrc * VIDEO_FONT_HEIGHT *
> +				  pcons->lcdsizex;
> +
> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
> +		*dst++ = *src++;
>  }
>  
>  static inline void console_back(void)
> @@ -121,19 +101,65 @@ 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,
> +			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(&cons, i, i+rows);
> +		for (i = 0; i < rows; i++)
> +			cons.fp_console_setrow(&cons, cons.rows-i-1, bg_color);
> +		cons.curr_row -= rows;
> +	}
> +	lcd_sync();
> +}
> +
> +static void console_calc_rowcol(struct console_t *pcons)
> +{
> +	pcons->cols = pcons->lcdsizex / VIDEO_FONT_WIDTH;
> +#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
> +	pcons->rows = (pcons->lcdsizey - BMP_LOGO_HEIGHT);
> +	pcons->rows /= VIDEO_FONT_HEIGHT;
> +#else
> +	pcons->rows = pcons->lcdsizey / VIDEO_FONT_HEIGHT;
> +#endif
> +}
> +
> +void __weak lcd_init_console_rot(struct console_t *pcons)
> +{
> +	return;
> +}
> +
> +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;
> +	cons.lcdrot = vl_rot;
> +
> +	cons.fp_putc_xy = &lcd_putc_xy0;
> +	cons.fp_console_moverow = &console_moverow0;
> +	cons.fp_console_setrow = &console_setrow0;
> +	console_calc_rowcol(&cons);

I think the above four lines is exactly what should be placed in the
__weak variant of lcd_init_console_rot() function (the one just above
this one).

> +
> +	lcd_init_console_rot(&cons);
> +
> +	debug("lcd_console: have %d/%d col/rws on scr %dx%d (%d deg rotated)\n",
> +	      cons.cols, cons.rows, cons.lcdsizex, cons.lcdsizey, vl_rot);
> +

no need for the empty line here.

>  }
>  
>  void lcd_putc(const char c)
> @@ -165,8 +191,9 @@ void lcd_putc(const char c)
>  
>  		return;
>  	default:
> -		lcd_putc_xy(cons.curr_col * VIDEO_FONT_WIDTH,
> -			    cons.curr_row * VIDEO_FONT_HEIGHT, c);
> +		cons.fp_putc_xy(&cons,
> +				cons.curr_col * VIDEO_FONT_WIDTH,
> +				cons.curr_row * VIDEO_FONT_HEIGHT, c);
>  		if (++cons.curr_col >= cons.cols)
>  			console_newline();
>  	}
> @@ -235,4 +262,3 @@ U_BOOT_CMD(
>  	"print string on lcd-framebuffer",
>  	"    <string>"
>  );
> -
> diff --git a/common/lcd_console_rotation.c b/common/lcd_console_rotation.c
> new file mode 100644
> index 0000000..3b6bb4f
> --- /dev/null
> +++ b/common/lcd_console_rotation.c
> @@ -0,0 +1,216 @@
> +/*
> + * (C) Copyright 2015
> + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <lcd.h>
> +#include <video_font.h>		/* Get font data, width and height */
> +
> +#if LCD_BPP == LCD_COLOR16
> +	#define fbptr_t ushort
> +#elif LCD_BPP == LCD_COLOR32
> +	#define fbptr_t u32
> +#else
> +	#define fbptr_t uchar
> +#endif

That is a duplication of the code in lcd_console.c.
If we can get rid of these size games, probably we should have in the lcd.h,
or lcd_console.h, or ...

> +
> +static void lcd_putc_xy90(struct console_t *pcons, ushort x, ushort y, char c)
> +{
> +	int fg_color = lcd_getfgcolor();
> +	int bg_color = lcd_getbgcolor();
> +	int col, i;
> +
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  (x+1) * pcons->lcdsizex -
> +				  y;
> +
> +	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)
> +			*dst-- = (*(pfont + i) & msk) ? fg_color : bg_color;
> +		msk >>= 1;
> +		dst += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
> +	}
> +}
> +
> +static inline void console_setrow90(struct console_t *pcons, u32 row, int clr)
> +{
> +	int i, j;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  pcons->lcdsizex -
> +				  row*VIDEO_FONT_HEIGHT+1;
> +
> +	for (j = 0; j < pcons->lcdsizey; j++) {
> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
> +			*dst-- = clr;
> +		dst += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
> +	}
> +}
> +
> +static inline void console_moverow90(struct console_t *pcons,
> +				      u32 rowdst, u32 rowsrc)
> +{
> +	int i, j;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  pcons->lcdsizex -
> +				  (rowdst*VIDEO_FONT_HEIGHT+1);
> +
> +	fbptr_t *src = (fbptr_t *)pcons->lcd_address +
> +				  pcons->lcdsizex -
> +				  (rowsrc*VIDEO_FONT_HEIGHT+1);
> +
> +	for (j = 0; j < pcons->lcdsizey; j++) {
> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
> +			*dst-- = *src--;
> +		src += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
> +		dst += (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
> +	}
> +}
> +static void lcd_putc_xy180(struct console_t *pcons, ushort x, ushort y, char c)
> +{
> +	int fg_color = lcd_getfgcolor();
> +	int bg_color = lcd_getbgcolor();
> +	int i, row;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  pcons->lcdsizex +
> +				  pcons->lcdsizey * pcons->lcdsizex -
> +				  y * pcons->lcdsizex -
> +				  (x+1);
> +
> +	for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
> +		uchar bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
> +
> +		for (i = 0; i < VIDEO_FONT_WIDTH; ++i) {
> +			*dst-- = (bits & 0x80) ? fg_color : bg_color;
> +			bits <<= 1;
> +		}
> +		dst -= (pcons->lcdsizex - VIDEO_FONT_WIDTH);
> +	}
> +}
> +
> +static inline void console_setrow180(struct console_t *pcons, u32 row, int clr)
> +{
> +	int i;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  (pcons->rows-row-1) * VIDEO_FONT_HEIGHT *
> +				  pcons->lcdsizex;
> +
> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
> +		*dst++ = clr;
> +}
> +
> +static inline void console_moverow180(struct console_t *pcons,
> +				      u32 rowdst, u32 rowsrc)
> +{
> +	int i;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  (pcons->rows-rowdst-1) * VIDEO_FONT_HEIGHT *
> +				  pcons->lcdsizex;
> +
> +	fbptr_t *src = (fbptr_t *)pcons->lcd_address +
> +				  (pcons->rows-rowsrc-1) * VIDEO_FONT_HEIGHT *
> +				  pcons->lcdsizex;
> +
> +	for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
> +		*dst++ = *src++;
> +}
> +
> +static void lcd_putc_xy270(struct console_t *pcons, ushort x, ushort y, char c)
> +{
> +	int fg_color = lcd_getfgcolor();
> +	int bg_color = lcd_getbgcolor();
> +	int i, col;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  pcons->lcdsizey * pcons->lcdsizex -
> +				  (x+1) * pcons->lcdsizex +
> +				  y;
> +
> +	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)
> +			*dst++ = (*(pfont + i) & msk) ? fg_color : bg_color;
> +		msk >>= 1;
> +		dst -= (pcons->lcdsizex + VIDEO_FONT_HEIGHT);
> +	}
> +}
> +
> +static inline void console_setrow270(struct console_t *pcons, u32 row, int clr)
> +{
> +	int i, j;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  row*VIDEO_FONT_HEIGHT;
> +
> +	for (j = 0; j < pcons->lcdsizey; j++) {
> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
> +			*dst++ = clr;
> +		dst += (pcons->lcdsizex - VIDEO_FONT_HEIGHT);
> +	}
> +}
> +
> +static inline void console_moverow270(struct console_t *pcons,
> +				     u32 rowdst, u32 rowsrc)
> +{
> +	int i, j;
> +	fbptr_t *dst = (fbptr_t *)pcons->lcd_address +
> +				  rowdst*VIDEO_FONT_HEIGHT;
> +
> +	fbptr_t *src = (fbptr_t *)pcons->lcd_address +
> +				  rowsrc*VIDEO_FONT_HEIGHT;
> +
> +	for (j = 0; j < pcons->lcdsizey; j++) {
> +		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
> +			*dst++ = *src++;
> +		src += (pcons->lcdsizex - VIDEO_FONT_HEIGHT);
> +		dst += (pcons->lcdsizex - VIDEO_FONT_HEIGHT);
> +	}
> +}
> +
> +static void console_calc_rowcol_rot(struct console_t *pcons)
> +{
> +	u32 cols, rows;
> +
> +	if (pcons->lcdrot == 1 || pcons->lcdrot == 3) {
> +		cols = pcons->lcdsizey;
> +		rows = pcons->lcdsizex;
> +	} else {
> +		cols = pcons->lcdsizex;
> +		rows = pcons->lcdsizey;
> +	}
> +
> +	pcons->cols = cols / VIDEO_FONT_WIDTH;
> +#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
> +	pcons->rows = (rows - BMP_LOGO_HEIGHT);
> +	pcons->rows /= VIDEO_FONT_HEIGHT;
> +#else
> +	pcons->rows = rows / VIDEO_FONT_HEIGHT;
> +#endif
> +}
> +
> +void lcd_init_console_rot(struct console_t *pcons)
> +{
> +	if (pcons->lcdrot == 0) {
> +		return;
> +	} else if (pcons->lcdrot == 1) {
> +		pcons->fp_putc_xy = &lcd_putc_xy90;
> +		pcons->fp_console_moverow = &console_moverow90;
> +		pcons->fp_console_setrow = &console_setrow90;
> +	} else if (pcons->lcdrot == 2) {
> +		pcons->fp_putc_xy = &lcd_putc_xy180;
> +		pcons->fp_console_moverow = &console_moverow180;
> +		pcons->fp_console_setrow = &console_setrow180;
> +	} else if (pcons->lcdrot == 3) {
> +		pcons->fp_putc_xy = &lcd_putc_xy270;
> +		pcons->fp_console_moverow = &console_moverow270;
> +		pcons->fp_console_setrow = &console_setrow270;
> +	} else {
> +		puts("lcd_init_console_rot: invalid framebuffer rotation!\n");

How about
printf("%s: invalid framebuffer rotation!\n", __func__);
?

> +		puts("                      using def. 0 degree rotation.\n");
> +		return;
> +	}
> +	console_calc_rowcol_rot(pcons);
> +}
> diff --git a/include/lcd.h b/include/lcd.h
> index f049fd3..1329280 100644
> --- a/include/lcd.h
> +++ b/include/lcd.h
> @@ -51,6 +51,7 @@ void lcd_set_flush_dcache(int flush);
>  typedef struct vidinfo {
>  	ushort	vl_col;		/* Number of columns (i.e. 160) */
>  	ushort	vl_row;		/* Number of rows (i.e. 100) */
> +	ushort	vl_rot;		/* Rotation of Display (0, 1, 2, 3) */
>  	u_char	vl_bpix;	/* Bits per pixel, 0 = 1 */
>  	ushort	*cmap;		/* Pointer to the colormap */
>  	void	*priv;		/* Pointer to driver-specific data */
> diff --git a/include/lcd_console.h b/include/lcd_console.h
> index 429214d..6612a38 100644
> --- a/include/lcd_console.h
> +++ b/include/lcd_console.h
> @@ -9,6 +9,16 @@
>  #define CONFIG_CONSOLE_SCROLL_LINES 1
>  #endif
>  
> +struct console_t {
> +	short curr_col, curr_row;
> +	short cols, rows;
> +	void *lcd_address;
> +	u32 lcdsizex, lcdsizey, lcdrot;
> +	void (*fp_putc_xy)(struct console_t *pcons, ushort x, ushort y, char c);
> +	void (*fp_console_moverow)(struct console_t *pcons,
> +				   u32 rowdst, u32 rowsrc);
> +	void (*fp_console_setrow)(struct console_t *pcons, u32 row, int clr);
> +};
>  /**
>   * lcd_init_console() - Initialize lcd console parameters
>   *
> @@ -16,11 +26,11 @@
>   * console has.
>   *
>   * @address: Console base address
> - * @rows: Number of rows in the console
> - * @cols: Number of columns in the console
> + * @vl_rows: Number of rows in the console
> + * @vl_cols: Number of columns in the console
> + * @vl_rot: Rotation of display in degree (0 - 90 - 180 - 270) counterlockwise
>   */
> -void lcd_init_console(void *address, int rows, int cols);
> -
> +void lcd_init_console(void *address, int vl_cols, int vl_rows, int vl_rot);
>  /**
>   * lcd_set_col() - Set the number of the current lcd console column
>   *
> 

-- 
Regards,
Igor.


More information about the U-Boot mailing list