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-2012, NVIDIA CORPORATION, All rights reserved.
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>
41 #include <linux/console.h>
45 #include "nvmap/nvmap.h"
46 #include "dc/dc_priv.h"
48 /* Pad pitch to 16-byte boundary. */
49 #define TEGRA_LINEAR_PITCH_ALIGNMENT 32
51 struct tegra_fb_info {
52 struct tegra_dc_win *win;
53 struct nvhost_device *ndev;
57 struct resource *fb_mem;
63 /* palette array used by the fbcon */
64 static u32 pseudo_palette[16];
66 static int tegra_fb_check_var(struct fb_var_screeninfo *var,
69 struct tegra_fb_info *tegra_fb = info->par;
70 struct tegra_dc *dc = tegra_fb->win->dc;
71 struct tegra_dc_out_ops *ops = dc->out_ops;
72 struct fb_videomode mode;
74 if ((var->yres * var->xres * var->bits_per_pixel / 8 * 2) >
78 /* Apply mode filter for HDMI only -LVDS supports only fix mode */
79 if (ops && ops->mode_filter) {
81 fb_var_to_videomode(&mode, var);
82 if (!ops->mode_filter(dc, &mode))
85 /* Mode filter may have modified the mode */
86 fb_videomode_to_var(var, &mode);
89 /* Double yres_virtual to allow double buffering through pan_display */
90 var->yres_virtual = var->yres * 2;
95 static int tegra_fb_set_par(struct fb_info *info)
97 struct tegra_fb_info *tegra_fb = info->par;
98 struct fb_var_screeninfo *var = &info->var;
99 struct tegra_dc *dc = tegra_fb->win->dc;
101 if (var->bits_per_pixel) {
102 /* we only support RGB ordering for now */
103 switch (var->bits_per_pixel) {
107 var->green.offset = 8;
108 var->green.length = 8;
109 var->blue.offset = 16;
110 var->blue.length = 8;
111 var->transp.offset = 24;
112 var->transp.length = 8;
113 tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
116 var->red.offset = 11;
118 var->green.offset = 5;
119 var->green.length = 6;
120 var->blue.offset = 0;
121 var->blue.length = 5;
122 tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
128 /* if line_length unset, then pad the stride */
129 if (!info->fix.line_length) {
130 info->fix.line_length = var->xres * var->bits_per_pixel
132 info->fix.line_length = round_up(info->fix.line_length,
133 TEGRA_LINEAR_PITCH_ALIGNMENT);
135 tegra_fb->win->stride = info->fix.line_length;
136 tegra_fb->win->stride_uv = 0;
137 tegra_fb->win->phys_addr_u = 0;
138 tegra_fb->win->phys_addr_v = 0;
143 unsigned old_len = 0;
144 struct fb_videomode m;
145 struct fb_videomode *old_mode = NULL;
147 fb_var_to_videomode(&m, var);
149 /* Load framebuffer info with new mode details*/
150 old_mode = info->mode;
151 old_len = info->fix.line_length;
153 info->mode = (struct fb_videomode *)
154 fb_find_nearest_mode(&m, &info->modelist);
156 dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n");
157 info->mode = old_mode;
161 /* Update fix line_length and window stride as per new mode */
162 info->fix.line_length = var->xres * var->bits_per_pixel / 8;
163 info->fix.line_length = round_up(info->fix.line_length,
164 TEGRA_LINEAR_PITCH_ALIGNMENT);
165 tegra_fb->win->stride = info->fix.line_length;
168 * only enable stereo if the mode supports it and
171 stereo = !!(var->vmode & info->mode->vmode &
172 #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
173 FB_VMODE_STEREO_FRAME_PACK);
175 FB_VMODE_STEREO_LEFT_RIGHT);
178 /* Configure DC with new mode */
179 if (tegra_dc_set_fb_mode(dc, info->mode, stereo)) {
180 /* Error while configuring DC, fallback to old mode */
181 dev_warn(&tegra_fb->ndev->dev, "can't configure dc with mode %ux%u\n",
182 info->mode->xres, info->mode->yres);
183 info->mode = old_mode;
184 info->fix.line_length = old_len;
185 tegra_fb->win->stride = old_len;
189 /* Reflect mode chnage on DC HW */
191 tegra_dc_disable(dc);
194 tegra_fb->win->w.full = dfixed_const(info->mode->xres);
195 tegra_fb->win->h.full = dfixed_const(info->mode->yres);
196 tegra_fb->win->out_w = info->mode->xres;
197 tegra_fb->win->out_h = info->mode->yres;
202 static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
203 unsigned blue, unsigned transp, struct fb_info *info)
205 struct fb_var_screeninfo *var = &info->var;
207 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
208 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
214 red = (red >> (16 - info->var.red.length));
215 green = (green >> (16 - info->var.green.length));
216 blue = (blue >> (16 - info->var.blue.length));
218 v = (red << var->red.offset) |
219 (green << var->green.offset) |
220 (blue << var->blue.offset);
222 ((u32 *)info->pseudo_palette)[regno] = v;
229 static int tegra_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
231 struct tegra_fb_info *tegra_fb = info->par;
232 struct tegra_dc *dc = tegra_fb->win->dc;
234 u16 *red = cmap->red;
235 u16 *green = cmap->green;
236 u16 *blue = cmap->blue;
237 int start = cmap->start;
239 if (((unsigned)start > 255) || ((start + cmap->len) > 256))
242 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
243 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
245 * For now we are considering color schemes with
246 * cmap->len <=16 as special case of basic color
247 * scheme to support fbconsole.But for DirectColor
248 * visuals(like the one we actually have, that include
249 * a HW LUT),the way it's intended to work is that the
250 * actual LUT HW is programmed to the intended values,
251 * even for small color maps like those with 16 or fewer
252 * entries. The pseudo_palette is then programmed to the
253 * identity transform.
255 if (cmap->len <= 16) {
256 /* Low-color schemes like fbconsole*/
257 u16 *transp = cmap->transp;
258 u_int vtransp = 0xffff;
260 for (i = 0; i < cmap->len; i++) {
263 if (tegra_fb_setcolreg(start++, *red++,
269 /* High-color schemes*/
270 for (i = 0; i < cmap->len; i++) {
271 dc->fb_lut.r[start+i] = *red++ >> 8;
272 dc->fb_lut.g[start+i] = *green++ >> 8;
273 dc->fb_lut.b[start+i] = *blue++ >> 8;
275 tegra_dc_update_lut(dc, -1, -1);
281 static int tegra_fb_blank(int blank, struct fb_info *info)
283 struct tegra_fb_info *tegra_fb = info->par;
286 case FB_BLANK_UNBLANK:
287 dev_dbg(&tegra_fb->ndev->dev, "unblank\n");
288 tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
289 tegra_dc_enable(tegra_fb->win->dc);
292 case FB_BLANK_NORMAL:
293 dev_dbg(&tegra_fb->ndev->dev, "blank - normal\n");
294 tegra_dc_blank(tegra_fb->win->dc);
297 case FB_BLANK_VSYNC_SUSPEND:
298 case FB_BLANK_HSYNC_SUSPEND:
299 case FB_BLANK_POWERDOWN:
300 dev_dbg(&tegra_fb->ndev->dev, "blank - powerdown\n");
301 tegra_dc_disable(tegra_fb->win->dc);
309 static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
310 struct fb_info *info)
312 struct tegra_fb_info *tegra_fb = info->par;
313 char __iomem *flush_start;
314 char __iomem *flush_end;
317 if (!tegra_fb->win->cur_handle) {
318 flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
319 flush_end = flush_start + (var->yres * info->fix.line_length);
321 info->var.xoffset = var->xoffset;
322 info->var.yoffset = var->yoffset;
324 addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
325 (var->xoffset * (var->bits_per_pixel/8));
327 tegra_fb->win->phys_addr = addr;
328 tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
329 tegra_fb->win->virt_addr = info->screen_base;
331 tegra_dc_update_windows(&tegra_fb->win, 1);
332 tegra_dc_sync_windows(&tegra_fb->win, 1);
338 static void tegra_fb_fillrect(struct fb_info *info,
339 const struct fb_fillrect *rect)
341 cfb_fillrect(info, rect);
344 static void tegra_fb_copyarea(struct fb_info *info,
345 const struct fb_copyarea *region)
347 cfb_copyarea(info, region);
350 static void tegra_fb_imageblit(struct fb_info *info,
351 const struct fb_image *image)
353 cfb_imageblit(info, image);
356 static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
358 struct tegra_fb_info *tegra_fb = (struct tegra_fb_info *)info->par;
359 struct tegra_fb_modedb modedb;
360 struct fb_modelist *modelist;
361 struct fb_vblank vblank = {};
365 case FBIO_TEGRA_GET_MODEDB:
366 if (copy_from_user(&modedb, (void __user *)arg, sizeof(modedb)))
370 list_for_each_entry(modelist, &info->modelist, list) {
371 struct fb_var_screeninfo var;
373 if (i >= modedb.modedb_len)
376 /* fb_videomode_to_var doesn't fill out all the members
377 of fb_var_screeninfo */
378 memset(&var, 0x0, sizeof(var));
380 fb_videomode_to_var(&var, &modelist->mode);
382 if (copy_to_user((void __user *)&modedb.modedb[i],
387 if (var.vmode & FB_VMODE_STEREO_MASK) {
388 if (i >= modedb.modedb_len)
390 var.vmode &= ~FB_VMODE_STEREO_MASK;
392 (void __user *)&modedb.modedb[i],
398 modedb.modedb_len = i;
400 if (copy_to_user((void __user *)arg, &modedb, sizeof(modedb)))
405 tegra_dc_get_fbvblank(tegra_fb->win->dc, &vblank);
408 (void __user *)arg, &vblank, sizeof(vblank)))
412 case FBIO_WAITFORVSYNC:
413 return tegra_dc_wait_for_vsync(tegra_fb->win->dc);
422 int tegra_fb_get_mode(struct tegra_dc *dc) {
423 return dc->fb->info->mode->refresh;
426 int tegra_fb_set_mode(struct tegra_dc *dc, int fps) {
428 struct list_head *pos;
429 struct fb_videomode *best_mode = NULL;
430 int curr_diff = INT_MAX; /* difference of best_mode refresh rate */
431 struct fb_modelist *modelist;
432 struct fb_info *info = dc->fb->info;
434 list_for_each(pos, &info->modelist) {
435 struct fb_videomode *mode;
437 modelist = list_entry(pos, struct fb_modelist, list);
438 mode = &modelist->mode;
439 if (fps <= mode->refresh && curr_diff > (mode->refresh - fps)) {
440 curr_diff = mode->refresh - fps;
445 info->mode = best_mode;
446 stereo = !!(info->var.vmode & info->mode->vmode &
447 #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
448 FB_VMODE_STEREO_FRAME_PACK);
450 FB_VMODE_STEREO_LEFT_RIGHT);
452 return tegra_dc_set_fb_mode(dc, best_mode, stereo);
457 static struct fb_ops tegra_fb_ops = {
458 .owner = THIS_MODULE,
459 .fb_check_var = tegra_fb_check_var,
460 .fb_set_par = tegra_fb_set_par,
461 .fb_setcmap = tegra_fb_setcmap,
462 .fb_blank = tegra_fb_blank,
463 .fb_pan_display = tegra_fb_pan_display,
464 .fb_fillrect = tegra_fb_fillrect,
465 .fb_copyarea = tegra_fb_copyarea,
466 .fb_imageblit = tegra_fb_imageblit,
467 .fb_ioctl = tegra_fb_ioctl,
470 const struct fb_videomode *tegra_fb_find_best_mode(
471 struct fb_var_screeninfo *var,
472 struct list_head *head)
474 struct list_head *pos;
475 struct fb_modelist *modelist;
476 struct fb_videomode *mode, *best = NULL;
479 list_for_each(pos, head) {
482 modelist = list_entry(pos, struct fb_modelist, list);
483 mode = &modelist->mode;
485 if (mode->xres >= var->xres && mode->yres >= var->yres) {
486 d = (mode->xres - var->xres) +
487 (mode->yres - var->yres);
491 } else if (diff == d && best &&
492 mode->refresh > best->refresh)
499 static int tegra_fb_activate_mode(struct tegra_fb_info *fb_info,
500 struct fb_var_screeninfo *var)
503 struct fb_info *info = fb_info->info;
505 var->activate |= FB_ACTIVATE_FORCE;
507 info->flags |= FBINFO_MISC_USEREVENT;
508 err = fb_set_var(info, var);
509 info->flags &= ~FBINFO_MISC_USEREVENT;
516 void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
517 struct fb_monspecs *specs,
518 bool (*mode_filter)(const struct tegra_dc *dc,
519 struct fb_videomode *mode))
523 struct fb_event event;
524 struct fb_info *info = fb_info->info;
525 const struct fb_videomode *best_mode = NULL;
526 struct fb_var_screeninfo var = {0,};
528 mutex_lock(&fb_info->info->lock);
529 fb_destroy_modedb(fb_info->info->monspecs.modedb);
531 fb_destroy_modelist(&fb_info->info->modelist);
534 struct tegra_dc_mode mode;
535 memset(&fb_info->info->monspecs, 0x0,
536 sizeof(fb_info->info->monspecs));
537 memset(&mode, 0x0, sizeof(mode));
540 * reset video mode properties to prevent garbage being displayed on 'mode' device.
542 fb_info->info->mode = (struct fb_videomode*) NULL;
544 tegra_dc_set_mode(fb_info->win->dc, &mode);
545 mutex_unlock(&fb_info->info->lock);
549 memcpy(&fb_info->info->monspecs, specs,
550 sizeof(fb_info->info->monspecs));
551 fb_info->info->mode = specs->modedb;
553 /* Prepare a mode db */
554 for (i = 0; i < specs->modedb_len; i++) {
555 if (info->fbops->fb_check_var) {
556 struct fb_videomode m;
558 /* Call mode filter to check mode */
559 fb_videomode_to_var(&var, &specs->modedb[i]);
560 if (!(info->fbops->fb_check_var(&var, info))) {
561 fb_var_to_videomode(&m, &var);
563 &fb_info->info->modelist);
566 fb_add_videomode(&specs->modedb[i],
567 &fb_info->info->modelist);
571 /* Get the best mode from modedb and apply on fb */
574 best_mode = tegra_fb_find_best_mode(&var, &info->modelist);
576 /* Update framebuffer with best mode */
577 fb_videomode_to_var(&var, best_mode);
579 /* TODO: Get proper way of getting rid of a 0 bpp */
580 if (!var.bits_per_pixel)
581 var.bits_per_pixel = 32;
583 memcpy(&info->var, &var, sizeof(struct fb_var_screeninfo));
585 ret = tegra_fb_activate_mode(fb_info, &var);
589 event.info = fb_info->info;
591 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
592 /* Lock the console before sending the noti. Fbconsole
593 * on HDMI might be using console
597 fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
598 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
599 /* Unlock the console */
603 mutex_unlock(&fb_info->info->lock);
606 struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
608 struct tegra_fb_data *fb_data,
609 struct resource *fb_mem)
611 struct tegra_dc_win *win;
612 struct fb_info *info;
613 struct tegra_fb_info *tegra_fb;
614 void __iomem *fb_base = NULL;
615 unsigned long fb_size = 0;
616 unsigned long fb_phys = 0;
620 win = tegra_dc_get_window(dc, fb_data->win);
622 dev_err(&ndev->dev, "dc does not have a window at index %d\n",
624 return ERR_PTR(-ENOENT);
627 info = framebuffer_alloc(sizeof(struct tegra_fb_info), &ndev->dev);
633 tegra_fb = info->par;
635 tegra_fb->ndev = ndev;
636 tegra_fb->fb_mem = fb_mem;
637 tegra_fb->xres = fb_data->xres;
638 tegra_fb->yres = fb_data->yres;
641 fb_size = resource_size(fb_mem);
642 fb_phys = fb_mem->start;
643 fb_base = ioremap_nocache(fb_phys, fb_size);
645 dev_err(&ndev->dev, "fb can't be mapped\n");
649 tegra_fb->valid = true;
652 info->fix.line_length = fb_data->xres * fb_data->bits_per_pixel / 8;
654 stride = tegra_dc_get_stride(dc, 0);
655 if (!stride) /* default to pad the stride */
656 stride = round_up(info->fix.line_length,
657 TEGRA_LINEAR_PITCH_ALIGNMENT);
659 info->fbops = &tegra_fb_ops;
660 info->pseudo_palette = pseudo_palette;
661 info->screen_base = fb_base;
662 info->screen_size = fb_size;
664 strlcpy(info->fix.id, "tegra_fb", sizeof(info->fix.id));
665 info->fix.type = FB_TYPE_PACKED_PIXELS;
666 info->fix.visual = FB_VISUAL_TRUECOLOR;
667 info->fix.xpanstep = 1;
668 info->fix.ypanstep = 1;
669 info->fix.accel = FB_ACCEL_NONE;
670 info->fix.smem_start = fb_phys;
671 info->fix.smem_len = fb_size;
672 info->fix.line_length = stride;
674 info->var.xres = fb_data->xres;
675 info->var.yres = fb_data->yres;
676 info->var.xres_virtual = fb_data->xres;
677 info->var.yres_virtual = fb_data->yres * 2;
678 info->var.bits_per_pixel = fb_data->bits_per_pixel;
679 info->var.activate = FB_ACTIVATE_VBL;
680 info->var.height = tegra_dc_get_out_height(dc);
681 info->var.width = tegra_dc_get_out_width(dc);
682 info->var.pixclock = 0;
683 info->var.left_margin = 0;
684 info->var.right_margin = 0;
685 info->var.upper_margin = 0;
686 info->var.lower_margin = 0;
687 info->var.hsync_len = 0;
688 info->var.vsync_len = 0;
689 info->var.vmode = FB_VMODE_NONINTERLACED;
691 win->x.full = dfixed_const(0);
692 win->y.full = dfixed_const(0);
693 win->w.full = dfixed_const(fb_data->xres);
694 win->h.full = dfixed_const(fb_data->yres);
695 /* TODO: set to output res dc */
698 win->out_w = fb_data->xres;
699 win->out_h = fb_data->yres;
701 win->phys_addr = fb_phys;
702 win->virt_addr = fb_base;
703 win->phys_addr_u = 0;
704 win->phys_addr_v = 0;
705 win->stride = info->fix.line_length;
707 win->flags = TEGRA_WIN_FLAG_ENABLED;
710 tegra_fb_set_par(info);
712 if (register_framebuffer(info)) {
713 dev_err(&ndev->dev, "failed to register framebuffer\n");
718 tegra_fb->info = info;
720 dev_info(&ndev->dev, "probed\n");
722 if (fb_data->flags & TEGRA_FB_FLIP_ON_PROBE) {
723 tegra_dc_update_windows(&tegra_fb->win, 1);
724 tegra_dc_sync_windows(&tegra_fb->win, 1);
727 if (dc->mode.pclk > 1000) {
728 struct tegra_dc_mode *mode = &dc->mode;
729 struct fb_videomode vmode;
731 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
732 info->var.pixclock = KHZ2PICOS(mode->rated_pclk / 1000);
734 info->var.pixclock = KHZ2PICOS(mode->pclk / 1000);
735 info->var.left_margin = mode->h_back_porch;
736 info->var.right_margin = mode->h_front_porch;
737 info->var.upper_margin = mode->v_back_porch;
738 info->var.lower_margin = mode->v_front_porch;
739 info->var.hsync_len = mode->h_sync_width;
740 info->var.vsync_len = mode->v_sync_width;
742 /* Keep info->var consistent with info->modelist. */
743 fb_var_to_videomode(&vmode, &info->var);
744 fb_add_videomode(&vmode, &info->modelist);
753 framebuffer_release(info);
758 void tegra_fb_unregister(struct tegra_fb_info *fb_info)
760 struct fb_info *info = fb_info->info;
762 unregister_framebuffer(info);
764 iounmap(info->screen_base);
765 framebuffer_release(info);