diff options
-rw-r--r-- | arch/arm/mach-tegra/include/nvbootargs.h | 16 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvos/nvos.c | 16 | ||||
-rw-r--r-- | drivers/video/tegra-fb.c | 125 |
3 files changed, 141 insertions, 16 deletions
diff --git a/arch/arm/mach-tegra/include/nvbootargs.h b/arch/arm/mach-tegra/include/nvbootargs.h index 908c26f0ea52..2e11843a9a68 100644 --- a/arch/arm/mach-tegra/include/nvbootargs.h +++ b/arch/arm/mach-tegra/include/nvbootargs.h @@ -94,6 +94,7 @@ typedef struct NvBootArgsCarveoutRec */ typedef struct NvBootArgsWarmbootRec { + /* The key used for accessing the preserved memory handle */ NvU32 MemHandleKey; } NvBootArgsWarmboot; @@ -112,7 +113,6 @@ typedef struct NvBootArgsPreservedMemHandleRec NvU32 Size; } NvBootArgsPreservedMemHandle; - /** * Display boot args, indexed by NvBootArgKey_Display. * @@ -162,6 +162,16 @@ typedef struct NvBootArgsFramebufferRec * assumed to begin at Pitch * Height bytes from the * previous surface. */ NvU8 NumSurfaces; + /* Flags for future expandability. + * Current allowable flags are: + * zero - default + * NV_BOOT_ARGS_FB_FLAG_TEARING_EFFECT - use a tearing effect signal in + * combination with a trigger from the display software to generate + * a frame of pixels for the display device. + */ + NvU32 Flags; +#define NVBOOTARG_FB_FLAG_TEARING_EFFECT (0x1) + } NvBootArgsFramebuffer; /** @@ -210,8 +220,8 @@ typedef struct NvBootArgsChipShmooPhysRec NvU32 Size; } NvBootArgsChipShmooPhys; -#define NVBOOTARG_NUM_PRESERVED_HANDLES (NvBootArgKey_PreservedMemHandle_Num - \ - NvBootArgKey_PreservedMemHandle_0) +#define NVBOOTARG_NUM_PRESERVED_HANDLES \ + (NvBootArgKey_PreservedMemHandle_Num - NvBootArgKey_PreservedMemHandle_0) /** * OS-agnostic bootarg structure. diff --git a/arch/arm/mach-tegra/nvos/nvos.c b/arch/arm/mach-tegra/nvos/nvos.c index 9b4329b97dc4..4de8cd4be33f 100644 --- a/arch/arm/mach-tegra/nvos/nvos.c +++ b/arch/arm/mach-tegra/nvos/nvos.c @@ -1445,8 +1445,7 @@ NvError NvOsBootArgGet(NvU32 key, void *arg, NvU32 size) } else { - switch (key) - { + switch (key) { case NvBootArgKey_ChipShmoo: src = &s_BootArgs.ChipShmooArgs; size_src = sizeof(NvBootArgsChipShmoo); @@ -1478,10 +1477,19 @@ NvError NvOsBootArgGet(NvU32 key, void *arg, NvU32 size) } } - if (!arg || !src || (size_src!=size)) + if( !arg || !src ) + { return NvError_BadParameter; + } - NvOsMemcpy(arg, src, size_src); + /* don't copy too much if the size has changed (gotten bigger in new + * binaries. + */ + NvOsMemcpy(arg, src, NV_MIN( size, size_src) ); + if( size > size_src ) + { + NvOsMemset( (NvU8 *)src + size_src, 0, size - size_src ); + } return NvSuccess; } 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); |