sunxi: display: Add overscan correction

Add support for making the visual area of the framebuffer smaller and
drawing a black border around it. This is intended for use with
overscanning monitors (esp. with composite video out), to avoid part
of the picture being invisible.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ian Campbell <ijc@hellion.org.uk>
Acked-by: Anatolij Gustschin <agust@denx.de>
master
Hans de Goede 9 years ago
parent c67a8767f5
commit 58332f89b6
  1. 5
      doc/README.video
  2. 51
      drivers/video/sunxi_display.c
  3. 1
      include/configs/sunxi-common.h

@ -68,6 +68,11 @@ The sunxi u-boot driver supports the following video-mode options:
overrides the xres, yres and refresh from the video-mode env. variable. overrides the xres, yres and refresh from the video-mode env. variable.
Defaults to edid=1. Defaults to edid=1.
- overscan_x/overscan_y=<int> - Set x/y overscan value
This configures a black border on the left and right resp. top and bottom
to deal with overscanning displays. Defaults to overscan_x=32 and
overscan_y=20 for composite monitors, 0 for other monitors.
For example to always use the hdmi connector, even if no cable is inserted, For example to always use the hdmi connector, even if no cable is inserted,
using edid info when available and otherwise initalizing it at 1024x768@60Hz, using edid info when available and otherwise initalizing it at 1024x768@60Hz,
use: "setenv video-mode sunxi:1024x768-24@60,monitor=dvi,hpd=0,edid=1". use: "setenv video-mode sunxi:1024x768-24@60,monitor=dvi,hpd=0,edid=1".

@ -19,6 +19,7 @@
#include <fdtdec.h> #include <fdtdec.h>
#include <fdt_support.h> #include <fdt_support.h>
#include <i2c.h> #include <i2c.h>
#include <malloc.h>
#include <video_fb.h> #include <video_fb.h>
#include "videomodes.h" #include "videomodes.h"
#include "hitachi_tx18d42vm_lcd.h" #include "hitachi_tx18d42vm_lcd.h"
@ -51,6 +52,7 @@ struct sunxi_display {
GraphicDevice graphic_device; GraphicDevice graphic_device;
enum sunxi_monitor monitor; enum sunxi_monitor monitor;
unsigned int depth; unsigned int depth;
unsigned int fb_addr;
unsigned int fb_size; unsigned int fb_size;
} sunxi_display; } sunxi_display;
@ -1297,9 +1299,10 @@ void *video_hw_init(void)
#ifdef CONFIG_VIDEO_HDMI #ifdef CONFIG_VIDEO_HDMI
int ret, hpd, hpd_delay, edid; int ret, hpd, hpd_delay, edid;
#endif #endif
int i, overscan_offset, overscan_x, overscan_y;
unsigned int fb_dma_addr;
char mon[16]; char mon[16];
char *lcd_mode = CONFIG_VIDEO_LCD_MODE; char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
int i;
memset(&sunxi_display, 0, sizeof(struct sunxi_display)); memset(&sunxi_display, 0, sizeof(struct sunxi_display));
@ -1310,6 +1313,8 @@ void *video_hw_init(void)
hpd_delay = video_get_option_int(options, "hpd_delay", 500); hpd_delay = video_get_option_int(options, "hpd_delay", 500);
edid = video_get_option_int(options, "edid", 1); edid = video_get_option_int(options, "edid", 1);
#endif #endif
overscan_x = video_get_option_int(options, "overscan_x", -1);
overscan_y = video_get_option_int(options, "overscan_y", -1);
sunxi_display.monitor = sunxi_get_default_mon(true); sunxi_display.monitor = sunxi_get_default_mon(true);
video_get_option_string(options, "monitor", mon, sizeof(mon), video_get_option_string(options, "monitor", mon, sizeof(mon),
sunxi_get_mon_desc(sunxi_display.monitor)); sunxi_get_mon_desc(sunxi_display.monitor));
@ -1386,8 +1391,20 @@ void *video_hw_init(void)
break; break;
} }
/* Yes these defaults are quite high, overscan on composite sucks... */
if (overscan_x == -1)
overscan_x = sunxi_is_composite() ? 32 : 0;
if (overscan_y == -1)
overscan_y = sunxi_is_composite() ? 20 : 0;
sunxi_display.fb_size = sunxi_display.fb_size =
(mode->xres * mode->yres * 4 + 0xfff) & ~0xfff; (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
/* We want to keep the fb_base for simplefb page aligned, where as
* the sunxi dma engines will happily accept an unaligned address. */
if (overscan_offset)
sunxi_display.fb_size += 0x1000;
if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) { if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
printf("Error need %dkB for fb, but only %dkB is reserved\n", printf("Error need %dkB for fb, but only %dkB is reserved\n",
sunxi_display.fb_size >> 10, sunxi_display.fb_size >> 10,
@ -1395,25 +1412,36 @@ void *video_hw_init(void)
return NULL; return NULL;
} }
printf("Setting up a %dx%d%s %s console\n", mode->xres, mode->yres, printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
mode->xres, mode->yres,
(mode->vmode == FB_VMODE_INTERLACED) ? "i" : "", (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
sunxi_get_mon_desc(sunxi_display.monitor)); sunxi_get_mon_desc(sunxi_display.monitor),
overscan_x, overscan_y);
gd->fb_base = gd->bd->bi_dram[0].start + gd->fb_base = gd->bd->bi_dram[0].start +
gd->bd->bi_dram[0].size - sunxi_display.fb_size; gd->bd->bi_dram[0].size - sunxi_display.fb_size;
sunxi_engines_init(); sunxi_engines_init();
sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
sunxi_display.fb_addr = gd->fb_base;
if (overscan_offset) {
fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
flush_cache(gd->fb_base, sunxi_display.fb_size);
}
sunxi_mode_set(mode, fb_dma_addr);
/* /*
* These are the only members of this structure that are used. All the * These are the only members of this structure that are used. All the
* others are driver specific. There is nothing to decribe pitch or * others are driver specific. The pitch is stored in plnSizeX.
* stride, but we are lucky with our hw.
*/ */
graphic_device->frameAdrs = gd->fb_base; graphic_device->frameAdrs = sunxi_display.fb_addr;
graphic_device->gdfIndex = GDF_32BIT_X888RGB; graphic_device->gdfIndex = GDF_32BIT_X888RGB;
graphic_device->gdfBytesPP = 4; graphic_device->gdfBytesPP = 4;
graphic_device->winSizeX = mode->xres; graphic_device->winSizeX = mode->xres - 2 * overscan_x;
graphic_device->winSizeY = mode->yres; graphic_device->winSizeY = mode->yres - 2 * overscan_y;
graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
return graphic_device; return graphic_device;
} }
@ -1490,10 +1518,9 @@ int sunxi_simplefb_setup(void *blob)
return ret; return ret;
} }
ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base, ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
graphic_device->winSizeX, graphic_device->winSizeY, graphic_device->winSizeX, graphic_device->winSizeY,
graphic_device->winSizeX * graphic_device->gdfBytesPP, graphic_device->plnSizeX, "x8r8g8b8");
"x8r8g8b8");
if (ret) if (ret)
eprintf("Cannot setup simplefb: Error setting properties\n"); eprintf("Cannot setup simplefb: Error setting properties\n");

@ -300,6 +300,7 @@ extern int soft_i2c_gpio_scl;
#define CONFIG_VIDEO_LOGO #define CONFIG_VIDEO_LOGO
#define CONFIG_VIDEO_STD_TIMINGS #define CONFIG_VIDEO_STD_TIMINGS
#define CONFIG_I2C_EDID #define CONFIG_I2C_EDID
#define VIDEO_LINE_LEN (pGD->plnSizeX)
/* allow both serial and cfb console. */ /* allow both serial and cfb console. */
#define CONFIG_CONSOLE_MUX #define CONFIG_CONSOLE_MUX

Loading…
Cancel
Save