diff --git a/drivers/lcd/lcd_framebuffer.c b/drivers/lcd/lcd_framebuffer.c index 99a9b22eed4..884fe0f40d3 100644 --- a/drivers/lcd/lcd_framebuffer.c +++ b/drivers/lcd/lcd_framebuffer.c @@ -211,43 +211,52 @@ static int lcdfb_updateearea(FAR struct fb_vtable_s *vtable, unsigned int pixperbyte = 8 / pinfo->bpp; startx &= ~(pixperbyte - 1); } + } + if (pinfo->putarea != NULL) + { + /* Each Driver's callback function putarea may be optimized by checking + * if it is a full screen/full row mode or not. + * In case of full screen/row mode the memory layout of drivers memory + * and data provided to putarea function may be (or not, it depends of + * display and driver implementation) identical. + * Identical memory layout let us to use: + * - memcopy (if there is shadow buffer in driver implementation) + * - apply DMA channel to transfer data to driver memory. + */ + + ret = pinfo->putarea(pinfo->dev, starty, endy, startx, endx, run); + if (ret < 0) + { + lcderr("Failed to update area"); + return ret; + } + } + else + { width = endx - startx + 1; /* Get the starting position in the framebuffer */ run = priv->fbmem + starty * priv->stride; run += (startx * pinfo->bpp + 7) >> 3; - } - /* Update the whole screen? */ - - if (startx == 0 && endx == priv->xres - 1 && - starty == 0 && endy == priv->yres - 1) - { - /* Yes, LCD driver support putarea callback? */ - - if (pinfo->putarea != NULL) + for (row = starty; row <= endy; row++) { - /* Yes, go the fast path */ + ret = pinfo->putrun(pinfo->dev, row, startx, run, width); + if (ret < 0) + { + lcderr("Failed to update row"); + return ret; + } - return pinfo->putarea(pinfo->dev, starty, endy, startx, endx, run); + run += priv->stride; } } - for (row = starty; row <= endy; row++) + if (pinfo->redraw != NULL) { - /* REVISIT: Some LCD hardware certain alignment requirements on DMA - * memory. - */ - - ret = pinfo->putrun(pinfo->dev, row, startx, run, width); - if (ret < 0) - { - return ret; - } - - run += priv->stride; + pinfo->redraw(pinfo->dev); } return OK; diff --git a/drivers/lcd/ssd1680.c b/drivers/lcd/ssd1680.c index 2d014d55ab5..33588ae689f 100644 --- a/drivers/lcd/ssd1680.c +++ b/drivers/lcd/ssd1680.c @@ -126,33 +126,38 @@ struct ssd1680_dev_s /* Libc extension */ -FAR void *bitscpy_ds(FAR void *dest, int dest_offset, FAR const void *src, - size_t nbits); +static FAR void *bitscpy_ds(FAR void *dest, int dest_offset, + FAR const void *src, size_t nbits); -FAR void *bitscpy_ss(FAR void *dest, FAR const void *src, int src_offset, - size_t nbits); +static FAR void *bitscpy_ss(FAR void *dest, FAR const void *src, + int src_offset, size_t nbits); /* LCD Data Transfer Methods */ static int ssd1680_busy_wait(FAR struct ssd1680_dev_s *priv); static void ssd1680_snd_cmd_with_data0(FAR struct ssd1680_dev_s *priv, - uint8_t cmd); + uint8_t cmd); static void ssd1680_snd_cmd_with_data1(FAR struct ssd1680_dev_s *priv, - uint8_t cmd, uint8_t dta1); + uint8_t cmd, uint8_t dta1); static void ssd1680_snd_cmd_with_data2(FAR struct ssd1680_dev_s *priv, - uint8_t cmd, uint8_t dta1, uint8_t dta2); + uint8_t cmd, uint8_t dta1, + uint8_t dta2); static void ssd1680_snd_cmd_with_data3(FAR struct ssd1680_dev_s *priv, - uint8_t cmd, uint8_t dta1, uint8_t dta2, uint8_t dta3); + uint8_t cmd, uint8_t dta1, + uint8_t dta2, uint8_t dta3); static void ssd1680_snd_cmd_with_data4(FAR struct ssd1680_dev_s *priv, - uint8_t cmd, uint8_t dta1, uint8_t dta2, uint8_t dta3, uint8_t dta4); + uint8_t cmd, uint8_t dta1, + uint8_t dta2, uint8_t dta3, + uint8_t dta4); static void ssd1680_snd_cmd_with_data(FAR struct ssd1680_dev_s *priv, - uint8_t cmd, const uint8_t *dta, int dta_len); + uint8_t cmd, const uint8_t *dta, + int dta_len); #if !defined(CONFIG_LCD_PORTRAIT) && !defined(CONFIG_LCD_RPORTRAIT) # if SSD1680_DEV_BPP == 1 @@ -179,6 +184,8 @@ static int ssd1680_getrun(FAR struct lcd_dev_s *dev, fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, size_t npixels); +static int ssd1680_redraw(FAR struct lcd_dev_s *dev); + /* LCD Configuration */ static int ssd1680_getvideoinfo(FAR struct lcd_dev_s *dev, @@ -207,7 +214,7 @@ static int ssd1680_setpower(struct lcd_dev_s *dev, int power); static int ssd1680_configuredisplay(struct ssd1680_dev_s *priv); static int ssd1680_redraw_display(struct ssd1680_dev_s *priv); static int ssd1680_update_row(struct ssd1680_dev_s *priv, int row); -static int ssd1680_update_all(struct ssd1680_dev_s *priv); +static int ssd1680_update_all_and_redraw(struct ssd1680_dev_s *priv); /**************************************************************************** * Private Data @@ -244,6 +251,7 @@ static const struct lcd_planeinfo_s g_planeinfo = .putarea = NULL, /* Not need to implement */ .getrun = ssd1680_getrun, /* Read content of shadow memory */ .getarea = NULL, /* Not need to implement */ + .redraw = ssd1680_redraw, /* Update drivers memory and redraw */ .buffer = (FAR uint8_t *)g_runbuffer, /* Run scratch buffer */ .bpp = SSD1680_DEV_BPP, /* Bits-per-pixel */ }; @@ -331,16 +339,6 @@ static int ssd1680_putrun(FAR struct lcd_dev_s *dev, fb_coord_t row, { FAR struct ssd1680_dev_s *priv = (FAR struct ssd1680_dev_s *)dev; - /* TODO Special IOCTL function in lcd_framebuf has to be implemented. - * Those function would call ssd1680_putrun with npixels = 0 - */ - - if (npixels == 0) - { - ssd1680_redraw_display(priv); - return OK; - } - uint8_t *dst = priv->shadow_fb + row * SSD1680_DEV_ROWSIZE + (col >> SSD1680_PDF); @@ -350,17 +348,6 @@ static int ssd1680_putrun(FAR struct lcd_dev_s *dev, fb_coord_t row, bitscpy_ds(dst, dst_start_bitshift, buffer, npixels); - /* Write data to memory of display driver */ - - ssd1680_update_row(priv, row); - - /* TODO Remove it after IOCTL refresh implementation */ - - if (row == SSD1680_DEV_FB_YRES / 2) - { - ssd1680_redraw_display(priv); - } - return OK; } @@ -385,7 +372,6 @@ static int ssd1680_getrun(FAR struct lcd_dev_s *dev, fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, size_t npixels) { - lcdinfo("(%d, %d, %d)\n", row, col, npixels); FAR struct ssd1680_dev_s *priv = (FAR struct ssd1680_dev_s *)dev; bitscpy_ss(buffer, @@ -396,6 +382,12 @@ static int ssd1680_getrun(FAR struct lcd_dev_s *dev, fb_coord_t row, return OK; } +static int ssd1680_redraw(FAR struct lcd_dev_s *dev) +{ + FAR struct ssd1680_dev_s *priv = (FAR struct ssd1680_dev_s *)dev; + return ssd1680_update_all_and_redraw(priv); +} + /**************************************************************************** * Name: ssd1680_getvideoinfo * @@ -529,17 +521,18 @@ static int ssd1680_setpower(FAR struct lcd_dev_s *dev, int power) ret = ssd1680_configuredisplay(priv); if (ret != OK) { + lcderr("Failed to configure display\n"); return ret; } /* Draw the framebuffer */ - ret = ssd1680_update_all(priv); - } - - if (ret < 0) - { - return ret; + ret = ssd1680_update_all_and_redraw(priv); + if (ret != OK) + { + lcderr("Failed to update and redraw\n"); + return ret; + } } priv->on = true; @@ -722,10 +715,11 @@ static int ssd1680_configuredisplay(struct ssd1680_dev_s *priv) } /**************************************************************************** - * Name: ssd1680_update_all + * Name: ssd1680_update_all_and_redraw * * Description: - * Redraw full framebuffer to display + * Copy content of shadow buffer to drivers memory. + * Redraws the display * * Input Parameters: * priv - Reference to private driver structure @@ -738,7 +732,7 @@ static int ssd1680_configuredisplay(struct ssd1680_dev_s *priv) * ****************************************************************************/ -static int ssd1680_update_all(struct ssd1680_dev_s *priv) +static int ssd1680_update_all_and_redraw(struct ssd1680_dev_s *priv) { int row; for (row = 0; row < SSD1680_DEV_FB_YRES; row++) @@ -752,6 +746,8 @@ static int ssd1680_update_all(struct ssd1680_dev_s *priv) static int ssd1680_redraw_display(struct ssd1680_dev_s *priv) { + /* Synchronize shadow buffer with drivers memory */ + int ret; /* Step 15: * Set control register 2. @@ -1312,8 +1308,8 @@ FAR struct lcd_dev_s *ssd1680_initialize(FAR struct spi_dev_s *dev, return &priv->dev; } -FAR void *bitscpy_ds(FAR void *dest, int dest_offset, FAR const void *src, - size_t nbits) +static FAR void *bitscpy_ds(FAR void *dest, int dest_offset, + FAR const void *src, size_t nbits) { FAR unsigned char *pout = (FAR unsigned char *)dest; FAR unsigned char *pin = (FAR unsigned char *)src; @@ -1371,8 +1367,8 @@ FAR void *bitscpy_ds(FAR void *dest, int dest_offset, FAR const void *src, return dest; } -FAR void *bitscpy_ss(FAR void *dest, FAR const void *src, int src_offset, - size_t nbits) +static FAR void *bitscpy_ss(FAR void *dest, FAR const void *src, + int src_offset, size_t nbits) { FAR unsigned char *pout = (FAR unsigned char *)dest; FAR unsigned char *pin = (FAR unsigned char *)src; diff --git a/include/nuttx/lcd/lcd.h b/include/nuttx/lcd/lcd.h index 565768be588..50ce4acf470 100644 --- a/include/nuttx/lcd/lcd.h +++ b/include/nuttx/lcd/lcd.h @@ -123,6 +123,21 @@ struct lcd_planeinfo_s fb_coord_t row_end, fb_coord_t col_start, fb_coord_t col_end, FAR uint8_t *buffer); + /* This method can be used to redraw display's content. + * + * dev - LCD interface to redraw its memory content + * + * NOTE: In case of non e-ink dispalys redrawing is cheap and can be done + * after each memory modification. Redrawing e-ink display is time and + * energy consuming. + * In order to avoid such operation (time and energy consumption) we can + * implement callback function putrun without redrawing the screen. + * Function putrun is called many times unless the function putarea is + * implemented. + */ + + int (*redraw)(FAR struct lcd_dev_s *dev); + /* Plane color characteristics ********************************************/ /* This is working memory allocated by the LCD driver for each LCD device