diff --git a/AUTHORS b/AUTHORS index 810f48d3050..9129bbd2d58 100644 --- a/AUTHORS +++ b/AUTHORS @@ -20,6 +20,9 @@ Daniel De Matteis - - Blackberry 10/Playbook port - iOS port patches +Tobias Jakobi - + - OMAP graphics driver + Jason Fetters - - Phoenix Java frontend - Android port patches diff --git a/Makefile b/Makefile index 184f81b194a..0096d7ec308 100644 --- a/Makefile +++ b/Makefile @@ -186,6 +186,10 @@ ifeq ($(HAVE_SDL), 1) LIBS += $(SDL_LIBS) endif +ifeq ($(HAVE_OMAP), 1) + OBJ += gfx/omap_gfx.o gfx/fbdev.o +endif + ifeq ($(HAVE_OPENGL), 1) OBJ += gfx/gl.o \ gfx/gfx_context.o \ diff --git a/config.def.h b/config.def.h index 0d647ad290a..6dcc5238b57 100644 --- a/config.def.h +++ b/config.def.h @@ -44,6 +44,7 @@ enum VIDEO_D3D9, VIDEO_VG, VIDEO_NULL, + VIDEO_OMAP, AUDIO_RSOUND, AUDIO_OSS, diff --git a/driver.c b/driver.c index 790e23e1f6d..44ae437dc8e 100644 --- a/driver.c +++ b/driver.c @@ -122,6 +122,9 @@ static const video_driver_t *video_drivers[] = { #ifdef HAVE_NULLVIDEO &video_null, #endif +#ifdef HAVE_OMAP + &video_omap, +#endif }; static const input_driver_t *input_drivers[] = { diff --git a/driver.h b/driver.h index 975ea7f29f7..944b51889c0 100644 --- a/driver.h +++ b/driver.h @@ -516,6 +516,7 @@ extern const video_driver_t video_xdk_d3d; extern const video_driver_t video_sdl; extern const video_driver_t video_vg; extern const video_driver_t video_null; +extern const video_driver_t video_omap; extern const input_driver_t input_android; extern const input_driver_t input_sdl; extern const input_driver_t input_dinput; diff --git a/gfx/fbdev.c b/gfx/fbdev.c new file mode 100644 index 00000000000..57f56b11976 --- /dev/null +++ b/gfx/fbdev.c @@ -0,0 +1,319 @@ +/* + * (C) GraÅžvydas "notaz" Ignotas, 2009-2010 + * + * This work is licensed under the terms of any of these licenses + * (at your option): + * - GNU GPL, version 2 or later. + * - GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fbdev.h" + +#define PFX "fbdev: " + +struct vout_fbdev { + int fd; + void *mem; + size_t mem_size; + struct fb_var_screeninfo fbvar_old; + struct fb_var_screeninfo fbvar_new; + int buffer_write; + int fb_size; + int buffer_count; + int top_border, bottom_border; + void *mem_saved; + size_t mem_saved_size; +}; + +void *vout_fbdev_flip(struct vout_fbdev *fbdev) +{ + int draw_buf; + + if (fbdev->buffer_count < 2) + return fbdev->mem; + + draw_buf = fbdev->buffer_write; + fbdev->buffer_write++; + if (fbdev->buffer_write >= fbdev->buffer_count) + fbdev->buffer_write = 0; + + fbdev->fbvar_new.yoffset = + (fbdev->top_border + fbdev->fbvar_new.yres + fbdev->bottom_border) * draw_buf + + fbdev->top_border; + + ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new); + + return (char *)fbdev->mem + fbdev->fb_size * fbdev->buffer_write; +} + +void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev) +{ + int arg = 0; + ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg); +} + +/* it is recommended to call vout_fbdev_clear() before this */ +void *vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h, int bpp, + int left_border, int right_border, int top_border, int bottom_border, int buffer_cnt) +{ + int w_total = left_border + w + right_border; + int h_total = top_border + h + bottom_border; + size_t mem_size; + int ret; + + // unblank to be sure the mode is really accepted + ioctl(fbdev->fd, FBIOBLANK, FB_BLANK_UNBLANK); + + if (fbdev->fbvar_new.bits_per_pixel != bpp || + fbdev->fbvar_new.xres != w || + fbdev->fbvar_new.yres != h || + fbdev->fbvar_new.xres_virtual != w_total|| + fbdev->fbvar_new.yres_virtual < h_total || + fbdev->fbvar_new.xoffset != left_border || + fbdev->buffer_count != buffer_cnt) + { + if (fbdev->fbvar_new.bits_per_pixel != bpp || + w != fbdev->fbvar_new.xres || h != fbdev->fbvar_new.yres) + printf(PFX "switching to %dx%d@%d\n", w, h, bpp); + + fbdev->fbvar_new.xres = w; + fbdev->fbvar_new.yres = h; + fbdev->fbvar_new.xres_virtual = w_total; + fbdev->fbvar_new.yres_virtual = h_total * buffer_cnt; + fbdev->fbvar_new.xoffset = left_border; + fbdev->fbvar_new.yoffset = top_border; + fbdev->fbvar_new.bits_per_pixel = bpp; + fbdev->fbvar_new.nonstd = 0; // can set YUV here on omapfb + fbdev->buffer_count = buffer_cnt; + fbdev->buffer_write = buffer_cnt > 1 ? 1 : 0; + + // seems to help a bit to avoid glitches + vout_fbdev_wait_vsync(fbdev); + + ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new); + if (ret == -1) { + // retry with no multibuffering + fbdev->fbvar_new.yres_virtual = h_total; + ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new); + if (ret == -1) { + perror(PFX "FBIOPUT_VSCREENINFO ioctl"); + return NULL; + } + fbdev->buffer_count = 1; + fbdev->buffer_write = 0; + fprintf(stderr, PFX "Warning: failed to increase virtual resolution, " + "multibuffering disabled\n"); + } + + } + + fbdev->fb_size = w_total * h_total * bpp / 8; + fbdev->top_border = top_border; + fbdev->bottom_border = bottom_border; + + mem_size = fbdev->fb_size * fbdev->buffer_count; + if (fbdev->mem_size >= mem_size) + goto out; + + if (fbdev->mem != NULL) + munmap(fbdev->mem, fbdev->mem_size); + + fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0); + if (fbdev->mem == MAP_FAILED && fbdev->buffer_count > 1) { + fprintf(stderr, PFX "Warning: can't map %zd bytes, doublebuffering disabled\n", mem_size); + fbdev->buffer_count = 1; + fbdev->buffer_write = 0; + mem_size = fbdev->fb_size; + fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0); + } + if (fbdev->mem == MAP_FAILED) { + fbdev->mem = NULL; + fbdev->mem_size = 0; + perror(PFX "mmap framebuffer"); + return NULL; + } + + fbdev->mem_size = mem_size; + +out: + return (char *)fbdev->mem + fbdev->fb_size * fbdev->buffer_write; +} + +void vout_fbdev_clear(struct vout_fbdev *fbdev) +{ + memset(fbdev->mem, 0, fbdev->mem_size); +} + +void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count) +{ + int stride = fbdev->fbvar_new.xres_virtual * fbdev->fbvar_new.bits_per_pixel / 8; + int i; + + if (y + count > fbdev->top_border + fbdev->fbvar_new.yres) + count = fbdev->top_border + fbdev->fbvar_new.yres - y; + + if (y >= 0 && count > 0) + for (i = 0; i < fbdev->buffer_count; i++) + memset((char *)fbdev->mem + fbdev->fb_size * i + y * stride, 0, stride * count); +} + +void *vout_fbdev_get_active_mem(struct vout_fbdev *fbdev) +{ + int i; + + i = fbdev->buffer_write - 1; + if (i < 0) + i = fbdev->buffer_count - 1; + + return (char *)fbdev->mem + fbdev->fb_size * i; +} + +int vout_fbdev_get_fd(struct vout_fbdev *fbdev) +{ + if (fbdev == NULL) return -1; + + return fbdev->fd; +} + +struct vout_fbdev *vout_fbdev_preinit(int fbdev_fd) +{ + struct vout_fbdev *fbdev; + + fbdev = calloc(1, sizeof(*fbdev)); + if (fbdev == NULL) return NULL; + + fbdev->fd = fbdev_fd; + + return fbdev; +} + +int vout_fbdev_init(struct vout_fbdev *fbdev, int *w, int *h, int bpp, int buffer_cnt) +{ + int req_w, req_h; + void *pret; + int ret; + + ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old); + if (ret == -1) { + perror(PFX "FBIOGET_VSCREENINFO ioctl"); + return -1; + } + + fbdev->fbvar_new = fbdev->fbvar_old; + + req_w = fbdev->fbvar_new.xres; + if (*w != 0) + req_w = *w; + req_h = fbdev->fbvar_new.yres; + if (*h != 0) + req_h = *h; + + pret = vout_fbdev_resize(fbdev, req_w, req_h, bpp, 0, 0, 0, 0, buffer_cnt); + if (pret == NULL) + return -1; + + printf(PFX "%ix%i@%d\n", fbdev->fbvar_new.xres, + fbdev->fbvar_new.yres, fbdev->fbvar_new.bits_per_pixel); + *w = fbdev->fbvar_new.xres; + *h = fbdev->fbvar_new.yres; + + memset(fbdev->mem, 0, fbdev->mem_size); + + // some checks + ret = 0; + ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret); + if (ret != 0) + fprintf(stderr, PFX "Warning: vsync doesn't seem to be supported\n"); + + if (fbdev->buffer_count > 1) { + fbdev->buffer_write = 0; + fbdev->fbvar_new.yoffset = fbdev->fbvar_new.yres * (fbdev->buffer_count - 1); + ret = ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new); + if (ret != 0) { + fbdev->buffer_count = 1; + fprintf(stderr, PFX "Warning: can't pan display, doublebuffering disabled\n"); + } + } + + printf("fbdev initialized.\n"); + return 0; +} + +void vout_fbdev_release(struct vout_fbdev *fbdev) +{ + if (fbdev->mem == NULL) return; + + ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_old); + if (fbdev->mem != MAP_FAILED) + munmap(fbdev->mem, fbdev->mem_size); + fbdev->mem = NULL; +} + +int vout_fbdev_save(struct vout_fbdev *fbdev) +{ + void *tmp; + + if (fbdev == NULL || fbdev->mem == NULL || fbdev->mem == MAP_FAILED) { + fprintf(stderr, PFX "bad args for save\n"); + return -1; + } + + if (fbdev->mem_saved_size < fbdev->mem_size) { + tmp = realloc(fbdev->mem_saved, fbdev->mem_size); + if (tmp == NULL) + return -1; + fbdev->mem_saved = tmp; + } + memcpy(fbdev->mem_saved, fbdev->mem, fbdev->mem_size); + fbdev->mem_saved_size = fbdev->mem_size; + + vout_fbdev_release(fbdev); + return 0; +} + +int vout_fbdev_restore(struct vout_fbdev *fbdev) +{ + int ret; + + if (fbdev == NULL || fbdev->mem != NULL) { + fprintf(stderr, PFX "bad args/state for restore\n"); + return -1; + } + + fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0); + if (fbdev->mem == MAP_FAILED) { + perror(PFX "restore: memory restore failed"); + return -1; + } + memcpy(fbdev->mem, fbdev->mem_saved, fbdev->mem_size); + + ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new); + if (ret == -1) { + perror(PFX "restore: FBIOPUT_VSCREENINFO"); + return -1; + } + + return 0; +} + +void vout_fbdev_teardown(struct vout_fbdev* fbdev) +{ + if (fbdev == NULL) return; + + if (fbdev->fd >= 0) close(fbdev->fd); + fbdev->fd = -1; + free(fbdev); +} diff --git a/gfx/fbdev.h b/gfx/fbdev.h new file mode 100644 index 00000000000..a821cbee444 --- /dev/null +++ b/gfx/fbdev.h @@ -0,0 +1,24 @@ +#ifndef _FBDEV_H +#define _FBDEV_H + +struct vout_fbdev; + +struct vout_fbdev *vout_fbdev_preinit(int fbdev_fd); +int vout_fbdev_init(struct vout_fbdev *fbdev, int *w, int *h, int bpp, int buffer_cnt); + +void *vout_fbdev_flip(struct vout_fbdev *fbdev); +void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev); +void *vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h, int bpp, + int left_border, int right_border, int top_border, int bottom_border, + int buffer_count); +void vout_fbdev_clear(struct vout_fbdev *fbdev); +void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count); +int vout_fbdev_get_fd(struct vout_fbdev *fbdev); +void *vout_fbdev_get_active_mem(struct vout_fbdev *fbdev); +int vout_fbdev_save(struct vout_fbdev *fbdev); +int vout_fbdev_restore(struct vout_fbdev *fbdev); + +void vout_fbdev_release(struct vout_fbdev *fbdev); +void vout_fbdev_teardown(struct vout_fbdev* fbdev); + +#endif diff --git a/gfx/omap_gfx.c b/gfx/omap_gfx.c new file mode 100644 index 00000000000..147c465bb1a --- /dev/null +++ b/gfx/omap_gfx.c @@ -0,0 +1,860 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2013 - Hans-Kristian Arntzen + * Copyright (C) 2013 - Tobias Jakobi + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "../driver.h" +#include +#include +#include "../general.h" +#include "scaler/scaler.h" +#include "gfx_common.h" +#include "gfx_context.h" +#include "fonts/fonts.h" + +#include +#include +#include +#include +#include +#include + +#include "omapfb.h" +#include "fbdev.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) ) + +enum omap_layer_size { + OMAP_LAYER_UNSCALED, + OMAP_LAYER_FULLSCREEN, + OMAP_LAYER_SCALED, + OMAP_LAYER_PIXELPERFECT, + OMAP_LAYER_CUSTOM +}; + +typedef struct omapfb_state { + struct omapfb_plane_info pi; + struct omapfb_mem_info mi; + struct omapfb_plane_info pi_old; + struct omapfb_mem_info mi_old; +} omapfb_state_t; + +typedef struct osdl_data +{ + struct vout_fbdev *fbdev; + void *front_buffer; + void *saved_layer; + /* physical/native screen size */ + int phys_w, phys_h; + /* layer */ + int layer_x, layer_y, layer_w, layer_h; + enum omap_layer_size layer_size; + bool vsync; +} osdl_data_t; + +static const char *get_fb_device(void) +{ + const char *fbname = getenv("OMAP_FBDEV"); + if (fbname == NULL) + fbname = "/dev/fb1"; + + return fbname; +} + +static int osdl_setup_omapfb(struct omapfb_state *ostate, int fd, int enabled, + int x, int y, int w, int h, int mem, int buffer_count) +{ + struct omapfb_plane_info pi; + struct omapfb_mem_info mi; + unsigned int size_cur; + int ret; + + RARCH_LOG("in osdl_setup_omapfb\n"); + + memset(&pi, 0, sizeof(pi)); + memset(&mi, 0, sizeof(mi)); + + ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi); + if (ret != 0) { + RARCH_ERR("omapfb: QUERY_PLANE\n"); + return -1; + } + + ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi); + if (ret != 0) { + RARCH_ERR("omapfb: QUERY_MEM\n"); + return -1; + } + size_cur = mi.size; + + /* must disable when changing stuff */ + if (pi.enabled) { + pi.enabled = 0; + ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi); + if (ret != 0) + RARCH_ERR("SETUP_PLANE\n"); + } + + /* if needed increase memory allocation */ + if (size_cur < mem * buffer_count) { + mi.size = mem * buffer_count; + ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi); + if (ret != 0) { + RARCH_ERR("omapfb: SETUP_MEM\n"); + RARCH_ERR("Failed to allocate %d bytes of vram.\n", mem * buffer_count); + return -1; + } + } + + pi.pos_x = x; + pi.pos_y = y; + pi.out_width = w; + pi.out_height = h; + pi.enabled = enabled; + + ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi); + if (ret != 0) { + RARCH_ERR("omapfb: SETUP_PLANE (%d %d %d %d)\n", x, y, w, h); + return -1; + } + + ostate->pi = pi; + ostate->mi = mi; + + return 0; +} + +static int osdl_setup_omapfb_enable(struct omapfb_state *ostate, + int fd, int enabled) +{ + int ret; + + ostate->pi.enabled = enabled; + ret = ioctl(fd, OMAPFB_SETUP_PLANE, &ostate->pi); + if (ret != 0) RARCH_ERR("omapfb: SETUP_PLANE\n"); + + return ret; +} + +static int read_sysfs(const char *fname, char *buff, size_t size) +{ + FILE *f; + int ret; + + f = fopen(fname, "r"); + if (f == NULL) { + RARCH_ERR("video_omap: open %s failed\n", fname); + return -1; + } + + ret = fread(buff, 1, size - 1, f); + fclose(f); + if (ret <= 0) { + RARCH_ERR("video_omap: read %s failed\n", fname); + return -1; + } + + buff[ret] = 0; + for (ret--; ret >= 0 && isspace(buff[ret]); ret--) + buff[ret] = 0; + + return 0; +} + +static int osdl_fbdev_init(struct osdl_data *pdata, int fd) +{ + pdata->fbdev = vout_fbdev_preinit(fd); + + if (pdata->fbdev == NULL) return -1; + + return 0; +} + +static int osdl_video_detect_screen(struct osdl_data *pdata, const char *fbname) +{ + int fb_id, overlay_id = -1, display_id = -1; + char buff[64], manager_name[64], display_name[64]; + struct stat status; + int fd, i, ret; + int w, h; + FILE *f; + + pdata->phys_w = pdata->phys_h = 0; + + /* Figure out screen resolution, we need to know default + * resolution for centering stuff. + * The only way to achieve this seems to be walking some sysfs files.. */ + ret = stat(fbname, &status); + if (ret != 0) { + RARCH_ERR("video_omap: can't stat %s\n", fbname); + return -1; + } + fb_id = minor(status.st_rdev); + + snprintf(buff, sizeof(buff), "/sys/class/graphics/fb%d/overlays", fb_id); + f = fopen(buff, "r"); + if (f == NULL) { + RARCH_ERR("video_omap: can't open %s\n", buff); + return -1; + } + + ret = fscanf(f, "%d", &overlay_id); + fclose(f); + if (ret != 1) { + RARCH_ERR("video_omap: can't parse %s\n", buff); + return -1; + } + + snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/overlay%d/manager", overlay_id); + ret = read_sysfs(buff, manager_name, sizeof(manager_name)); + if (ret < 0) { + RARCH_ERR("video_omap: can't read manager name\n"); + return -1; + } + + for (i = 0; ; i++) { + snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/manager%d/name", i); + ret = read_sysfs(buff, buff, sizeof(buff)); + if (ret < 0) break; + + if (strcmp(manager_name, buff) == 0) { + snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/manager%d/display", i); + ret = read_sysfs(buff, display_name, sizeof(display_name)); + + if (ret < 0) { + RARCH_ERR("video_omap: can't read display name\n"); + return -1; + } + + break; + } + } + + if (ret < 0) { + RARCH_ERR("video_omap: couldn't find manager\n"); + return -1; + } + + for (i = 0; ; i++) { + snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/display%d/name", i); + ret = read_sysfs(buff, buff, sizeof(buff)); + if (ret < 0) break; + + if (strcmp(display_name, buff) == 0) { + display_id = i; + break; + } + } + + if (display_id < 0) { + RARCH_ERR("video_omap: couldn't find display\n"); + return -1; + } + + snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/display%d/timings", display_id); + f = fopen(buff, "r"); + if (f == NULL) { + RARCH_ERR("video_omap: can't open %s\n", buff); + return -1; + } + + ret = fscanf(f, "%*d,%d/%*d/%*d/%*d,%d/%*d/%*d/%*d", &w, &h); + fclose(f); + if (ret != 2) { + RARCH_ERR("video_omap: can't parse %s (%d)\n", buff, ret); + return -1; + } + + RARCH_LOG("video_omap: detected %dx%d '%s' (%d) display attached to fb %d and overlay %d\n", + w, h, display_name, display_id, fb_id, overlay_id); + + pdata->phys_w = w; + pdata->phys_h = h; + + return 0; +} + +static int osdl_init(struct osdl_data *pdata) +{ + const char *fbname; + int ret, fb; + + fbname = get_fb_device(); + ret = osdl_video_detect_screen(pdata, fbname); + + if (ret != 0) return ret; + + fb = open(fbname, O_RDWR); + if (fb == -1) { + RARCH_ERR("video_omap: can't open fb device\n"); + return -1; + } + + ret = osdl_fbdev_init(pdata, fb); + + return ret; +} + +static int osdl_setup_omap_layer(struct osdl_data *pdata, int width, + int height, int bpp, int buffer_count) +{ + int x = 0, y = 0, w = width, h = height; /* layer size and pos */ + int screen_w = w, screen_h = h; + int tmp_w, tmp_h; + const char *tmp; + int retval = -1; + int ret; + + RARCH_LOG("in osdl_setup_omap_layer\n"); + + const int fd = vout_fbdev_get_fd(pdata->fbdev); + + if (fd == -1) { + RARCH_ERR("got no fbdev fd\n"); + } + + pdata->layer_x = pdata->layer_y = pdata->layer_w = pdata->layer_h = 0; + + if (pdata->phys_w != 0) + screen_w = pdata->phys_w; + if (pdata->phys_h != 0) + screen_h = pdata->phys_h; + + /* FIXME: assuming layer doesn't change here */ + if (pdata->saved_layer == NULL) { + struct omapfb_state *slayer; + slayer = calloc(1, sizeof(*slayer)); + if (slayer == NULL) + goto out; + + ret = ioctl(fd, OMAPFB_QUERY_PLANE, &slayer->pi_old); + if (ret != 0) { + RARCH_ERR("omapfb: QUERY_PLANE\n"); + goto out; + } + + ret = ioctl(fd, OMAPFB_QUERY_MEM, &slayer->mi_old); + if (ret != 0) { + RARCH_ERR("omapfb: QUERY_MEM\n"); + goto out; + } + + pdata->saved_layer = slayer; + } + + switch (pdata->layer_size) { + case OMAP_LAYER_FULLSCREEN: + { + w = screen_w, h = screen_h; + } + break; + + case OMAP_LAYER_SCALED: + { + const float factor = MIN(((float)screen_w) / width, ((float)screen_h) / height); + w = (int)(factor*width), h = (int)(factor*height); + } + break; + + case OMAP_LAYER_PIXELPERFECT: + { + const float factor = MIN(((float)screen_w) / width, ((float)screen_h) / height); + w = ((int)factor) * width, h = ((int)factor) * height; + /* factor < 1.f => 0x0 layer, so fall back to 'scaled' */ + if (!w || !h) { + w = (int)(factor * width), h = (int)(factor * height); + } + } + break; + + // TODO: use g_settings.video.fullscreen_x for this! + case OMAP_LAYER_CUSTOM: + { + tmp = getenv("OMAP_LAYER_SIZE"); + + if (tmp != NULL && sscanf(tmp, "%dx%d", &tmp_w, &tmp_h) == 2) { + w = tmp_w, h = tmp_h; + } else { + RARCH_ERR("omap_video: custom layer size specified incorrectly, " + "should be like 800x480\n"); + } + } + break; + + default: + break; + } + + /* the layer can't be set larger than screen */ + tmp_w = w, tmp_h = h; + if (w > screen_w) w = screen_w; + if (h > screen_h) h = screen_h; + if (w != tmp_w || h != tmp_h) + RARCH_LOG("omap_video: layer resized %dx%d -> %dx%d to fit screen\n", tmp_w, tmp_h, w, h); + + x = screen_w / 2 - w / 2; + y = screen_h / 2 - h / 2; + ret = osdl_setup_omapfb(pdata->saved_layer, fd, 0, x, y, w, h, + width * height * ((bpp + 7) / 8), buffer_count); + + if (ret == 0) { + pdata->layer_x = x; + pdata->layer_y = y; + pdata->layer_w = w; + pdata->layer_h = h; + } + + retval = ret; + +out: + return retval; +} + +static void *osdl_video_flip(struct osdl_data *pdata) +{ + void *ret; + + if (pdata->fbdev == NULL) + return NULL; + + ret = vout_fbdev_flip(pdata->fbdev); + + if (pdata->vsync) + vout_fbdev_wait_vsync(pdata->fbdev); + + return ret; +} + +void osdl_video_finish(struct osdl_data *pdata) +{ + vout_fbdev_release(pdata->fbdev); + + /* restore the OMAP layer */ + if (pdata->saved_layer != NULL) { + struct omapfb_state *slayer = pdata->saved_layer; + int fd = vout_fbdev_get_fd(pdata->fbdev); + + int enabled = slayer->pi_old.enabled; + + /* be sure to disable while setting up */ + slayer->pi_old.enabled = 0; + ioctl(fd, OMAPFB_SETUP_PLANE, &slayer->pi_old); + ioctl(fd, OMAPFB_SETUP_MEM, &slayer->mi_old); + if (enabled) { + slayer->pi_old.enabled = enabled; + ioctl(fd, OMAPFB_SETUP_PLANE, &slayer->pi_old); + } + + free(slayer); + pdata->saved_layer = NULL; + } + + vout_fbdev_teardown(pdata->fbdev); + pdata->fbdev = NULL; +} + +static void *osdl_video_set_mode(struct osdl_data *pdata, int width, + int height, int bpp) +{ + int num_buffers; + void *result; + int ret; + + RARCH_LOG("osdl: setting video mode\n"); + + vout_fbdev_release(pdata->fbdev); + + /* always use triple buffering for reduced chance of tearing */ + num_buffers = 3; + + RARCH_LOG("width = %d, height = %d\n", width, height); + + ret = osdl_setup_omap_layer(pdata, width, height, bpp, num_buffers); + if (ret < 0) + goto fail; + + ret = vout_fbdev_init(pdata->fbdev, &width, &height, bpp, num_buffers); + if (ret == -1) + goto fail; + + result = osdl_video_flip(pdata); + if (result == NULL) + goto fail; + + ret = osdl_setup_omapfb_enable(pdata->saved_layer, + vout_fbdev_get_fd(pdata->fbdev), 1); + if (ret != 0) { + RARCH_ERR("video_omap: layer enable failed\n"); + goto fail; + } + + return result; + +fail: + osdl_video_finish(pdata); + return NULL; +} + +void *osdl_video_get_active_buffer(struct osdl_data *pdata) +{ + if (pdata->fbdev == NULL) return NULL; + + return vout_fbdev_get_active_mem(pdata->fbdev); +} + +int osdl_video_pause(struct osdl_data *pdata, int is_pause) +{ + struct omapfb_state *state = pdata->saved_layer; + struct omapfb_plane_info pi; + struct omapfb_mem_info mi; + int enabled; + int fd = -1; + int ret; + + if (pdata->fbdev != NULL) + fd = vout_fbdev_get_fd(pdata->fbdev); + if (fd == -1) { + RARCH_ERR("bad fd %d", fd); + return -1; + } + if (state == NULL) { + RARCH_ERR("missing layer state\n"); + return -1; + } + + if (is_pause) { + ret = vout_fbdev_save(pdata->fbdev); + if (ret != 0) + return ret; + pi = state->pi_old; + mi = state->mi_old; + enabled = pi.enabled; + } else { + pi = state->pi; + mi = state->mi; + enabled = 1; + } + pi.enabled = 0; + ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi); + if (ret != 0) { + RARCH_ERR("SETUP_PLANE"); + return -1; + } + + ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi); + if (ret != 0) + RARCH_ERR("SETUP_MEM"); + + if (!is_pause) { + ret = vout_fbdev_restore(pdata->fbdev); + if (ret != 0) { + RARCH_ERR("fbdev_restore failed\n"); + return ret; + } + } + + if (enabled) { + pi.enabled = 1; + ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi); + if (ret != 0) { + RARCH_ERR("SETUP_PLANE"); + return -1; + } + } + + return 0; +} + + +typedef struct omap_video +{ + struct osdl_data osdl; + void* pixels; + + void *font; + const font_renderer_driver_t *font_driver; + uint8_t font_r; + uint8_t font_g; + uint8_t font_b; + + /* current settings */ + unsigned width; + unsigned height; + unsigned bytes_per_pixel; +} omap_video_t; + +static void omap_gfx_free(void *data) +{ + omap_video_t *vid = (omap_video_t*)data; + if (!vid) return; + + osdl_video_finish(&vid->osdl); + + if (vid->font) vid->font_driver->free(vid->font); + + free(vid); +} + +static void omap_init_font(omap_video_t *vid, const char *font_path, unsigned font_size) +{ + if (!g_settings.video.font_enable) return; + + if (font_renderer_create_default(&vid->font_driver, &vid->font)) { + int r = g_settings.video.msg_color_r * 255; + int g = g_settings.video.msg_color_g * 255; + int b = g_settings.video.msg_color_b * 255; + + r = r < 0 ? 0 : (r > 255 ? 255 : r); + g = g < 0 ? 0 : (g > 255 ? 255 : g); + b = b < 0 ? 0 : (b > 255 ? 255 : b); + + vid->font_r = r; + vid->font_g = g; + vid->font_b = b; + } else { + RARCH_LOG("Could not initialize fonts.\n"); + } +} + +/*static void omap_render_msg(omap_video_t *vid, SDL_Surface *buffer, + const char *msg, unsigned width, unsigned height, const SDL_PixelFormat *fmt) +{ + if (!vid->font) return; + + struct font_output_list out; + vid->font_driver->render_msg(vid->font, msg, &out); + struct font_output *head = out.head; + + int msg_base_x = g_settings.video.msg_pos_x * width; + int msg_base_y = (1.0 - g_settings.video.msg_pos_y) * height; + + unsigned rshift = fmt->Rshift; + unsigned gshift = fmt->Gshift; + unsigned bshift = fmt->Bshift; + + for (; head; head = head->next) + { + int base_x = msg_base_x + head->off_x; + int base_y = msg_base_y - head->off_y - head->height; + + int glyph_width = head->width; + int glyph_height = head->height; + + const uint8_t *src = head->output; + + if (base_x < 0) + { + src -= base_x; + glyph_width += base_x; + base_x = 0; + } + + if (base_y < 0) + { + src -= base_y * (int)head->pitch; + glyph_height += base_y; + base_y = 0; + } + + int max_width = width - base_x; + int max_height = height - base_y; + + if (max_width <= 0 || max_height <= 0) + continue; + + if (glyph_width > max_width) + glyph_width = max_width; + if (glyph_height > max_height) + glyph_height = max_height; + + uint32_t *out = (uint32_t*)buffer->pixels + base_y * (buffer->pitch >> 2) + base_x; + + for (int y = 0; y < glyph_height; y++, src += head->pitch, out += buffer->pitch >> 2) + { + for (int x = 0; x < glyph_width; x++) + { + unsigned blend = src[x]; + unsigned out_pix = out[x]; + unsigned r = (out_pix >> rshift) & 0xff; + unsigned g = (out_pix >> gshift) & 0xff; + unsigned b = (out_pix >> bshift) & 0xff; + + unsigned out_r = (r * (256 - blend) + vid->font_r * blend) >> 8; + unsigned out_g = (g * (256 - blend) + vid->font_g * blend) >> 8; + unsigned out_b = (b * (256 - blend) + vid->font_b * blend) >> 8; + out[x] = (out_r << rshift) | (out_g << gshift) | (out_b << bshift); + } + } + } + + vid->font_driver->free_output(vid->font, &out); +}*/ + +static void *omap_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data) +{ + void* ret = NULL; + + omap_video_t *vid = (omap_video_t*)calloc(1, sizeof(*vid)); + if (!vid) return NULL; + + if (osdl_init(&vid->osdl) != 0) { + goto fail; + } + + RARCH_LOG("Detecting native resolution %ux%u.\n", + vid->osdl.phys_w, vid->osdl.phys_h); + + if (!video->fullscreen) + RARCH_LOG("Creating unscaled output @ %ux%u.\n", video->width, video->height); + + if (video->fullscreen) { + vid->osdl.layer_size = video->force_aspect ? + OMAP_LAYER_SCALED : OMAP_LAYER_FULLSCREEN; + } else { + vid->osdl.layer_size = OMAP_LAYER_UNSCALED; + } + + vid->osdl.vsync = video->vsync; + vid->bytes_per_pixel = video->rgb32 ? 4 : 2; + + // TODO: use geom from geom->base_width / geom->base_height + // const struct retro_game_geometry *geom = &g_extern.system.av_info.geometry; + + RARCH_LOG("calling osdl_video_set_mode with width = %d, height = %d\n", video->width, video->height); + + // TODO: handle width = height = 0 + + ret = osdl_video_set_mode(&vid->osdl, video->width, video->height, + vid->bytes_per_pixel * 8); + + if (ret == NULL) { + goto fail; + } + + vid->width = video->width; + vid->height = video->height; + vid->pixels = ret; + + if (input && input_data) { + *input = NULL; + //input_data = NULL; + } + + omap_init_font(vid, g_settings.video.font_path, g_settings.video.font_size); + + return vid; + +fail: + RARCH_ERR("Failed to init OMAP video output.\n"); + omap_gfx_free(vid); + return NULL; +} + +static void omap_blit_frame(omap_video_t *video, const void *src, + unsigned src_pitch) +{ + unsigned i; + const unsigned pitch = video->width * video->bytes_per_pixel; + + RARCH_LOG("in omap_blit_frame\n"); + + for (i = 0; i < video->height; i++) { + memcpy(video->pixels + pitch * i, src + src_pitch * i, pitch); + } +} + +static bool omap_gfx_frame(void *data, const void *frame, unsigned width, + unsigned height, unsigned pitch, const char *msg) +{ + if (!frame) return true; + + omap_video_t *vid = (omap_video_t*)data; + + if (width != vid->width || height != vid->height) { + void* pixels; + + RARCH_LOG("Dimensions changed -> OMAP reinit\n"); + pixels = osdl_video_set_mode(&vid->osdl, width, height, + vid->bytes_per_pixel * 8); + + if (pixels == NULL) { + RARCH_ERR("OMAP reinit failed\n"); + return false; + } + + vid->width = width; + vid->height = height; + } + + omap_blit_frame(vid, frame, pitch); + + /*if (msg) + omap_render_msg(vid, vid->screen, msg, vid->screen->w, vid->screen->h, vid->screen->format);*/ + + vid->pixels = osdl_video_flip(&vid->osdl); + g_extern.frame_count++; + + return true; +} + +static void omap_gfx_set_nonblock_state(void *data, bool state) +{ + (void)data; /* NOP */ + (void)state; +} + +static bool omap_gfx_alive(void *data) +{ + (void)data; + return true; /* always alive */ +} + +static bool omap_gfx_focus(void *data) +{ + (void)data; + return true; /* fb device always has focus */ +} + +static void omap_gfx_viewport_info(void *data, struct rarch_viewport *vp) +{ + omap_video_t *vid = (omap_video_t*)data; + vp->x = vp->y = 0; + + // TODO: maybe set full_width,height to phys_w,h + vp->width = vp->full_width = vid->width; + vp->height = vp->full_height = vid->height; +} + +const video_driver_t video_omap = { + omap_gfx_init, + omap_gfx_frame, + omap_gfx_set_nonblock_state, + omap_gfx_alive, + omap_gfx_focus, + NULL, + omap_gfx_free, + "omap", + +#ifdef HAVE_RGUI + NULL, + NULL, +#endif + + NULL, + omap_gfx_viewport_info, +}; diff --git a/gfx/omapfb.h b/gfx/omapfb.h new file mode 100644 index 00000000000..f156e3a14d4 --- /dev/null +++ b/gfx/omapfb.h @@ -0,0 +1,427 @@ +/* + * File: arch/arm/plat-omap/include/mach/omapfb.h + * + * Framebuffer driver for TI OMAP boards + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OMAPFB_H +#define __OMAPFB_H + +#include +#include + +/* IOCTL commands. */ + +#define OMAP_IOW(num, dtype) _IOW('O', num, dtype) +#define OMAP_IOR(num, dtype) _IOR('O', num, dtype) +#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype) +#define OMAP_IO(num) _IO('O', num) + +#define OMAPFB_MIRROR OMAP_IOW(31, int) +#define OMAPFB_SYNC_GFX OMAP_IO(37) +#define OMAPFB_VSYNC OMAP_IO(38) +#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int) +#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps) +#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int) +#define OMAPFB_LCD_TEST OMAP_IOW(45, int) +#define OMAPFB_CTRL_TEST OMAP_IOW(46, int) +#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old) +#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key) +#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key) +#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info) +#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info) +#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window) +#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info) +#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info) +#define OMAPFB_WAITFORVSYNC OMAP_IO(57) +#define OMAPFB_MEMORY_READ OMAP_IOR(58, struct omapfb_memory_read) + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) +#endif + +#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff +#define OMAPFB_CAPS_LCDC_MASK 0x00fff000 +#define OMAPFB_CAPS_PANEL_MASK 0xff000000 + +#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000 +#define OMAPFB_CAPS_TEARSYNC 0x00002000 +#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000 +#define OMAPFB_CAPS_PLANE_SCALE 0x00008000 +#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000 +#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000 +#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000 +#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000 +#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000 + +/* Values from DSP must map to lower 16-bits */ +#define OMAPFB_FORMAT_MASK 0x00ff +#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100 +#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200 +#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400 +#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800 +#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000 + +#define OMAPFB_EVENT_READY 1 +#define OMAPFB_EVENT_DISABLED 2 + +#define OMAPFB_MEMTYPE_SDRAM 0 +#define OMAPFB_MEMTYPE_SRAM 1 +#define OMAPFB_MEMTYPE_MAX 1 + +enum omapfb_color_format { + OMAPFB_COLOR_RGB565 = 0, + OMAPFB_COLOR_YUV422, + OMAPFB_COLOR_YUV420, + OMAPFB_COLOR_CLUT_8BPP, + OMAPFB_COLOR_CLUT_4BPP, + OMAPFB_COLOR_CLUT_2BPP, + OMAPFB_COLOR_CLUT_1BPP, + OMAPFB_COLOR_RGB444, + OMAPFB_COLOR_YUY422, + + OMAPFB_COLOR_ARGB16, + OMAPFB_COLOR_RGB24U, /* RGB24, 32-bit container */ + OMAPFB_COLOR_RGB24P, /* RGB24, 24-bit container */ + OMAPFB_COLOR_ARGB32, + OMAPFB_COLOR_RGBA32, + OMAPFB_COLOR_RGBX32, +}; + +struct omapfb_update_window { + __u32 x, y; + __u32 width, height; + __u32 format; + __u32 out_x, out_y; + __u32 out_width, out_height; + __u32 reserved[8]; +}; + +struct omapfb_update_window_old { + __u32 x, y; + __u32 width, height; + __u32 format; +}; + +enum omapfb_plane { + OMAPFB_PLANE_GFX = 0, + OMAPFB_PLANE_VID1, + OMAPFB_PLANE_VID2, +}; + +enum omapfb_channel_out { + OMAPFB_CHANNEL_OUT_LCD = 0, + OMAPFB_CHANNEL_OUT_DIGIT, +}; + +struct omapfb_plane_info { + __u32 pos_x; + __u32 pos_y; + __u8 enabled; + __u8 channel_out; + __u8 mirror; + __u8 reserved1; + __u32 out_width; + __u32 out_height; + __u32 reserved2[12]; +}; + +struct omapfb_mem_info { + __u32 size; + __u8 type; + __u8 reserved[3]; +}; + +struct omapfb_caps { + __u32 ctrl; + __u32 plane_color; + __u32 wnd_color; +}; + +enum omapfb_color_key_type { + OMAPFB_COLOR_KEY_DISABLED = 0, + OMAPFB_COLOR_KEY_GFX_DST, + OMAPFB_COLOR_KEY_VID_SRC, +}; + +struct omapfb_color_key { + __u8 channel_out; + __u32 background; + __u32 trans_key; + __u8 key_type; +}; + +enum omapfb_update_mode { + OMAPFB_UPDATE_DISABLED = 0, + OMAPFB_AUTO_UPDATE, + OMAPFB_MANUAL_UPDATE +}; + +struct omapfb_memory_read { + __u16 x; + __u16 y; + __u16 w; + __u16 h; + size_t buffer_size; + void *buffer; +}; + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#include + +#define OMAP_LCDC_INV_VSYNC 0x0001 +#define OMAP_LCDC_INV_HSYNC 0x0002 +#define OMAP_LCDC_INV_PIX_CLOCK 0x0004 +#define OMAP_LCDC_INV_OUTPUT_EN 0x0008 +#define OMAP_LCDC_HSVS_RISING_EDGE 0x0010 +#define OMAP_LCDC_HSVS_OPPOSITE 0x0020 + +#define OMAP_LCDC_SIGNAL_MASK 0x003f + +#define OMAP_LCDC_PANEL_TFT 0x0100 + +#define OMAPFB_PLANE_XRES_MIN 8 +#define OMAPFB_PLANE_YRES_MIN 8 + +#ifdef CONFIG_ARCH_OMAP1 +#define OMAPFB_PLANE_NUM 1 +#else +#define OMAPFB_PLANE_NUM 3 +#endif + +struct omapfb_device; + +struct lcd_panel { + const char *name; + int config; /* TFT/STN, signal inversion */ + int bpp; /* Pixel format in fb mem */ + int data_lines; /* Lines on LCD HW interface */ + + int x_res, y_res; + int pixel_clock; /* In kHz */ + int hsw; /* Horizontal synchronization + pulse width */ + int hfp; /* Horizontal front porch */ + int hbp; /* Horizontal back porch */ + int vsw; /* Vertical synchronization + pulse width */ + int vfp; /* Vertical front porch */ + int vbp; /* Vertical back porch */ + int acb; /* ac-bias pin frequency */ + int pcd; /* pixel clock divider. + Obsolete use pixel_clock instead */ + + int (*init) (struct lcd_panel *panel, + struct omapfb_device *fbdev); + void (*cleanup) (struct lcd_panel *panel); + int (*enable) (struct lcd_panel *panel); + void (*disable) (struct lcd_panel *panel); + unsigned long (*get_caps) (struct lcd_panel *panel); + int (*set_bklight_level)(struct lcd_panel *panel, + unsigned int level); + unsigned int (*get_bklight_level)(struct lcd_panel *panel); + unsigned int (*get_bklight_max) (struct lcd_panel *panel); + int (*run_test) (struct lcd_panel *panel, int test_num); +}; + +struct extif_timings { + int cs_on_time; + int cs_off_time; + int we_on_time; + int we_off_time; + int re_on_time; + int re_off_time; + int we_cycle_time; + int re_cycle_time; + int cs_pulse_width; + int access_time; + + int clk_div; + + u32 tim[5]; /* set by extif->convert_timings */ + + int converted; +}; + +struct lcd_ctrl_extif { + int (*init) (struct omapfb_device *fbdev); + void (*cleanup) (void); + void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div); + unsigned long (*get_max_tx_rate)(void); + int (*convert_timings) (struct extif_timings *timings); + void (*set_timings) (const struct extif_timings *timings); + void (*set_bits_per_cycle)(int bpc); + void (*write_command) (const void *buf, unsigned int len); + void (*read_data) (void *buf, unsigned int len); + void (*write_data) (const void *buf, unsigned int len); + void (*transfer_area) (int width, int height, + void (callback)(void * data), void *data); + int (*setup_tearsync) (unsigned pin_cnt, + unsigned hs_pulse_time, unsigned vs_pulse_time, + int hs_pol_inv, int vs_pol_inv, int div); + int (*enable_tearsync) (int enable, unsigned line); + + unsigned long max_transmit_size; +}; + +struct omapfb_notifier_block { + struct notifier_block nb; + void *data; + int plane_idx; +}; + +typedef int (*omapfb_notifier_callback_t)(struct notifier_block *, + unsigned long event, + void *fbi); + +struct omapfb_mem_region { + u32 paddr; + void __iomem *vaddr; + unsigned long size; + u8 type; /* OMAPFB_PLANE_MEM_* */ + enum omapfb_color_format format;/* OMAPFB_COLOR_* */ + unsigned format_used:1; /* Must be set when format is set. + * Needed b/c of the badly chosen 0 + * base for OMAPFB_COLOR_* values + */ + unsigned alloc:1; /* allocated by the driver */ + unsigned map:1; /* kernel mapped by the driver */ +}; + +struct omapfb_mem_desc { + int region_cnt; + struct omapfb_mem_region region[OMAPFB_PLANE_NUM]; +}; + +struct lcd_ctrl { + const char *name; + void *data; + + int (*init) (struct omapfb_device *fbdev, + int ext_mode, + struct omapfb_mem_desc *req_md); + void (*cleanup) (void); + void (*bind_client) (struct omapfb_notifier_block *nb); + void (*get_caps) (int plane, struct omapfb_caps *caps); + int (*set_update_mode)(enum omapfb_update_mode mode); + enum omapfb_update_mode (*get_update_mode)(void); + int (*setup_plane) (int plane, int channel_out, + unsigned long offset, + int screen_width, + int pos_x, int pos_y, int width, + int height, int color_mode); + int (*set_rotate) (int angle); + int (*setup_mem) (int plane, size_t size, + int mem_type, unsigned long *paddr); + int (*mmap) (struct fb_info *info, + struct vm_area_struct *vma); + int (*set_scale) (int plane, + int orig_width, int orig_height, + int out_width, int out_height); + int (*enable_plane) (int plane, int enable); + int (*update_window) (struct fb_info *fbi, + struct omapfb_update_window *win, + void (*callback)(void *), + void *callback_data); + void (*sync) (void); + void (*suspend) (void); + void (*resume) (void); + int (*run_test) (int test_num); + int (*setcolreg) (u_int regno, u16 red, u16 green, + u16 blue, u16 transp, + int update_hw_mem); + int (*set_color_key) (struct omapfb_color_key *ck); + int (*get_color_key) (struct omapfb_color_key *ck); +}; + +enum omapfb_state { + OMAPFB_DISABLED = 0, + OMAPFB_SUSPENDED= 99, + OMAPFB_ACTIVE = 100 +}; + +struct omapfb_plane_struct { + int idx; + struct omapfb_plane_info info; + enum omapfb_color_format color_mode; + struct omapfb_device *fbdev; +}; + +struct omapfb_device { + int state; + int ext_lcdc; /* Using external + LCD controller */ + struct mutex rqueue_mutex; + + int palette_size; + u32 pseudo_palette[17]; + + struct lcd_panel *panel; /* LCD panel */ + const struct lcd_ctrl *ctrl; /* LCD controller */ + const struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */ + struct lcd_ctrl_extif *ext_if; /* LCD ctrl external + interface */ + struct device *dev; + struct fb_var_screeninfo new_var; /* for mode changes */ + + struct omapfb_mem_desc mem_desc; + struct fb_info *fb_info[OMAPFB_PLANE_NUM]; +}; + +struct omapfb_platform_data { + struct omap_lcd_config lcd; + struct omapfb_mem_desc mem_desc; + void *ctrl_platform_data; +}; + +#ifdef CONFIG_ARCH_OMAP1 +extern struct lcd_ctrl omap1_lcd_ctrl; +#else +extern struct lcd_ctrl omap2_disp_ctrl; +#endif + +extern void omapfb_set_platform_data(struct omapfb_platform_data *data); + +extern void omapfb_reserve_sdram(void); +extern void omapfb_register_panel(struct lcd_panel *panel); +extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); +extern void omapfb_notify_clients(struct omapfb_device *fbdev, + unsigned long event); +extern int omapfb_register_client(struct omapfb_notifier_block *nb, + omapfb_notifier_callback_t callback, + void *callback_data); +extern int omapfb_unregister_client(struct omapfb_notifier_block *nb); +extern int omapfb_update_window_async(struct fb_info *fbi, + struct omapfb_update_window *win, + void (*callback)(void *), + void *callback_data); + +/* in arch/arm/plat-omap/fb.c */ +extern void omapfb_set_ctrl_platform_data(void *pdata); + +#endif /* __KERNEL__ */ + +#endif /* __OMAPFB_H */ diff --git a/settings.c b/settings.c index 1c6d656016c..bc245c76e05 100644 --- a/settings.c +++ b/settings.c @@ -102,6 +102,8 @@ const char *config_get_default_video(void) return "vg"; case VIDEO_NULL: return "null"; + case VIDEO_OMAP: + return "omap"; default: return NULL; }