summaryrefslogtreecommitdiff
path: root/drivers/video/tegra-fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra-fb.c')
-rw-r--r--drivers/video/tegra-fb.c125
1 files changed, 116 insertions, 9 deletions
diff --git a/drivers/video/tegra-fb.c b/drivers/video/tegra-fb.c
index 24a90213ecdc..fa18ad494c79 100644
--- a/drivers/video/tegra-fb.c
+++ b/drivers/video/tegra-fb.c
@@ -3,7 +3,7 @@
*
* Dumb framebuffer driver for NVIDIA Tegra SoCs
*
- * Copyright (C) 2009 NVIDIA Corporation
+ * Copyright (C) 2009 - 2010 NVIDIA Corporation
*
* 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
@@ -37,6 +37,7 @@
#include "nvbootargs.h"
#include "nvrm_module.h"
#include "nvrm_memmgr.h"
+#include "nvrm_power.h"
#include "nvrm_ioctls.h"
static struct fb_info tegra_fb_info = {
@@ -50,6 +51,8 @@ static struct fb_info tegra_fb_info = {
.line_length = 800 * 2,
},
+ // these values are just defaults. they will be over-written with the
+ // correct values from the boot args.
.var = {
.xres = 800,
.yres = 480,
@@ -74,12 +77,19 @@ static struct fb_info tegra_fb_info = {
},
};
-unsigned long s_fb_addr;
-unsigned long s_fb_size;
-unsigned long s_fb_width;
-unsigned long s_fb_height;
-int s_fb_Bpp;
-NvRmMemHandle s_fb_hMem;
+static unsigned long s_fb_addr;
+static unsigned long s_fb_size;
+static unsigned long s_fb_width;
+static unsigned long s_fb_height;
+static int s_fb_Bpp;
+static NvRmMemHandle s_fb_hMem;
+static unsigned long *s_fb_regs;
+static unsigned short s_use_tearing_effect;
+static unsigned long s_power_id = (unsigned long)-1;
+
+#define DISPLAY_BASE (0x54200000)
+#define REGW( reg, val ) \
+ *(s_fb_regs + (reg)) = (val)
/* palette attary used by the fbcon */
u32 pseudo_palette[16];
@@ -159,6 +169,85 @@ int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
+static NvBool tegra_fb_power_register( void )
+{
+ if( s_power_id != (unsigned long)-1 )
+ {
+ return NV_TRUE;
+ }
+
+ if( NvRmPowerRegister( s_hRmGlobal, 0, &s_power_id ) != NvSuccess )
+ {
+ printk( "nvtegrafb: unable to load power manager\n" );
+ return NV_FALSE;
+ }
+
+ return NV_TRUE;
+}
+
+static NvBool tegra_fb_power_on( void )
+{
+ if( NvRmPowerVoltageControl( s_hRmGlobal,
+ NVRM_MODULE_ID( NvRmModuleID_GraphicsHost, 0 ),
+ s_power_id, NvRmVoltsUnspecified, NvRmVoltsUnspecified,
+ NULL, 0, NULL ) != NvSuccess )
+ {
+ printk( "nvtegrafb: unable to enable graphics host power\n" );
+ return NV_FALSE;
+ }
+
+ if( NvRmPowerVoltageControl( s_hRmGlobal,
+ NVRM_MODULE_ID( NvRmModuleID_Display, 0 ),
+ s_power_id, NvRmVoltsUnspecified, NvRmVoltsUnspecified,
+ NULL, 0, NULL ) != NvSuccess )
+ {
+ printk( "nvtegrafb: unable to enable display power\n" );
+ return NV_FALSE;
+ }
+
+ NvRmPowerModuleClockControl( s_hRmGlobal, NvRmModuleID_GraphicsHost,
+ s_power_id, NV_TRUE );
+
+ return NV_TRUE;
+}
+
+static void tegra_fb_power_off( void )
+{
+ // this will most likely not actually disable power to the display,
+ // but will make it such that the power reference count is correct
+ NvRmPowerVoltageControl( s_hRmGlobal,
+ NVRM_MODULE_ID( NvRmModuleID_GraphicsHost, 0 ),
+ s_power_id, NvRmVoltsOff, NvRmVoltsOff,
+ NULL, 0, NULL );
+
+ NvRmPowerVoltageControl( s_hRmGlobal,
+ NVRM_MODULE_ID( NvRmModuleID_Display, 0 ),
+ s_power_id, NvRmVoltsOff, NvRmVoltsOff,
+ NULL, 0, NULL );
+
+ NvRmPowerModuleClockControl( s_hRmGlobal, NvRmModuleID_GraphicsHost,
+ s_power_id, NV_FALSE );
+}
+
+static void tegra_fb_trigger_frame( void )
+{
+ if( !s_use_tearing_effect )
+ {
+ return;
+ }
+
+ if( !tegra_fb_power_on() )
+ {
+ return;
+ }
+
+ // state control: write the host trigger bit (24) along with a general
+ // activation request (bit 0)
+ REGW( 0x41, (1 << 24) | 1 );
+
+ tegra_fb_power_off();
+}
+
int tegra_fb_blank(int blank, struct fb_info *info)
{
return 0;
@@ -167,16 +256,19 @@ int tegra_fb_blank(int blank, struct fb_info *info)
void tegra_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
cfb_fillrect(info, rect);
+ tegra_fb_trigger_frame();
}
void tegra_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
cfb_copyarea(info, region);
+ tegra_fb_trigger_frame();
}
void tegra_fb_imageblit(struct fb_info *info, const struct fb_image *image)
{
cfb_imageblit(info, image);
+ tegra_fb_trigger_frame();
}
int tegra_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
@@ -196,23 +288,34 @@ static int tegra_plat_probe( struct platform_device *d )
e = NvOsBootArgGet(NvBootArgKey_Framebuffer, &boot_fb, sizeof(boot_fb));
if (e != NvSuccess || !boot_fb.MemHandleKey) {
- printk("tegrafb: bootargs not found\n");
+ printk("nvtegrafb: bootargs not found\n");
return -1;
}
e = NvRmMemHandleClaimPreservedHandle(s_hRmGlobal, boot_fb.MemHandleKey,
&s_fb_hMem );
if (e != NvSuccess) {
- printk("tegrafb: Unable to query bootup framebuffer memory.\n");
+ printk("nvtegrafb: Unable to query bootup framebuffer memory.\n");
return -1;
}
+ tegra_fb_power_register();
+
s_fb_width = boot_fb.Width;
s_fb_height = boot_fb.Height * boot_fb.NumSurfaces;
s_fb_size = boot_fb.Size;
s_fb_addr = NvRmMemPin(s_fb_hMem);
s_fb_Bpp = NV_COLOR_GET_BPP(boot_fb.ColorFormat) >> 3;
+ /* need to poke a trigger register if the tearing effect signal is
+ * used
+ */
+ if( boot_fb.Flags & NVBOOTARG_FB_FLAG_TEARING_EFFECT )
+ {
+ s_fb_regs = ioremap_nocache( DISPLAY_BASE, 256 * 1024 );
+ s_use_tearing_effect = 1;
+ }
+
tegra_fb_info.fix.smem_start = s_fb_addr;
tegra_fb_info.fix.smem_len = s_fb_size;
tegra_fb_info.fix.line_length = boot_fb.Pitch;
@@ -281,6 +384,10 @@ static int __init tegra_fb_init(void)
static void __exit tegra_exit( void )
{
+ tegra_fb_power_off();
+
+ NvRmPowerUnRegister( s_hRmGlobal, s_power_id );
+
unregister_framebuffer(&tegra_fb_info);
}
module_exit(tegra_exit);