diff options
-rw-r--r-- | arch/arm/mach-tegra/include/mach/dc.h | 7 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 81 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_priv.h | 18 | ||||
-rw-r--r-- | drivers/video/tegra/fb.c | 323 | ||||
-rw-r--r-- | include/video/tegrafb.h | 83 |
5 files changed, 488 insertions, 24 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index ce562e5634f7..49c09a177d00 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -86,6 +86,7 @@ struct tegra_dc_out { #define TEGRA_DC_ORDER_BLUE_RED 1 struct tegra_dc; +struct nvmap_handle_ref; struct tegra_dc_win { u8 idx; @@ -108,6 +109,8 @@ struct tegra_dc_win { int dirty; struct tegra_dc *dc; + + struct nvmap_handle_ref *surface; }; #define TEGRA_WIN_FLAG_ENABLED (1 << 0) @@ -165,6 +168,10 @@ struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win); void tegra_dc_enable(struct tegra_dc *dc); void tegra_dc_disable(struct tegra_dc *dc); +u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc); +u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc); +void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, u32 val); + /* tegra_dc_update_windows and tegra_dc_sync_windows do not support windows * with differenct dcs in one call */ diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index fadecf4796e1..16e6a454336d 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -102,6 +102,8 @@ static void _dump_regs(struct tegra_dc *dc, void *data, int i; char buff[256]; + tegra_dc_io_start(dc); + DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); DUMP_REG(DC_CMD_DISPLAY_COMMAND); DUMP_REG(DC_CMD_SIGNAL_RAISE); @@ -225,6 +227,8 @@ static void _dump_regs(struct tegra_dc *dc, void *data, DUMP_REG(DC_WINBUF_ADDR_H_OFFSET); DUMP_REG(DC_WINBUF_ADDR_V_OFFSET); } + + tegra_dc_io_end(dc); } #undef DUMP_REG @@ -285,7 +289,6 @@ static void tegra_dc_dbg_add(struct tegra_dc *dc) snprintf(name, sizeof(name), "tegra_dc%d_regs", dc->ndev->id); (void) debugfs_create_file(name, S_IRUGO, NULL, dc, &dbg_fops); - } #else static void tegra_dc_dbg_add(struct tegra_dc *dc) {} @@ -533,13 +536,40 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) } tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL); - mutex_unlock(&dc->lock); return 0; } EXPORT_SYMBOL(tegra_dc_update_windows); +u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc) +{ + return dc->syncpt_id; +} +EXPORT_SYMBOL(tegra_dc_get_syncpt_id); + +u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc) +{ + u32 max; + + mutex_lock(&dc->lock); + max = nvhost_syncpt_incr_max(&dc->ndev->host->syncpt, dc->syncpt_id, 1); + dc->syncpt_max = max; + mutex_unlock(&dc->lock); + + return max; +} + +void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, u32 val) +{ + mutex_lock(&dc->lock); + while (dc->syncpt_min < val) { + dc->syncpt_min++; + nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt, dc->syncpt_id); + } + mutex_unlock(&dc->lock); +} + static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[], int n) { @@ -769,11 +799,18 @@ static void tegra_dc_set_color_control(struct tegra_dc *dc) static void tegra_dc_init(struct tegra_dc *dc) { + u32 disp_syncpt; + u32 vblank_syncpt; + tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); - if (dc->ndev->id == 0) - tegra_dc_writel(dc, 0x0000011a, DC_CMD_CONT_SYNCPT_VSYNC); - else - tegra_dc_writel(dc, 0x0000011b, DC_CMD_CONT_SYNCPT_VSYNC); + if (dc->ndev->id == 0) { + disp_syncpt = NVSYNCPT_DISP0; + vblank_syncpt = NVSYNCPT_VBLANK0; + } else if (dc->ndev->id == 1) { + disp_syncpt = NVSYNCPT_DISP1; + vblank_syncpt = NVSYNCPT_VBLANK1; + } + tegra_dc_writel(dc, 0x00000100 | vblank_syncpt, DC_CMD_CONT_SYNCPT_VSYNC); tegra_dc_writel(dc, 0x00004700, DC_CMD_INT_TYPE); tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_POLARITY); tegra_dc_writel(dc, 0x00000020, DC_DISP_MEM_HIGH_PRIORITY); @@ -786,18 +823,24 @@ static void tegra_dc_init(struct tegra_dc *dc) tegra_dc_set_color_control(dc); + dc->syncpt_id = disp_syncpt; + + dc->syncpt_min = dc->syncpt_max = + nvhost_syncpt_read(&dc->ndev->host->syncpt, disp_syncpt); + if (dc->mode.pclk) tegra_dc_program_mode(dc, &dc->mode); } static void _tegra_dc_enable(struct tegra_dc *dc) { + tegra_dc_io_start(dc); + if (dc->out && dc->out->enable) dc->out->enable(); tegra_dc_setup_clk(dc, dc->clk); - clk_enable(dc->host1x_clk); clk_enable(dc->clk); tegra_periph_reset_deassert(dc->clk); enable_irq(dc->irq); @@ -831,10 +874,17 @@ static void _tegra_dc_disable(struct tegra_dc *dc) disable_irq(dc->irq); tegra_periph_reset_assert(dc->clk); clk_disable(dc->clk); - clk_disable(dc->host1x_clk); if (dc->out && dc->out->disable) dc->out->disable(); + + /* flush any pending syncpt waits */ + while (dc->syncpt_min < dc->syncpt_max) { + dc->syncpt_min++; + nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt, dc->syncpt_id); + } + + tegra_dc_io_end(dc); } @@ -854,7 +904,6 @@ static int tegra_dc_probe(struct nvhost_device *ndev) { struct tegra_dc *dc; struct clk *clk; - struct clk *host1x_clk; struct resource *res; struct resource *base_res; struct resource *fb_mem = NULL; @@ -904,23 +953,14 @@ static int tegra_dc_probe(struct nvhost_device *ndev) fb_mem = nvhost_get_resource_byname(ndev, IORESOURCE_MEM, "fbmem"); - host1x_clk = clk_get(&ndev->dev, "host1x"); - if (IS_ERR_OR_NULL(host1x_clk)) { - dev_err(&ndev->dev, "can't get host1x clock\n"); - ret = -ENOENT; - goto err_iounmap_reg; - } - clk = clk_get(&ndev->dev, NULL); if (IS_ERR_OR_NULL(clk)) { dev_err(&ndev->dev, "can't get clock\n"); ret = -ENOENT; - - goto err_put_host1x_clk; + goto err_iounmap_reg; } dc->clk = clk; - dc->host1x_clk = host1x_clk; dc->base_res = base_res; dc->base = base; dc->irq = irq; @@ -984,8 +1024,6 @@ err_free_irq: free_irq(irq, dc); err_put_clk: clk_put(clk); -err_put_host1x_clk: - clk_put(host1x_clk); err_iounmap_reg: iounmap(base); if (fb_mem) @@ -1014,7 +1052,6 @@ static int tegra_dc_remove(struct nvhost_device *ndev) free_irq(dc->irq, dc); clk_put(dc->clk); - clk_put(dc->host1x_clk); iounmap(dc->base); if (dc->fb_mem) release_resource(dc->base_res); diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h index 2297be40f030..39a03e8fb9c0 100644 --- a/drivers/video/tegra/dc/dc_priv.h +++ b/drivers/video/tegra/dc/dc_priv.h @@ -22,6 +22,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/wait.h> +#include "../host/dev.h" struct tegra_dc; @@ -54,7 +55,6 @@ struct tegra_dc { int irq; struct clk *clk; - struct clk *host1x_clk; bool enabled; @@ -74,17 +74,33 @@ struct tegra_dc { struct resource *fb_mem; struct tegra_fb_info *fb; + + u32 syncpt_id; + u32 syncpt_min; + u32 syncpt_max; }; +static inline void tegra_dc_io_start(struct tegra_dc *dc) +{ + nvhost_module_busy(&dc->ndev->host->mod); +} + +static inline void tegra_dc_io_end(struct tegra_dc *dc) +{ + nvhost_module_idle(&dc->ndev->host->mod); +} + static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, unsigned long reg) { + BUG_ON(!nvhost_module_powered(&dc->ndev->host->mod)); return readl(dc->base + reg * 4); } static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val, unsigned long reg) { + BUG_ON(!nvhost_module_powered(&dc->ndev->host->mod)); writel(val, dc->base + reg * 4); } diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 7e4ffa8ba0b9..1656a6e49279 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -23,13 +23,22 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> +#include <linux/uaccess.h> #include <linux/slab.h> +#include <linux/file.h> +#include <linux/workqueue.h> #include <asm/atomic.h> +#include <video/tegrafb.h> + #include <mach/dc.h> #include <mach/fb.h> #include <mach/nvhost.h> +#include <mach/nvmap.h> + +#include "host/dev.h" +#include "nvmap/nvmap.h" struct tegra_fb_info { struct tegra_dc_win *win; @@ -43,6 +52,24 @@ struct tegra_fb_info { int yres; atomic_t in_use; + struct nvmap_client *user_nvmap; + struct nvmap_client *fb_nvmap; + + struct workqueue_struct *flip_wq; +}; + +struct tegra_fb_flip_win { + struct tegra_dc_win win_data; + struct tegra_dc_win *dc_win; + s32 pre_syncpt_id; + u32 pre_syncpt_val; +}; + +struct tegra_fb_flip_data { + struct work_struct work; + struct tegra_fb_info *fb; + struct tegra_fb_flip_win windows[TEGRA_FB_FLIP_N_WINDOWS]; + u32 syncpt_max; }; /* palette array used by the fbcon */ @@ -55,6 +82,8 @@ static int tegra_fb_open(struct fb_info *info, int user) if (atomic_xchg(&tegra_fb->in_use, 1)) return -EBUSY; + tegra_fb->user_nvmap = NULL; + return 0; } @@ -62,6 +91,13 @@ static int tegra_fb_release(struct fb_info *info, int user) { struct tegra_fb_info *tegra_fb = info->par; + flush_workqueue(tegra_fb->flip_wq); + + if (tegra_fb->user_nvmap) { + nvmap_client_put(tegra_fb->user_nvmap); + tegra_fb->user_nvmap = NULL; + } + WARN_ON(!atomic_xchg(&tegra_fb->in_use, 0)); return 0; @@ -215,6 +251,12 @@ static int tegra_fb_pan_display(struct fb_var_screeninfo *var, tegra_dc_update_windows(&tegra_fb->win, 1); tegra_dc_sync_windows(&tegra_fb->win, 1); + if (WARN_ON(tegra_fb->win->surface)) { + nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->surface); + nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->surface); + tegra_fb->win->surface = NULL; + } + return 0; } @@ -236,6 +278,255 @@ static void tegra_fb_imageblit(struct fb_info *info, cfb_imageblit(info, image); } +/* TODO: implement ALLOC, FREE, BLANK ioctls */ + +static int tegra_fb_set_nvmap_fd(struct tegra_fb_info *tegra_fb, int fd) +{ + struct nvmap_client *nvmap = NULL; + + if (fd < 0) + return -EINVAL; + + nvmap = nvmap_client_get_file(fd); + if (IS_ERR(nvmap)) + return PTR_ERR(nvmap); + + if (tegra_fb->user_nvmap) + nvmap_client_put(tegra_fb->user_nvmap); + + tegra_fb->user_nvmap = nvmap; + + return 0; +} + +static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb, + struct tegra_dc_win *win, + const struct tegra_fb_windowattr *attr) +{ + struct nvmap_handle_ref *r_dupe; + struct nvmap_handle *h_win; + + if (!attr->buff_id) { + win->flags = 0; + win->surface = NULL; + return 0; + } + + h_win = nvmap_get_handle_id(tegra_fb->user_nvmap, attr->buff_id); + if (h_win == NULL) { + dev_err(&tegra_fb->ndev->dev, "%s: flip invalid " + "handle %08x\n", current->comm, attr->buff_id); + return -EPERM; + } + + /* duplicate the new framebuffer's handle into the fb driver's + * nvmap context, to ensure that the handle won't be freed as + * long as it is in-use by the fb driver */ + r_dupe = nvmap_duplicate_handle_id(tegra_fb->fb_nvmap, attr->buff_id); + nvmap_handle_put(h_win); + + if (IS_ERR(r_dupe)) { + dev_err(&tegra_fb->ndev->dev, "couldn't duplicate handle\n"); + return PTR_ERR(r_dupe); + } + + win->surface = r_dupe; + + win->flags = TEGRA_WIN_FLAG_ENABLED; + if (attr->blend == TEGRA_FB_WIN_BLEND_PREMULT) + win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT; + else if (attr->blend == TEGRA_FB_WIN_BLEND_COVERAGE) + win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE; + win->fmt = attr->pixformat; + win->x = attr->x; + win->y = attr->y; + win->w = attr->w; + win->h = attr->h; + win->out_x = attr->out_x; + win->out_y = attr->out_y; + win->out_w = attr->out_w; + win->out_h = attr->out_h; + win->z = attr->z; + + win->phys_addr = nvmap_pin(tegra_fb->fb_nvmap, r_dupe); + if (IS_ERR((void *)win->phys_addr)) { + dev_err(&tegra_fb->ndev->dev, "couldn't pin handle\n"); + nvmap_free(tegra_fb->fb_nvmap, r_dupe); + return (int)win->phys_addr; + } + /* STOPSHIP verify that this won't read outside of the surface */ + win->phys_addr += attr->offset; + win->stride = attr->stride; + + return 0; +} + +static void tegra_fb_flip_work(struct work_struct *work) +{ + struct tegra_fb_flip_data *data; + struct tegra_dc_win *wins[TEGRA_FB_FLIP_N_WINDOWS]; + struct nvmap_handle_ref *surfs[TEGRA_FB_FLIP_N_WINDOWS]; + int i, nr_win = 0, nr_unpin = 0; + + data = container_of(work, struct tegra_fb_flip_data, work); + + for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) { + struct tegra_fb_flip_win *flip_win = &data->windows[i]; + + if (!flip_win->dc_win) + continue; + + if (flip_win->dc_win->flags && flip_win->dc_win->surface) + surfs[nr_unpin++] = flip_win->dc_win->surface; + + wins[nr_win++] = flip_win->dc_win; + + flip_win->dc_win->flags = flip_win->win_data.flags; + if (!flip_win->dc_win->flags) + continue; + + flip_win->dc_win->surface = flip_win->win_data.surface; + flip_win->dc_win->fmt = flip_win->win_data.fmt; + flip_win->dc_win->x = flip_win->win_data.x; + flip_win->dc_win->y = flip_win->win_data.y; + flip_win->dc_win->w = flip_win->win_data.w; + flip_win->dc_win->h = flip_win->win_data.h; + flip_win->dc_win->out_x = flip_win->win_data.out_x; + flip_win->dc_win->out_y = flip_win->win_data.out_y; + flip_win->dc_win->out_w = flip_win->win_data.out_w; + flip_win->dc_win->out_h = flip_win->win_data.out_h; + flip_win->dc_win->z = flip_win->win_data.z; + flip_win->dc_win->phys_addr = flip_win->win_data.phys_addr; + flip_win->dc_win->stride = flip_win->win_data.stride; + + if (flip_win->pre_syncpt_id < 0) + continue; + + nvhost_syncpt_wait_timeout(&data->fb->ndev->host->syncpt, + flip_win->pre_syncpt_id, + flip_win->pre_syncpt_val, + msecs_to_jiffies(500)); + } + + if (!nr_win) + goto free_data; + + tegra_dc_update_windows(wins, nr_win); + /* TODO: implement swapinterval here */ + tegra_dc_sync_windows(wins, nr_win); + + tegra_dc_incr_syncpt_min(data->fb->win->dc, data->syncpt_max); + + /* unpin and deref previous front buffers */ + for (i = 0; i < nr_unpin; i++) { + nvmap_unpin(data->fb->fb_nvmap, surfs[i]); + nvmap_free(data->fb->fb_nvmap, surfs[i]); + } + +free_data: + kfree(data); +} + +static int tegra_fb_flip(struct tegra_fb_info *tegra_fb, + struct tegra_fb_flip_args *args) +{ + struct tegra_fb_flip_data *data; + struct tegra_fb_flip_win *flip_win; + struct tegra_dc *dc = tegra_fb->win->dc; + u32 syncpt_max; + int i, err; + + if (WARN_ON(!tegra_fb->user_nvmap)) + return -EFAULT; + + if (WARN_ON(!tegra_fb->ndev)) + return -EFAULT; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&tegra_fb->ndev->dev, "no memory for flip\n"); + return -ENOMEM; + } + + INIT_WORK(&data->work, tegra_fb_flip_work); + data->fb = tegra_fb; + + for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) { + + flip_win = &data->windows[i]; + flip_win->dc_win = tegra_dc_get_window(dc, args->win[i].index); + flip_win->pre_syncpt_id = args->win[i].pre_syncpt_id; + flip_win->pre_syncpt_val = args->win[i].pre_syncpt_val; + + if (!flip_win->dc_win) + continue; + + err = tegra_fb_set_windowattr(tegra_fb, &flip_win->win_data, + &args->win[i]); + if (err) { + dev_err(&tegra_fb->ndev->dev, "error setting window " + "attributes\n"); + goto surf_err; + } + } + + syncpt_max = tegra_dc_incr_syncpt_max(dc); + data->syncpt_max = syncpt_max; + + queue_work(tegra_fb->flip_wq, &data->work); + + args->post_syncpt_val = syncpt_max; + args->post_syncpt_id = tegra_dc_get_syncpt_id(dc); + + return 0; + +surf_err: + while (i--) { + if (data->windows[i].win_data.surface) { + nvmap_unpin(tegra_fb->fb_nvmap, + data->windows[i].win_data.surface); + nvmap_free(tegra_fb->fb_nvmap, + data->windows[i].win_data.surface); + } + } + kfree(data); + return err; +} + +/* TODO: implement private window ioctls to set overlay x,y */ + +static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct tegra_fb_info *tegra_fb = info->par; + struct tegra_fb_flip_args flip_args; + int fd; + int ret; + + switch (cmd) { + case FBIO_TEGRA_SET_NVMAP_FD: + if (copy_from_user(&fd, (void __user *)arg, sizeof(fd))) + return -EFAULT; + + return tegra_fb_set_nvmap_fd(tegra_fb, fd); + + case FBIO_TEGRA_FLIP: + if (copy_from_user(&flip_args, (void __user *)arg, sizeof(flip_args))) + return -EFAULT; + + ret = tegra_fb_flip(tegra_fb, &flip_args); + + if (copy_to_user((void __user *)arg, &flip_args, sizeof(flip_args))) + return -EFAULT; + + return ret; + + default: + return -ENOTTY; + } + + return 0; +} + static struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, .fb_open = tegra_fb_open, @@ -248,6 +539,7 @@ static struct fb_ops tegra_fb_ops = { .fb_fillrect = tegra_fb_fillrect, .fb_copyarea = tegra_fb_copyarea, .fb_imageblit = tegra_fb_imageblit, + .fb_ioctl = tegra_fb_ioctl, }; void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, @@ -316,8 +608,21 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, tegra_fb->fb_mem = fb_mem; tegra_fb->xres = fb_data->xres; tegra_fb->yres = fb_data->yres; + tegra_fb->fb_nvmap = nvmap_create_client(nvmap_dev); + if (!tegra_fb->fb_nvmap) { + dev_err(&ndev->dev, "couldn't create nvmap client\n"); + ret = -ENOMEM; + goto err_free; + } atomic_set(&tegra_fb->in_use, 0); + tegra_fb->flip_wq = create_singlethread_workqueue(dev_name(&ndev->dev)); + if (!tegra_fb->flip_wq) { + dev_err(&ndev->dev, "couldn't create flip work-queue\n"); + ret = -ENOMEM; + goto err_delete_wq; + } + if (fb_mem) { fb_size = resource_size(fb_mem); fb_phys = fb_mem->start; @@ -325,7 +630,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, if (!fb_base) { dev_err(&ndev->dev, "fb can't be mapped\n"); ret = -EBUSY; - goto err_free; + goto err_put_client; } tegra_fb->valid = true; } @@ -396,6 +701,10 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, err_iounmap_fb: iounmap(fb_base); +err_put_client: + nvmap_client_put(tegra_fb->fb_nvmap); +err_delete_wq: + destroy_workqueue(tegra_fb->flip_wq); err_free: framebuffer_release(info); err: @@ -406,7 +715,19 @@ void tegra_fb_unregister(struct tegra_fb_info *fb_info) { struct fb_info *info = fb_info->info; + if (fb_info->win->surface) { + nvmap_unpin(fb_info->fb_nvmap, fb_info->win->surface); + nvmap_free(fb_info->fb_nvmap, fb_info->win->surface); + } + + if (fb_info->fb_nvmap) + nvmap_client_put(fb_info->fb_nvmap); + unregister_framebuffer(info); + + flush_workqueue(fb_info->flip_wq); + destroy_workqueue(fb_info->flip_wq); + iounmap(info->screen_base); framebuffer_release(info); } diff --git a/include/video/tegrafb.h b/include/video/tegrafb.h new file mode 100644 index 000000000000..3d7a5a9d66e9 --- /dev/null +++ b/include/video/tegrafb.h @@ -0,0 +1,83 @@ +/* + * include/video/tegrafb.h + * + * Copyright (C) 2010 Google, Inc. + * Author: Erik Gilling <konkers@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _LINUX_TEGRAFB_H_ +#define _LINUX_TEGRAFB_H_ + +#include <linux/types.h> +#include <asm/ioctl.h> + +#define TEGRA_FB_WIN_FMT_P1 0 +#define TEGRA_FB_WIN_FMT_P2 1 +#define TEGRA_FB_WIN_FMT_P4 2 +#define TEGRA_FB_WIN_FMT_P8 3 +#define TEGRA_FB_WIN_FMT_B4G4R4A4 4 +#define TEGRA_FB_WIN_FMT_B5G5R5A 5 +#define TEGRA_FB_WIN_FMT_B5G6R5 6 +#define TEGRA_FB_WIN_FMT_AB5G5R5 7 +#define TEGRA_FB_WIN_FMT_B8G8R8A8 12 +#define TEGRA_FB_WIN_FMT_R8G8B8A8 13 +#define TEGRA_FB_WIN_FMT_B6x2G6x2R6x2A8 14 +#define TEGRA_FB_WIN_FMT_R6x2G6x2B6x2A8 15 +#define TEGRA_FB_WIN_FMT_YCbCr422 16 +#define TEGRA_FB_WIN_FMT_YUV422 17 +#define TEGRA_FB_WIN_FMT_YCbCr420P 18 +#define TEGRA_FB_WIN_FMT_YUV420P 19 +#define TEGRA_FB_WIN_FMT_YCbCr422P 20 +#define TEGRA_FB_WIN_FMT_YUV422P 21 +#define TEGRA_FB_WIN_FMT_YCbCr422R 22 +#define TEGRA_FB_WIN_FMT_YUV422R 23 +#define TEGRA_FB_WIN_FMT_YCbCr422RA 24 +#define TEGRA_FB_WIN_FMT_YUV422RA 25 + +#define TEGRA_FB_WIN_BLEND_NONE 0 +#define TEGRA_FB_WIN_BLEND_PREMULT 1 +#define TEGRA_FB_WIN_BLEND_COVERAGE 2 + +/* set index to -1 to ignore window data */ +struct tegra_fb_windowattr { + __s32 index; + __u32 buff_id; + __u32 blend; + __u32 offset; + __u32 stride; + __u32 pixformat; + __u32 x; + __u32 y; + __u32 w; + __u32 h; + __u32 out_x; + __u32 out_y; + __u32 out_w; + __u32 out_h; + __u32 z; + __u32 pre_syncpt_id; + __u32 pre_syncpt_val; +}; + +#define TEGRA_FB_FLIP_N_WINDOWS 3 + +struct tegra_fb_flip_args { + struct tegra_fb_windowattr win[TEGRA_FB_FLIP_N_WINDOWS]; + __u32 post_syncpt_id; + __u32 post_syncpt_val; +}; + +#define FBIO_TEGRA_SET_NVMAP_FD _IOW('F', 0x40, __u32) +#define FBIO_TEGRA_FLIP _IOW('F', 0x41, struct tegra_fb_flip_args) + +#endif |