2 * drivers/video/tegra/fb.c
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 * Colin Cross <ccross@android.com>
7 * Travis Geiselbrecht <travis@palm.com>
9 * Copyright (C) 2010-2011 NVIDIA Corporation
11 * This software is licensed under the terms of the GNU General Public
12 * License version 2, as published by the Free Software Foundation, and
13 * may be copied, distributed, and modified under those terms.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
28 #include <linux/uaccess.h>
29 #include <linux/slab.h>
30 #include <linux/file.h>
31 #include <linux/workqueue.h>
33 #include <asm/atomic.h>
35 #include <video/tegrafb.h>
39 #include <linux/nvhost.h>
40 #include <linux/nvmap.h>
43 #include "nvmap/nvmap.h"
44 #include "dc/dc_priv.h"
46 /* Pad pitch to 16-byte boundary. */
47 #define TEGRA_LINEAR_PITCH_ALIGNMENT 32
49 struct tegra_fb_info {
50 struct tegra_dc_win *win;
51 struct nvhost_device *ndev;
55 struct resource *fb_mem;
61 /* palette array used by the fbcon */
62 static u32 pseudo_palette[16];
64 static int tegra_fb_check_var(struct fb_var_screeninfo *var,
67 struct tegra_fb_info *tegra_fb = info->par;
68 struct tegra_dc *dc = tegra_fb->win->dc;
69 struct tegra_dc_out_ops *ops = dc->out_ops;
70 struct fb_videomode mode;
72 if ((var->yres * var->xres * var->bits_per_pixel / 8 * 2) >
76 /* Apply mode filter for HDMI only -LVDS supports only fix mode */
77 if (ops && ops->mode_filter) {
79 fb_var_to_videomode(&mode, var);
80 if (!ops->mode_filter(dc, &mode))
83 /* Mode filter may have modified the mode */
84 fb_videomode_to_var(var, &mode);
87 /* Double yres_virtual to allow double buffering through pan_display */
88 var->yres_virtual = var->yres * 2;
93 static int tegra_fb_set_par(struct fb_info *info)
95 struct tegra_fb_info *tegra_fb = info->par;
96 struct fb_var_screeninfo *var = &info->var;
98 if (var->bits_per_pixel) {
99 /* we only support RGB ordering for now */
100 switch (var->bits_per_pixel) {
104 var->green.offset = 8;
105 var->green.length = 8;
106 var->blue.offset = 16;
107 var->blue.length = 8;
108 var->transp.offset = 24;
109 var->transp.length = 8;
110 tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
113 var->red.offset = 11;
115 var->green.offset = 5;
116 var->green.length = 6;
117 var->blue.offset = 0;
118 var->blue.length = 5;
119 tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
125 info->fix.line_length = var->xres * var->bits_per_pixel / 8;
126 /* Pad the stride to 16-byte boundary. */
127 info->fix.line_length = round_up(info->fix.line_length,
128 TEGRA_LINEAR_PITCH_ALIGNMENT);
129 tegra_fb->win->stride = info->fix.line_length;
130 tegra_fb->win->stride_uv = 0;
131 tegra_fb->win->phys_addr_u = 0;
132 tegra_fb->win->phys_addr_v = 0;
137 struct fb_videomode m;
139 fb_var_to_videomode(&m, var);
141 info->mode = (struct fb_videomode *)
142 fb_find_nearest_mode(&m, &info->modelist);
144 dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n");
149 * only enable stereo if the mode supports it and
152 stereo = !!(var->vmode & info->mode->vmode &
153 #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
154 FB_VMODE_STEREO_FRAME_PACK);
156 FB_VMODE_STEREO_LEFT_RIGHT);
159 tegra_dc_set_fb_mode(tegra_fb->win->dc, info->mode, stereo);
161 tegra_fb->win->w.full = dfixed_const(info->mode->xres);
162 tegra_fb->win->h.full = dfixed_const(info->mode->yres);
163 tegra_fb->win->out_w = info->mode->xres;
164 tegra_fb->win->out_h = info->mode->yres;
169 static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
170 unsigned blue, unsigned transp, struct fb_info *info)
172 struct fb_var_screeninfo *var = &info->var;
174 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
175 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
181 red = (red >> (16 - info->var.red.length));
182 green = (green >> (16 - info->var.green.length));
183 blue = (blue >> (16 - info->var.blue.length));
185 v = (red << var->red.offset) |
186 (green << var->green.offset) |
187 (blue << var->blue.offset);
189 ((u32 *)info->pseudo_palette)[regno] = v;
196 static int tegra_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
198 struct tegra_fb_info *tegra_fb = info->par;
199 struct tegra_dc *dc = tegra_fb->win->dc;
201 u16 *red = cmap->red;
202 u16 *green = cmap->green;
203 u16 *blue = cmap->blue;
204 int start = cmap->start;
206 if (((unsigned)start > 255) || ((start + cmap->len) > 256))
209 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
210 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
212 * For now we are considering color schemes with
213 * cmap->len <=16 as special case of basic color
214 * scheme to support fbconsole.But for DirectColor
215 * visuals(like the one we actually have, that include
216 * a HW LUT),the way it's intended to work is that the
217 * actual LUT HW is programmed to the intended values,
218 * even for small color maps like those with 16 or fewer
219 * entries. The pseudo_palette is then programmed to the
220 * identity transform.
222 if (cmap->len <= 16) {
223 /* Low-color schemes like fbconsole*/
224 u16 *transp = cmap->transp;
225 u_int vtransp = 0xffff;
227 for (i = 0; i < cmap->len; i++) {
230 if (tegra_fb_setcolreg(start++, *red++,
236 /* High-color schemes*/
237 for (i = 0; i < cmap->len; i++) {
238 dc->fb_lut.r[start+i] = *red++ >> 8;
239 dc->fb_lut.g[start+i] = *green++ >> 8;
240 dc->fb_lut.b[start+i] = *blue++ >> 8;
242 tegra_dc_update_lut(dc, -1, -1);
248 #if defined(CONFIG_FRAMEBUFFER_CONSOLE)
249 static void tegra_fb_flip_win(struct tegra_fb_info *tegra_fb)
251 struct tegra_dc_win *win = tegra_fb->win;
252 struct fb_info *info = tegra_fb->info;
254 win->x.full = dfixed_const(0);
255 win->y.full = dfixed_const(0);
256 win->w.full = dfixed_const(tegra_fb->xres);
257 win->h.full = dfixed_const(tegra_fb->yres);
259 /* TODO: set to output res dc */
262 win->out_w = tegra_fb->xres;
263 win->out_h = tegra_fb->yres;
265 win->phys_addr = info->fix.smem_start +
266 (info->var.yoffset * info->fix.line_length) +
267 (info->var.xoffset * (info->var.bits_per_pixel / 8));
268 win->virt_addr = info->screen_base;
270 win->phys_addr_u = 0;
271 win->phys_addr_v = 0;
272 win->stride = info->fix.line_length;
275 switch (info->var.bits_per_pixel) {
280 tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
283 tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
286 win->flags = TEGRA_WIN_FLAG_ENABLED;
288 tegra_dc_update_windows(&tegra_fb->win, 1);
289 tegra_dc_sync_windows(&tegra_fb->win, 1);
293 static int tegra_fb_blank(int blank, struct fb_info *info)
295 struct tegra_fb_info *tegra_fb = info->par;
298 case FB_BLANK_UNBLANK:
299 dev_dbg(&tegra_fb->ndev->dev, "unblank\n");
300 tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
301 tegra_dc_enable(tegra_fb->win->dc);
304 case FB_BLANK_NORMAL:
305 dev_dbg(&tegra_fb->ndev->dev, "blank - normal\n");
306 tegra_dc_blank(tegra_fb->win->dc);
309 case FB_BLANK_VSYNC_SUSPEND:
310 case FB_BLANK_HSYNC_SUSPEND:
311 case FB_BLANK_POWERDOWN:
312 dev_dbg(&tegra_fb->ndev->dev, "blank - powerdown\n");
313 tegra_dc_disable(tegra_fb->win->dc);
321 static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
322 struct fb_info *info)
324 struct tegra_fb_info *tegra_fb = info->par;
325 char __iomem *flush_start;
326 char __iomem *flush_end;
329 if (!tegra_fb->win->cur_handle) {
330 flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
331 flush_end = flush_start + (var->yres * info->fix.line_length);
333 info->var.xoffset = var->xoffset;
334 info->var.yoffset = var->yoffset;
336 addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
337 (var->xoffset * (var->bits_per_pixel/8));
339 tegra_fb->win->phys_addr = addr;
340 tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
341 tegra_fb->win->virt_addr = info->screen_base;
343 tegra_dc_update_windows(&tegra_fb->win, 1);
344 tegra_dc_sync_windows(&tegra_fb->win, 1);
350 static void tegra_fb_fillrect(struct fb_info *info,
351 const struct fb_fillrect *rect)
353 cfb_fillrect(info, rect);
356 static void tegra_fb_copyarea(struct fb_info *info,
357 const struct fb_copyarea *region)
359 cfb_copyarea(info, region);
362 static void tegra_fb_imageblit(struct fb_info *info,
363 const struct fb_image *image)
365 cfb_imageblit(info, image);
368 static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
370 struct tegra_fb_modedb modedb;
371 struct fb_modelist *modelist;
375 case FBIO_TEGRA_GET_MODEDB:
376 if (copy_from_user(&modedb, (void __user *)arg, sizeof(modedb)))
380 list_for_each_entry(modelist, &info->modelist, list) {
381 struct fb_var_screeninfo var;
383 if (i >= modedb.modedb_len)
386 /* fb_videomode_to_var doesn't fill out all the members
387 of fb_var_screeninfo */
388 memset(&var, 0x0, sizeof(var));
390 fb_videomode_to_var(&var, &modelist->mode);
392 if (copy_to_user((void __user *)&modedb.modedb[i],
397 if (var.vmode & FB_VMODE_STEREO_MASK) {
398 if (i >= modedb.modedb_len)
400 var.vmode &= ~FB_VMODE_STEREO_MASK;
402 (void __user *)&modedb.modedb[i],
408 modedb.modedb_len = i;
410 if (copy_to_user((void __user *)arg, &modedb, sizeof(modedb)))
421 int tegra_fb_get_mode(struct tegra_dc *dc) {
422 return dc->fb->info->mode->refresh;
425 int tegra_fb_set_mode(struct tegra_dc *dc, int fps) {
427 struct list_head *pos;
428 struct fb_videomode *best_mode = NULL;
429 int curr_diff = INT_MAX; /* difference of best_mode refresh rate */
430 struct fb_modelist *modelist;
431 struct fb_info *info = dc->fb->info;
433 list_for_each(pos, &info->modelist) {
434 struct fb_videomode *mode;
436 modelist = list_entry(pos, struct fb_modelist, list);
437 mode = &modelist->mode;
438 if (fps <= mode->refresh && curr_diff > (mode->refresh - fps)) {
439 curr_diff = mode->refresh - fps;
444 info->mode = best_mode;
445 stereo = !!(info->var.vmode & info->mode->vmode &
446 #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
447 FB_VMODE_STEREO_FRAME_PACK);
449 FB_VMODE_STEREO_LEFT_RIGHT);
451 return tegra_dc_set_fb_mode(dc, best_mode, stereo);
456 static struct fb_ops tegra_fb_ops = {
457 .owner = THIS_MODULE,
458 .fb_check_var = tegra_fb_check_var,
459 .fb_set_par = tegra_fb_set_par,
460 .fb_setcmap = tegra_fb_setcmap,
461 .fb_blank = tegra_fb_blank,
462 .fb_pan_display = tegra_fb_pan_display,
463 .fb_fillrect = tegra_fb_fillrect,
464 .fb_copyarea = tegra_fb_copyarea,
465 .fb_imageblit = tegra_fb_imageblit,
466 .fb_ioctl = tegra_fb_ioctl,
469 void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
470 struct fb_monspecs *specs,
471 bool (*mode_filter)(const struct tegra_dc *dc,
472 struct fb_videomode *mode))
474 struct fb_event event;
477 mutex_lock(&fb_info->info->lock);
478 fb_destroy_modedb(fb_info->info->monspecs.modedb);
480 fb_destroy_modelist(&fb_info->info->modelist);
483 struct tegra_dc_mode mode;
484 memset(&fb_info->info->monspecs, 0x0,
485 sizeof(fb_info->info->monspecs));
486 memset(&mode, 0x0, sizeof(mode));
489 * reset video mode properties to prevent garbage being displayed on 'mode' device.
491 fb_info->info->mode = (struct fb_videomode*) NULL;
493 tegra_dc_set_mode(fb_info->win->dc, &mode);
494 mutex_unlock(&fb_info->info->lock);
498 memcpy(&fb_info->info->monspecs, specs,
499 sizeof(fb_info->info->monspecs));
500 fb_info->info->mode = specs->modedb;
502 for (i = 0; i < specs->modedb_len; i++) {
504 if (mode_filter(fb_info->win->dc, &specs->modedb[i]))
505 fb_add_videomode(&specs->modedb[i],
506 &fb_info->info->modelist);
508 fb_add_videomode(&specs->modedb[i],
509 &fb_info->info->modelist);
513 event.info = fb_info->info;
514 fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
515 mutex_unlock(&fb_info->info->lock);
518 struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
520 struct tegra_fb_data *fb_data,
521 struct resource *fb_mem)
523 struct tegra_dc_win *win;
524 struct fb_info *info;
525 struct tegra_fb_info *tegra_fb;
526 void __iomem *fb_base = NULL;
527 unsigned long fb_size = 0;
528 unsigned long fb_phys = 0;
532 win = tegra_dc_get_window(dc, fb_data->win);
534 dev_err(&ndev->dev, "dc does not have a window at index %d\n",
536 return ERR_PTR(-ENOENT);
539 info = framebuffer_alloc(sizeof(struct tegra_fb_info), &ndev->dev);
545 tegra_fb = info->par;
547 tegra_fb->ndev = ndev;
548 tegra_fb->fb_mem = fb_mem;
549 tegra_fb->xres = fb_data->xres;
550 tegra_fb->yres = fb_data->yres;
553 fb_size = resource_size(fb_mem);
554 fb_phys = fb_mem->start;
555 fb_base = ioremap_nocache(fb_phys, fb_size);
557 dev_err(&ndev->dev, "fb can't be mapped\n");
561 tegra_fb->valid = true;
564 stride = tegra_dc_get_stride(dc, 0);
565 if (!stride) /* default to pad the stride to 16-byte boundary. */
566 stride = round_up(info->fix.line_length,
567 TEGRA_LINEAR_PITCH_ALIGNMENT);
569 info->fbops = &tegra_fb_ops;
570 info->pseudo_palette = pseudo_palette;
571 info->screen_base = fb_base;
572 info->screen_size = fb_size;
574 strlcpy(info->fix.id, "tegra_fb", sizeof(info->fix.id));
575 info->fix.type = FB_TYPE_PACKED_PIXELS;
576 info->fix.visual = FB_VISUAL_TRUECOLOR;
577 info->fix.xpanstep = 1;
578 info->fix.ypanstep = 1;
579 info->fix.accel = FB_ACCEL_NONE;
580 info->fix.smem_start = fb_phys;
581 info->fix.smem_len = fb_size;
582 info->fix.line_length = fb_data->xres * fb_data->bits_per_pixel / 8;
583 info->fix.line_length = stride;
585 info->var.xres = fb_data->xres;
586 info->var.yres = fb_data->yres;
587 info->var.xres_virtual = fb_data->xres;
588 info->var.yres_virtual = fb_data->yres * 2;
589 info->var.bits_per_pixel = fb_data->bits_per_pixel;
590 info->var.activate = FB_ACTIVATE_VBL;
591 info->var.height = tegra_dc_get_out_height(dc);
592 info->var.width = tegra_dc_get_out_width(dc);
593 info->var.pixclock = 0;
594 info->var.left_margin = 0;
595 info->var.right_margin = 0;
596 info->var.upper_margin = 0;
597 info->var.lower_margin = 0;
598 info->var.hsync_len = 0;
599 info->var.vsync_len = 0;
600 info->var.vmode = FB_VMODE_NONINTERLACED;
602 win->x.full = dfixed_const(0);
603 win->y.full = dfixed_const(0);
604 win->w.full = dfixed_const(fb_data->xres);
605 win->h.full = dfixed_const(fb_data->yres);
606 /* TODO: set to output res dc */
609 win->out_w = fb_data->xres;
610 win->out_h = fb_data->yres;
612 win->phys_addr = fb_phys;
613 win->virt_addr = fb_base;
614 win->phys_addr_u = 0;
615 win->phys_addr_v = 0;
616 win->stride = info->fix.line_length;
618 win->flags = TEGRA_WIN_FLAG_ENABLED;
621 tegra_fb_set_par(info);
623 if (register_framebuffer(info)) {
624 dev_err(&ndev->dev, "failed to register framebuffer\n");
629 tegra_fb->info = info;
631 dev_info(&ndev->dev, "probed\n");
633 if (fb_data->flags & TEGRA_FB_FLIP_ON_PROBE) {
634 tegra_dc_update_windows(&tegra_fb->win, 1);
635 tegra_dc_sync_windows(&tegra_fb->win, 1);
638 if (dc->mode.pclk > 1000) {
639 struct tegra_dc_mode *mode = &dc->mode;
641 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
642 info->var.pixclock = KHZ2PICOS(mode->rated_pclk / 1000);
644 info->var.pixclock = KHZ2PICOS(mode->pclk / 1000);
645 info->var.left_margin = mode->h_back_porch;
646 info->var.right_margin = mode->h_front_porch;
647 info->var.upper_margin = mode->v_back_porch;
648 info->var.lower_margin = mode->v_front_porch;
649 info->var.hsync_len = mode->h_sync_width;
650 info->var.vsync_len = mode->v_sync_width;
659 framebuffer_release(info);
664 void tegra_fb_unregister(struct tegra_fb_info *fb_info)
666 struct fb_info *info = fb_info->info;
668 unregister_framebuffer(info);
670 iounmap(info->screen_base);
671 framebuffer_release(info);