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

Igor Grinberg grinberg at compulab.co.il
Sun Mar 15 09:34:42 CET 2015


Hi Hannes,

On 03/12/15 18:46, Hannes Petermaier wrote:
> 
> 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).

Of course I did before sending the reply...
What I'm trying to say is - let it exist and default to 0 angle rotation.

> I made this to be compatible to all who have allready initialized a
> panel_info without vl_rot.

This increases the mess and I think is not sensible enough.
Just change the users to initialize the panel_info with vl_rot.
I think also that default initialization of globals is 0, right?
If so, those users that do not initialize the vl_rot explicitly,
should have it initialized to 0 implicitly by compiler.

>>
>>> -    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 ?

Sounds good.

> But how we deal with the function-pointer initialization ?

I think the usual method would do...
You call some kind of lcd_console_init_rot() with most of the code
that you currently have in lcd_init_console() that is related to rotation.
If the CONFIG_LCD_ROTATION is not set, then the lcd_init_console() stub
just returns the 0 rotation config.

>>
>>> +
>>>   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°

Yep. Sorry, I've missed the switch between cols and rows...

>>
>>> +#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?

Yes, that is how I think it will do better.

Just to explain my points:
1) make the rotation feature an integrative part of the code by always using
   the rotation code: if CONFIG_LCD_ROTATION is *not* set then just rotate it
   to 0 degrees and compile out the rest of the code.
2) make the rotation feature a bit more separate from the console code.
   I believe this way will make it cleaner.

Also, might it be useful to allow specifiying the angle through the
CONFIG_LCD_ROTATION define?
Have you considered using Kconfig for this?

-- 
Regards,
Igor.


More information about the U-Boot mailing list