// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// omap3530/beagle_drivers/lcd/lcd.cpp
// Implementation of an LCD driver.
// This file is part of the Beagle Base port
// N.B. This sample code assumes that the display supports setting the backlight on or off,
// as well as adjusting the contrast and the brightness.
//
#include <videodriver.h>
#include <platform.h>
#include <nkern.h>
#include <kernel.h>
#include <kern_priv.h>
#include <kpower.h>
#include <assp/omap3530_assp/omap3530_assp_priv.h>
#include <assp/omap3530_assp/omap3530_hardware_base.h>
#include <assp/omap3530_assp/omap3530_prcm.h>
#define DSS_SYSCONFIG 0x48050010
#define DISPC_SYSSTATUS 0x48050414
#define DISPC_SYSCONFIG 0x48050410
#define DISPC_CONFIG 0x48050444
#define DISPC_DEFAULT_COLOR0 0x4805044c
#define DISPC_TRANS_COLOR0 0x48050454
#define DISPC_TIMING_H 0x48050464
#define DISPC_TIMING_V 0x48050468
#define DISPC_POL_FREQ 0x4805046c
#define DISPC_DIVISOR 0x48050470
#define DISPC_SIZE_LCD 0x4805047c
#define DISPC_GFX_BA1 0x48050480
#define DISPC_GFX_BA2 0x48050484
#define DISPC_GFX_POSITION 0x48050488
#define DISPC_GFX_SIZE 0x4805048c
#define DISPC_GFX_ATTRIBUTES 0x480504a0
#define DISPC_GFX_FIFO_THRESHOLD 0x480504a4
#define DISPC_GFX_FIFO_SIZE_STATUS 0x480504a8
#define DISPC_GFX_ROW_INC 0x480504ac
#define DISPC_GFX_PIXEL_INC 0x480504b0
#define DISPC_GFX_WINDOW_SKIP 0x480504b4
#define DISPC_GFX_TABLE_BA 0x480504b8
#define DISPC_CONTROL 0x48050440
#define GET_REGISTER(Reg) *( (TUint *) Omap3530HwBase::TVirtual<Reg>::Value )
#define SET_REGISTER(Reg,Val) *( (TUint *) Omap3530HwBase::TVirtual<Reg>::Value ) = Val
#define _MODE_1280x1024_
//#define _MODE_1024x768_
#ifdef _MODE_800x600_
// ModeLine "800x600@60" 40.0 800 840 968 1056 600 601 605 628 +hsync +vsync
// Decoded by: http://www.tkk.fi/Misc/Electronics/faq/vga2rgb/calc.html
# define PIXEL_CLK 40000
# define H_DISP 800
# define H_FPORCH 40
# define H_SYNC 128
# define H_BPORCH 88
# define H_SYNC_POL 1
# define V_DISP 600
# define V_FPORCH 1
# define V_SYNC 4
# define V_BPORCH 23
# define V_SYNC_POL 1
# define INTERLACE_ENABLE 0
#endif
#ifdef _MODE_1024x768_
// ModeLine "1024x768@60" 65.0 1024 1048 1184 1344 768 771 777 806 -hsync -vsync
// Decoded by: http://www.tkk.fi/Misc/Electronics/faq/vga2rgb/calc.html
# define PIXEL_CLK 65000
# define H_DISP 1024
# define H_FPORCH 24
# define H_SYNC 136
# define H_BPORCH 160
# define H_SYNC_POL 0
# define V_DISP 768
# define V_FPORCH 3
# define V_SYNC 6
# define V_BPORCH 29
# define V_SYNC_POL 0
# define INTERLACE_ENABLE 0
#endif
#ifdef _MODE_1280x1024_
// ModeLine "1280x1024@60" 108.0 1280 1328 1440 1688 1024 1025 1028 1066 +hsync +vsync
// Decoded by: http://www.tkk.fi/Misc/Electronics/faq/vga2rgb/calc.html
# define PIXEL_CLK 108000
# define H_DISP 1280
# define H_FPORCH 48
# define H_SYNC 112
# define H_BPORCH 248
# define H_SYNC_POL 1
# define V_DISP 1024
# define V_FPORCH 1
# define V_SYNC 3
# define V_BPORCH 38
# define V_SYNC_POL 1
# define INTERLACE_ENABLE 0
#endif
// TO DO: (mandatory)
// If the display supports Contrast and/or Brightness control then supply the following defines:
// This is only example code... you may need to modify it for your hardware
const TInt KConfigInitialDisplayContrast = 128;
const TInt KConfigLcdMinDisplayContrast = 1;
const TInt KConfigLcdMaxDisplayContrast = 255;
const TInt KConfigInitialDisplayBrightness = 128;
const TInt KConfigLcdMinDisplayBrightness = 1;
const TInt KConfigLcdMaxDisplayBrightness = 255;
// TO DO: (mandatory)
// define a macro to calculate the screen buffer size
// This is only example code... you may need to modify it for your hardware
// aBpp is the number of bits-per-pixel, aPpl is the number of pixels per line and
// aLpp number of lines per panel
#define FRAME_BUFFER_SIZE(aBpp,aPpl,aLpp) (aBpp*aPpl*aLpp)/8
// TO DO: (mandatory)
// define the physical screen dimensions
// This is only example code... you need to modify it for your hardware
const TUint KConfigLcdWidth = 360;//640; // 640 pixels per line
const TUint KConfigLcdHeight = 640;//480; // 480 lines per panel
// TO DO: (mandatory)
// define the characteristics of the LCD display
// This is only example code... you need to modify it for your hardware
const TBool KConfigLcdIsMono = EFalse;
const TBool KConfigLcdPixelOrderLandscape = ETrue;
const TBool KConfigLcdPixelOrderRGB = ETrue;
const TInt KConfigLcdMaxDisplayColors = 65536; //24bit: 16777216;
// TO DO: (mandatory)
// define the display dimensions in TWIPs
// A TWIP is a 20th of a point. A point is a 72nd of an inch
// Therefore a TWIP is a 1440th of an inch
// This is only example code... you need to modify it for your hardware
const TInt KConfigLcdWidthInTwips = 9638;//10800; // = 6.69 inches //15*1440;
const TInt KConfigLcdHeightInTwips = 7370;//11232;//5616; // = 5.11 inches //12*1440;
// TO DO: (mandatory)
// define the available display modes
// This is only example code... you need to modify it for your hardware
const TInt KConfigLcdNumberOfDisplayModes = 1;
const TInt KConfigLcdInitialDisplayMode = 0;
struct SLcdConfig
{
TInt iMode;
TInt iOffsetToFirstVideoBuffer;
TInt iLenghtOfVideoBufferInBytes;
TInt iOffsetBetweenLines;
TBool iIsPalettized;
TInt iBitsPerPixel;
};
static const SLcdConfig Lcd_Mode_Config[KConfigLcdNumberOfDisplayModes]=
{
{
0, // iMode
0, // iOffsetToFirstVideoBuffer
FRAME_BUFFER_SIZE(16, KConfigLcdWidth, KConfigLcdHeight), // iLenghtOfVideoBufferInBytes
KConfigLcdWidth*2, // iOffsetBetweenLines
EFalse, // iIsPalettized
16 // iBitsPerPixel
}
};
_LIT(KLitLcd,"LCD");
//
// TO DO: (optional)
//
// Add any private functions and data you require
//
NONSHARABLE_CLASS(DLcdPowerHandler) : public DPowerHandler
{
public:
DLcdPowerHandler();
// from DPowerHandler
void PowerDown(TPowerState);
void PowerUp();
void PowerUpDfc();
void PowerDownDfc();
TInt Create();
void DisplayOn();
void DisplayOff();
TInt HalFunction(TInt aFunction, TAny* a1, TAny* a2);
void PowerUpLcd(TBool aSecure);
void PowerDownLcd();
void ScreenInfo(TScreenInfoV01& aInfo);
void WsSwitchOnScreen();
void WsSwitchOffScreen();
void HandleMsg();
void SwitchDisplay(TBool aSecure);
void SetBacklightState(TBool aState);
void BacklightOn();
void BacklightOff();
TInt SetContrast(TInt aContrast);
TInt SetBrightness(TInt aBrightness);
private:
TInt SetPaletteEntry(TInt aEntry, TInt aColor);
TInt GetPaletteEntry(TInt aEntry, TInt* aColor);
TInt NumberOfPaletteEntries();
TInt GetCurrentDisplayModeInfo(TVideoInfoV01& aInfo, TBool aSecure);
TInt GetSpecifiedDisplayModeInfo(TInt aMode, TVideoInfoV01& aInfo);
TInt SetDisplayMode(TInt aMode);
void SplashScreen();
TInt GetDisplayColors(TInt* aColors);
private:
TBool iIsPalettized;
TBool iDisplayOn; // to prevent a race condition with WServer trying to power up/down at the same time
DPlatChunkHw* iChunk;
DPlatChunkHw* iSecureChunk;
TBool iWsSwitchOnScreen;
TBool iSecureDisplay;
TDfcQue* iDfcQ;
TMessageQue iMsgQ;
TDfc iPowerUpDfc;
TDfc iPowerDownDfc;
TVideoInfoV01 iVideoInfo;
TVideoInfoV01 iSecureVideoInfo;
NFastMutex iLock; // protects against being preempted whilst manipulating iVideoInfo/iSecureVideoInfo
TPhysAddr ivRamPhys;
TPhysAddr iSecurevRamPhys;
TBool iBacklightOn;
TInt iContrast;
TInt iBrightness;
};
/**
HAL handler function
@param aPtr a pointer to an instance of DLcdPowerHandler
@param aFunction the function number
@param a1 an arbitrary parameter
@param a2 an arbitrary parameter
*/
LOCAL_C TInt halFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
{
DLcdPowerHandler* pH=(DLcdPowerHandler*)aPtr;
return pH->HalFunction(aFunction,a1,a2);
}
/**
DFC for receiving messages from the power handler
@param aPtr a pointer to an instance of DLcdPowerHandler
*/
void rxMsg(TAny* aPtr)
{
DLcdPowerHandler& h=*(DLcdPowerHandler*)aPtr;
h.HandleMsg();
}
/**
DFC for powering up the device
@param aPtr aPtr a pointer to an instance of DLcdPowerHandler
*/
void power_up_dfc(TAny* aPtr)
{
((DLcdPowerHandler*)aPtr)->PowerUpDfc();
}
/**
DFC for powering down the device
@param aPtr aPtr a pointer to an instance of DLcdPowerHandler
*/
void power_down_dfc(TAny* aPtr)
{
((DLcdPowerHandler*)aPtr)->PowerDownDfc();
}
/**
Default constructor
*/
DLcdPowerHandler::DLcdPowerHandler() :
DPowerHandler(KLitLcd),
iMsgQ(rxMsg,this,NULL,1),
iPowerUpDfc(&power_up_dfc,this,6),
iPowerDownDfc(&power_down_dfc,this,7),
iBacklightOn(EFalse),
iContrast(KConfigInitialDisplayContrast),
iBrightness(KConfigInitialDisplayBrightness)
{
}
/**
Second-phase constructor
Called by factory function at ordinal 0
*/
TInt DLcdPowerHandler::Create()
{
iDfcQ=Kern::DfcQue0(); // use low priority DFC queue for this driver
// map the video RAM
//TPhysAddr videoRamPhys;
TInt vSize = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iLenghtOfVideoBufferInBytes; //KConfigLcdWidth*KConfigLcdHeight*3; //VideoRamSize();
TInt r = Epoc::AllocPhysicalRam( 2*vSize, ivRamPhys );
if ( r!=KErrNone )
{
Kern::Fault( "AllocVRam", r );
}
//TInt vSize = ((Omap3530BoardAssp*)Arch::TheAsic())->VideoRamSize();
//ivRamPhys = TOmap3530Assp::VideoRamPhys(); // EXAMPLE ONLY: assume TOmap3530Assp interface class
r = DPlatChunkHw::New(iChunk,ivRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC);
if (r != KErrNone)
return r;
//create "secure" screen immediately after normal one
iSecurevRamPhys = ivRamPhys + vSize;
TInt r2 = DPlatChunkHw::New(iSecureChunk,iSecurevRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC);
if (r2 != KErrNone)
return r2;
TUint* pV=(TUint*)iChunk->LinearAddress();
__KTRACE_OPT(KEXTENSION,Kern::Printf("DLcdPowerHandler::Create: VideoRamSize=%x, VideoRamPhys=%08x, VideoRamLin=%08x",vSize,ivRamPhys,pV));
// TO DO: (mandatory)
// initialise the palette for the initial display mode
// NOTE: the palette could either be a buffer allocated in system RAM (usually contiguous to Video buffer)
// or could be offered as part of the hardware block that implemenst the lcd control
//
TUint* pV2=(TUint*)iSecureChunk->LinearAddress();
__KTRACE_OPT(KEXTENSION,Kern::Printf("DLcdPowerHandler::Create: Secure display VideoRamSize=%x, VideoRamPhys=%08x, VideoRamLin=%08x",vSize,iSecurevRamPhys,pV2));
// TO DO: (mandatory)
// initialise the secure screen's palette for the initial display mode
//
// setup the video info structure, this'll be used to remember the video settings
iVideoInfo.iDisplayMode = KConfigLcdInitialDisplayMode;
iVideoInfo.iOffsetToFirstPixel = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iOffsetToFirstVideoBuffer;
iVideoInfo.iIsPalettized = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iIsPalettized;
iVideoInfo.iOffsetBetweenLines = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iOffsetBetweenLines;
iVideoInfo.iBitsPerPixel = Lcd_Mode_Config[KConfigLcdInitialDisplayMode].iBitsPerPixel;
iVideoInfo.iSizeInPixels.iWidth = KConfigLcdWidth;
iVideoInfo.iSizeInPixels.iHeight = KConfigLcdHeight;
iVideoInfo.iSizeInTwips.iWidth = KConfigLcdWidthInTwips;
iVideoInfo.iSizeInTwips.iHeight = KConfigLcdHeightInTwips;
iVideoInfo.iIsMono = KConfigLcdIsMono;
iVideoInfo.iVideoAddress=(TInt)pV;
iVideoInfo.iIsPixelOrderLandscape = KConfigLcdPixelOrderLandscape;
iVideoInfo.iIsPixelOrderRGB = KConfigLcdPixelOrderRGB;
iSecureVideoInfo = iVideoInfo;
iSecureVideoInfo.iVideoAddress = (TInt)pV2;
iDisplayOn = EFalse;
iSecureDisplay = EFalse;
// install the HAL function
r=Kern::AddHalEntry(EHalGroupDisplay, halFunction, this);
if (r!=KErrNone)
return r;
iPowerUpDfc.SetDfcQ(iDfcQ);
iPowerDownDfc.SetDfcQ(iDfcQ);
iMsgQ.SetDfcQ(iDfcQ);
iMsgQ.Receive();
// install the power handler
// power up the screen
Add();
DisplayOn();
SplashScreen();
return KErrNone;
}
/**
Turn the display on
May be called as a result of a power transition or from the HAL
If called from HAL, then the display may be already be on (iDisplayOn == ETrue)
*/
void DLcdPowerHandler::DisplayOn()
{
__KTRACE_OPT(KBOOT, Kern::Printf("DisplayOn %d", iDisplayOn));
if (!iDisplayOn) // may have been powered up already
{
iDisplayOn = ETrue;
PowerUpLcd(iSecureDisplay);
SetContrast(iContrast);
SetBrightness(iBrightness);
}
}
/**
Turn the display off
May be called as a result of a power transition or from the HAL
If called from Power Manager, then the display may be already be off (iDisplayOn == EFalse)
if the platform is in silent running mode
*/
void DLcdPowerHandler::DisplayOff()
{
__KTRACE_OPT(KBOOT, Kern::Printf("DisplayOff %d", iDisplayOn));
if (iDisplayOn)
{
iDisplayOn = EFalse;
PowerDownLcd();
}
}
/**
Switch between secure and non-secure displays
@param aSecure ETrue if switching to secure display
*/
void DLcdPowerHandler::SwitchDisplay(TBool aSecure)
{
if (aSecure)
{
if (!iSecureDisplay)
{
//switch to secure display
DisplayOff();
iSecureDisplay = ETrue;
DisplayOn();
}
}
else
{
if (iSecureDisplay)
{
//switch from secure display
DisplayOff();
iSecureDisplay = EFalse;
DisplayOn();
}
}
}
/**
DFC to power up the display
*/
void DLcdPowerHandler::PowerUpDfc()
{
__KTRACE_OPT(KPOWER, Kern::Printf("PowerUpDfc"));
DisplayOn();
PowerUpDone(); // must be called from a different thread than PowerUp()
}
/**
DFC to power down the display
*/
void DLcdPowerHandler::PowerDownDfc()
{
__KTRACE_OPT(KPOWER, Kern::Printf("PowerDownDfc"));
DisplayOff();
PowerDownDone(); // must be called from a different thread than PowerUp()
}
/**
Schedule the power-down DFC
*/
void DLcdPowerHandler::PowerDown(TPowerState)
{
iPowerDownDfc.Enque(); // schedules DFC to execute on this driver's thread
}
/**
Schedule the power-up DFC
*/
void DLcdPowerHandler::PowerUp()
{
iPowerUpDfc.Enque(); // schedules DFC to execute on this driver's thread
}
/**
Power up the display
@param aSecure ETrue if powering up the secure display
*/
void DLcdPowerHandler::PowerUpLcd(TBool aSecure)
{
TUint32 l = 0x0;
// Set up the Display Subsystem to control a DVI monitor
// The following four lines need to be replaced by a call to the GPIO driver which should call the PowerClock driver
// PowerClock::GpioActive(0, PowerClock::E1s, PowerClock::ECpu10, PowerClock::EBus10);
// PowerClock::GpioAccess(0, PowerClock::EAuto);
Prcm::SetClockState( Prcm::EClkGpio1_F, Prcm::EClkOn );
Prcm::SetClockState( Prcm::EClkGpio1_I, Prcm::EClkAuto );
*( (TUint *) Omap3530HwBase::TVirtual<0x48310034>::Value ) = 0xfefffedf; //GPIO1 output enable p3336
*( (TUint *) Omap3530HwBase::TVirtual<0x48310094>::Value ) = 0x01000120; //GPIO1 set data out p3336
// const TUint KCM_CLKSEL_DSS = Omap3530HwBase::TVirtual<0x48004E40>::Value;
// Prcm::Set(KCM_CLKSEL_DSS, 0xffffffffu, 0x00001006);
Prcm::SetDivider( Prcm::EClkDss1_F, 2 );
Prcm::SetDivider( Prcm::EClkTv_F, 1 );
SET_REGISTER( DSS_SYSCONFIG, 0x00000010 ); // Display Subsystem reset
while ( !( GET_REGISTER( DISPC_SYSSTATUS ) & 1 ) ); // Spin until reset complete
TInt8 MIDLEMODE = 0x2; // Smart Standby. MStandby is asserted based on the internal activity of the module.
TInt8 CLOCKACTIVITY = 0x0; // interface and functional clocks can be switched off.
TInt8 SIDLEMODE = 0x2; // Smart idle. Idle request is acknowledged based on the internal activity of the module
TInt8 ENWAKEUP = 0x1; // Wakeup is enabled.
TInt8 SOFTRESET = 0x0; // Normal mode
TInt8 AUTOIDLE = 0x1; // Automatic L3 and L4 interface clock gating strategy is applied based on interface activity
l = MIDLEMODE<<12 | CLOCKACTIVITY<<8 | SIDLEMODE<<3 | ENWAKEUP<<2 | SOFTRESET<<1 | AUTOIDLE;
SET_REGISTER( DISPC_SYSCONFIG, l );
TInt8 LOADMOAD = 0x2; //Frame data only loaded every frame
l = LOADMOAD<<1;
SET_REGISTER( DISPC_CONFIG, l );
SET_REGISTER( DISPC_DEFAULT_COLOR0, 0xFFFFFFFF );
SET_REGISTER( DISPC_TRANS_COLOR0, 0x00000000 );
TUint8 hbp = H_BPORCH - 1; // Horizontal Back Porch
TUint8 hfp = H_FPORCH - 1; // Horizontal front porch
TUint8 hsw = H_SYNC - 1; // Horizontal synchronization pulse width
if ( hsw > 63 )
{
hsw = 63;
Kern::Printf("[LCD] H_SYNC too big");
}
l = hbp<<20 | hfp<<8 | hsw;
SET_REGISTER( DISPC_TIMING_H, l );
TUint8 vbp = V_BPORCH; // Vertical back porch
TUint8 vfp = V_FPORCH; // Vertical front porch
TUint8 vsw = V_SYNC; // Vertical synchronization pulse width
__ASSERT_ALWAYS( vbp<=255, Kern::Fault("LCD", 1) );
__ASSERT_ALWAYS( vfp<=255, Kern::Fault("LCD", 1) );
__ASSERT_ALWAYS( vsw>=1 && vsw<=255, Kern::Fault("LCD", 1) );
l = vbp<<20 | vfp<<8 | vsw;
SET_REGISTER( DISPC_TIMING_V, l );
TUint8 onoff= 0;
TUint8 rf = 0;
TUint8 ieo = 0;
TUint8 ipc = 1; // Invert Pixel Clock
TUint8 ihs = H_SYNC_POL ? 0 : 1; // Invert HSYNC (0: Positive Sync polarity, 1: Negative Sync polarity)
TUint8 ivs = V_SYNC_POL ? 0 : 1; // Invert VSYNC (0: Positive Sync polarity, 1: Negative Sync polarity)
TUint8 acbi = 0;
TUint16 acb = 0x28; // AC-bias pin frequency
l = onoff<<17 | rf<<16 | ieo<<15 | ipc<<14 | ihs<<13 | ivs<<12 | acbi<<8 | acb;
SET_REGISTER( DISPC_POL_FREQ, l );
TUint8 lcd = 1; // Display Controller Logic Clock Divisor
TUint8 pcd = ( 432000 + (PIXEL_CLK - 1) ) / PIXEL_CLK; // Pixel Clock Divisor - add (PIXEL_CLK - 1) to avoid rounding error
__ASSERT_ALWAYS( lcd>=1 && lcd<=255, Kern::Fault("LCD", 1) );
__ASSERT_ALWAYS( pcd>=2 && pcd<=255, Kern::Fault("LCD", 1) );
l = lcd<<16 | pcd;
SET_REGISTER( DISPC_DIVISOR, l );
TUint16 ppl = H_DISP - 1; // Pixels per line
TUint16 llp = V_DISP - 1; // Lines per panel
__ASSERT_ALWAYS( ppl>=1 && ppl<=2048, Kern::Fault("LCD", 1) );
__ASSERT_ALWAYS( llp>=1 && llp<=2048, Kern::Fault("LCD", 1) );
l = llp<<16 | ppl;
SET_REGISTER( DISPC_SIZE_LCD, l );
// Setup a graphics region (GFX)
// Set GFX frame buffer
SET_REGISTER( DISPC_GFX_BA1, ivRamPhys );
// Center the GFX
TInt16 gfxposy = ( V_DISP - KConfigLcdHeight ) / 2;
TInt16 gfxposx = ( H_DISP - KConfigLcdWidth ) / 2;
l = ( gfxposy << 16 ) | gfxposx;
SET_REGISTER( DISPC_GFX_POSITION, l );
// Set the GFX dimensions
TInt16 gfxsizey = KConfigLcdHeight - 1;
TInt16 gfxsizex = KConfigLcdWidth - 1;
l = gfxsizey<<16 | gfxsizex;
SET_REGISTER( DISPC_GFX_SIZE, l );
TInt8 GFXSELFREFRESH = 0x0;
TInt8 GFXARBITRATION = 0x0;
TInt8 GFXROTATION = 0x0;
TInt8 GFXFIFOPRELOAD = 0x0;
TInt8 GFXENDIANNESS = 0x0;
TInt8 GFXNIBBLEMODE = 0x0;
TInt8 GFXCHANNELOUT = 0x0;
TInt8 GFXBURSTSIZE = 0x2; // 16x32bit bursts
TInt8 GFXREPLICATIONENABLE = 0x0; // Disable Graphics replication logic
TInt8 GFXFORMAT = 0x6; // RGB16=0x6, RGB24-unpacked=0x8, RGB24-packed=0x9
TInt8 GFXENABLE = 0x1; // Graphics enabled
l = GFXSELFREFRESH<<15 | GFXARBITRATION<<14 | GFXROTATION<<12 | GFXFIFOPRELOAD<<11 | GFXENDIANNESS<<10 | GFXNIBBLEMODE<<9 | GFXCHANNELOUT<8 | GFXBURSTSIZE<<6 | GFXREPLICATIONENABLE<<5 | GFXFORMAT<<1 | GFXENABLE;
SET_REGISTER( DISPC_GFX_ATTRIBUTES, l );
TInt16 GFXFIFOHIGHTHRESHOLD = 0x3fc; // Graphics FIFO High Threshold
TInt16 GFXFIFOLOWTHRESHOLD = 0x3BC; // Graphics FIFO Low Threshold
l = GFXFIFOHIGHTHRESHOLD<<16 | GFXFIFOLOWTHRESHOLD;
SET_REGISTER(DISPC_GFX_FIFO_THRESHOLD, l);
TInt16 GFXFIFOSIZE = 0x400; // Number of bytes defining the FIFO value
l = GFXFIFOSIZE;
SET_REGISTER(DISPC_GFX_FIFO_SIZE_STATUS, l);
TInt32 GFXROWINC = 0x1;
l = GFXROWINC;
SET_REGISTER(DISPC_GFX_ROW_INC, l);
TInt16 GFXPIXELINC = 0x1;
l = GFXPIXELINC;
SET_REGISTER(DISPC_GFX_PIXEL_INC, l);
TInt32 GFXWINDOWSKIP = 0x0;
l = GFXWINDOWSKIP;
SET_REGISTER(DISPC_GFX_WINDOW_SKIP, l);
// TO DO: Sort out the Gamma table + pallets
TInt32 GFXTABLEBA = 0x807ff000;
l = GFXTABLEBA;
SET_REGISTER(DISPC_GFX_TABLE_BA, l);
// Propigate all the shadowed registers
TInt8 SPATIALTEMPORALDITHERINGFRAMES = 0;
TInt8 LCDENABLEPOL = 0;
TInt8 LCDENABLESIGNAL = 0;
TInt8 PCKFREEENABLE = 0;
TInt8 TDMUNUSEDBITS = 0;
TInt8 TDMCYCLEFORMAT = 0;
TInt8 TDMPARALLELMODE = 0;
TInt8 TDMENABLE = 0;
TInt8 HT = 0;
TInt8 GPOUT1 = 1;
TInt8 GPOUT0 = 1;
TInt8 GPIN1 = 0;
TInt8 GPIN0 = 0;
TInt8 OVERLAYOPTIMIZATION = 0;
TInt8 RFBIMODE = 0;
TInt8 SECURE = 0;
TInt8 TFTDATALINES = 0x3;
TInt8 STDITHERENABLE = 0;
TInt8 GODIGITAL = 1;
TInt8 GOLCD = 1;
TInt8 M8B = 0;
TInt8 STNTFT = 1;
TInt8 MONOCOLOR = 0;
TInt8 DIGITALENABLE = 1;
TInt8 LCDENABLE = 1;
l = SPATIALTEMPORALDITHERINGFRAMES<<30 | LCDENABLEPOL<<29 | LCDENABLESIGNAL<<28 | PCKFREEENABLE<<27 |
TDMUNUSEDBITS<<25 | TDMCYCLEFORMAT<<23 | TDMPARALLELMODE<<21 | TDMENABLE<<20 | HT<<17 | GPOUT1<<16 |
GPOUT0<<15 | GPIN1<<14 | GPIN0<<13 | OVERLAYOPTIMIZATION<<12 | RFBIMODE<<11 | SECURE<<10 |
TFTDATALINES<<8 | STDITHERENABLE<<7 | GODIGITAL<<6 | GOLCD<<5 | M8B<<4 | STNTFT<<3 |
MONOCOLOR<<2 | DIGITALENABLE<<1 | LCDENABLE;
NKern::Sleep(1);
SET_REGISTER(DISPC_CONTROL, l);
NKern::Sleep(1);
}
/**
Power down the display and the backlight
*/
void DLcdPowerHandler::PowerDownLcd()
{
SetBacklightState(EFalse);
// TO DO: (mandatory)
// Power down the display & disable LCD DMA.
// May need to wait until the current frame has been output
//
SET_REGISTER(DISPC_CONTROL, 0);
}
/**
Set the Lcd contrast
@param aValue the contrast setting
*/
TInt DLcdPowerHandler::SetContrast(TInt aValue)
{
__KTRACE_OPT(KEXTENSION,Kern::Printf("SetContrast(%d)", aValue));
if (aValue >= KConfigLcdMinDisplayContrast && aValue <= KConfigLcdMaxDisplayContrast)
{
iContrast=aValue;
// TO DO: (mandatory)
// set the contrast
//
return KErrNone;
}
return KErrArgument;
}
/**
Set the Lcd brightness
@param aValue the brightness setting
*/
TInt DLcdPowerHandler::SetBrightness(TInt aValue)
{
__KTRACE_OPT(KEXTENSION,Kern::Printf("SetBrightness(%d)", aValue));
if (aValue >= KConfigLcdMinDisplayBrightness && aValue <= KConfigLcdMaxDisplayBrightness)
{
iBrightness=aValue;
// TO DO: (mandatory)
// set the brightness
//
return KErrNone;
}
return KErrArgument;
}
/**
Turn the backlight on
*/
void DLcdPowerHandler::BacklightOn()
{
// TO DO: (mandatory)
// turn the backlight on
//
}
/**
Turn the backlight off
*/
void DLcdPowerHandler::BacklightOff()
{
// TO DO: (mandatory)
// turn the backlight off
//
}
/**
Set the state of the backlight
@param aState ETrue if setting the backlight on
*/
void DLcdPowerHandler::SetBacklightState(TBool aState)
{
iBacklightOn=aState;
if (iBacklightOn)
BacklightOn();
else
BacklightOff();
}
void DLcdPowerHandler::ScreenInfo(TScreenInfoV01& anInfo)
{
__KTRACE_OPT(KEXTENSION,Kern::Printf("DLcdPowerHandler::ScreenInfo"));
anInfo.iWindowHandleValid=EFalse;
anInfo.iWindowHandle=NULL;
anInfo.iScreenAddressValid=ETrue;
anInfo.iScreenAddress=(TAny *)(iChunk->LinearAddress());
anInfo.iScreenSize.iWidth=KConfigLcdWidth;
anInfo.iScreenSize.iHeight=KConfigLcdHeight;
}
/**
Handle a message from the power handler
*/
void DLcdPowerHandler::HandleMsg(void)
{
TMessageBase* msg = iMsgQ.iMessage;
if (msg == NULL)
return;
if (msg->iValue)
DisplayOn();
else
DisplayOff();
msg->Complete(KErrNone,ETrue);
}
/**
Send a message to the power-handler message queue to turn the display on
*/
void DLcdPowerHandler::WsSwitchOnScreen()
{
TThreadMessage& m=Kern::Message();
m.iValue = ETrue;
m.SendReceive(&iMsgQ); // send a message and block Client thread until keyboard has been powered up
}
/**
Send a message to the power-handler message queue to turn the display off
*/
void DLcdPowerHandler::WsSwitchOffScreen()
{
TThreadMessage& m=Kern::Message();
m.iValue = EFalse;
m.SendReceive(&iMsgQ); // send a message and block Client thread until keyboard has been powered down
}
/**
Return information about the current display mode
@param aInfo a structure supplied by the caller to be filled by this function.
@param aSecure ETrue if requesting information about the secure display
@return KErrNone if successful
*/
TInt DLcdPowerHandler::GetCurrentDisplayModeInfo(TVideoInfoV01& aInfo, TBool aSecure)
{
__KTRACE_OPT(KEXTENSION,Kern::Printf("GetCurrentDisplayModeInfo"));
NKern::FMWait(&iLock);
if (aSecure)
aInfo = iSecureVideoInfo;
else
aInfo = iVideoInfo;
NKern::FMSignal(&iLock);
return KErrNone;
}
/**
Return information about the specified display mode
@param aMode the display mode to query
@param aInfo a structure supplied by the caller to be filled by this function.
@return KErrNone if successful
*/
TInt DLcdPowerHandler::GetSpecifiedDisplayModeInfo(TInt aMode, TVideoInfoV01& aInfo)
{
__KTRACE_OPT(KEXTENSION,Kern::Printf("GetSpecifiedDisplayModeInfo mode is %d",aMode));
if (aMode < 0 || aMode >= KConfigLcdNumberOfDisplayModes)
return KErrArgument;
NKern::FMWait(&iLock);
aInfo = iVideoInfo;
NKern::FMSignal(&iLock);
if (aMode != aInfo.iDisplayMode)
{
aInfo.iOffsetToFirstPixel=Lcd_Mode_Config[aMode].iOffsetToFirstVideoBuffer;
aInfo.iIsPalettized = Lcd_Mode_Config[aMode].iIsPalettized;
aInfo.iOffsetBetweenLines=Lcd_Mode_Config[aMode].iOffsetBetweenLines;
aInfo.iBitsPerPixel = Lcd_Mode_Config[aMode].iBitsPerPixel;
}
return KErrNone;
}
/**
Set the display mode
@param aMode the display mode to set
*/
TInt DLcdPowerHandler::SetDisplayMode(TInt aMode)
{
__KTRACE_OPT(KEXTENSION,Kern::Printf("SetDisplayMode = %d", aMode));
if (aMode < 0 || aMode >= KConfigLcdNumberOfDisplayModes)
return KErrArgument;
NKern::FMWait(&iLock);
// store the current mode
iVideoInfo.iDisplayMode = aMode;
iVideoInfo.iOffsetToFirstPixel = Lcd_Mode_Config[aMode].iOffsetToFirstVideoBuffer;
iVideoInfo.iIsPalettized = Lcd_Mode_Config[aMode].iIsPalettized;
iVideoInfo.iOffsetBetweenLines = Lcd_Mode_Config[aMode].iOffsetBetweenLines;
iVideoInfo.iBitsPerPixel = Lcd_Mode_Config[aMode].iBitsPerPixel;
// store the current mode for secure screen
iSecureVideoInfo.iDisplayMode = aMode;
iSecureVideoInfo.iOffsetToFirstPixel = Lcd_Mode_Config[aMode].iOffsetToFirstVideoBuffer;
iSecureVideoInfo.iIsPalettized = Lcd_Mode_Config[aMode].iIsPalettized;
iSecureVideoInfo.iOffsetBetweenLines = Lcd_Mode_Config[aMode].iOffsetBetweenLines;
iSecureVideoInfo.iBitsPerPixel = Lcd_Mode_Config[aMode].iBitsPerPixel;
// TO DO: (mandatory)
// set bits per pixel on hardware
// May need to reconfigure DMA if video buffer size and location have changed
//
NKern::FMSignal(&iLock);
__KTRACE_OPT(KEXTENSION,Kern::Printf("SetDisplayMode mode = %d, otfp = %d, palettized = %d, bpp = %d, obl = %d",
aMode, iVideoInfo.iOffsetToFirstPixel, iVideoInfo.iIsPalettized, iVideoInfo.iBitsPerPixel, iVideoInfo.iOffsetBetweenLines));
return KErrNone;
}
/**
Fill the video memory with an initial pattern or image
This will be displayed on boot-up
*/
void DLcdPowerHandler::SplashScreen()
{
// TO DO: (optional)
// replace the example code below to display a different spash screen
__KTRACE_OPT(KEXTENSION,Kern::Printf("Splash SCreen +"));
TUint* pV=(TUint*)(iVideoInfo.iVideoAddress + iVideoInfo.iOffsetToFirstPixel);
__KTRACE_OPT(KEXTENSION,Kern::Printf("Splash SCreen FB @ %x",pV));
//Fill the framebuffer with bars
for (TInt y = 0; y<KConfigLcdHeight; ++y)
{
for(TInt x = 0; x<KConfigLcdHeight; ++x)
{
TUint8 r = 0x00;
TUint8 g = 0x00;
TUint8 b = 0x00;
TUint16 rgb = ((r&0xf8) << 8) | ((g&0xfc) << 3) | ((b&0xf8) >> 3);
TUint16* px = reinterpret_cast<TUint16*>(pV) + y*KConfigLcdWidth + x;
*px = rgb;
}
}
__KTRACE_OPT(KEXTENSION,Kern::Printf("Splash SCreen -"));
}
/**
Get the size of the pallete
@return the number of pallete entries
*/
TInt DLcdPowerHandler::NumberOfPaletteEntries() //only call when holding mutex
{
// TO DO: (mandatory)
// Calculate the number of Palette entries - this is normally
// calculated from the bits per-pixel.
// This is only example code... you may need to modify it for your hardware
//
TInt num = iVideoInfo.iIsPalettized ? 1<<iVideoInfo.iBitsPerPixel : 0;
__KTRACE_OPT(KEXTENSION,Kern::Printf("NumberOfPaletteEntries = %d", num));
return num;
}
/**
Retrieve the palette entry at a particular offset
@param aEntry the palette index
@param aColor a caller-supplied pointer to a location where the returned RGB color is to be stored
@return KErrNone if successful
KErrNotSupported if the current vide mode does not support a palette
KErrArgument if aEntry is out of range
*/
TInt DLcdPowerHandler::GetPaletteEntry(TInt aEntry, TInt* aColor)
{
NKern::FMWait(&iLock);
if (!iVideoInfo.iIsPalettized)
{
NKern::FMSignal(&iLock);
return KErrNotSupported;
}
if ((aEntry < 0) || (aEntry >= NumberOfPaletteEntries()))
{
NKern::FMSignal(&iLock);
return KErrArgument;
}
// TO DO: (mandatory)
// read the RGB value of the palette entry into aColor
// NOTE: the palette could either be a buffer allocated in system RAM (usually contiguous to Video buffer)
// or could be offered as part of the hardware block that implemenst the lcd control
//
NKern::FMSignal(&iLock);
__KTRACE_OPT(KEXTENSION,Kern::Printf("GetPaletteEntry %d color 0x%x", aEntry, aColor));
return KErrNone;
}
/**
Set the palette entry at a particular offset
@param aEntry the palette index
@param aColor the RGB color to store
@return KErrNone if successful
KErrNotSupported if the current vide mode does not support a palette
KErrArgument if aEntry is out of range
*/
TInt DLcdPowerHandler::SetPaletteEntry(TInt aEntry, TInt aColor)
{
NKern::FMWait(&iLock);
if (!iVideoInfo.iIsPalettized)
{
NKern::FMSignal(&iLock);
return KErrNotSupported;
}
if ((aEntry < 0) || (aEntry >= NumberOfPaletteEntries())) //check entry in range
{
NKern::FMSignal(&iLock);
return KErrArgument;
}
// TO DO: (mandatory)
// update the palette entry for the secure and non-secure screen
// NOTE: the palette could either be a buffer allocated in system RAM (usually contiguous to Video buffer)
// or could be offered as part of the hardware block that implemenst the lcd control
//
__KTRACE_OPT(KEXTENSION,Kern::Printf("SetPaletteEntry %d to 0x%x", aEntry, aColor ));
return KErrNone;
}
/**
a HAL entry handling function for HAL group attribute EHalGroupDisplay
@param a1 an arbitrary argument
@param a2 an arbitrary argument
@return KErrNone if successful
*/
TInt DLcdPowerHandler::HalFunction(TInt aFunction, TAny* a1, TAny* a2)
{
TInt r=KErrNone;
switch(aFunction)
{
case EDisplayHalScreenInfo:
{
TPckgBuf<TScreenInfoV01> vPckg;
ScreenInfo(vPckg());
Kern::InfoCopy(*(TDes8*)a1,vPckg);
break;
}
case EDisplayHalWsRegisterSwitchOnScreenHandling:
iWsSwitchOnScreen=(TBool)a1;
break;
case EDisplayHalWsSwitchOnScreen:
WsSwitchOnScreen();
break;
case EDisplayHalMaxDisplayContrast:
{
TInt mc=KConfigLcdMaxDisplayContrast;
kumemput32(a1,&mc,sizeof(mc));
break;
}
case EDisplayHalSetDisplayContrast:
__KTRACE_OPT(KEXTENSION,Kern::Printf("EDisplayHalSetDisplayContrast"));
if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetDisplayContrast")))
return KErrPermissionDenied;
r=SetContrast(TInt(a1));
break;
case EDisplayHalDisplayContrast:
kumemput32(a1,&iContrast,sizeof(iContrast));
break;
case EDisplayHalMaxDisplayBrightness:
{
TInt mc=KConfigLcdMaxDisplayBrightness;
kumemput32(a1,&mc,sizeof(mc));
break;
}
case EDisplayHalSetDisplayBrightness:
__KTRACE_OPT(KEXTENSION,Kern::Printf("EDisplayHalSetDisplayBrightness"));
if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetDisplayBrightness")))
return KErrPermissionDenied;
r=SetBrightness(TInt(a1));
break;
case EDisplayHalDisplayBrightness:
kumemput32(a1,&iBrightness,sizeof(iBrightness));
break;
case EDisplayHalSetBacklightOn:
if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetBacklightOn")))
return KErrPermissionDenied;
if (Kern::MachinePowerStatus()<ELow)
r=KErrBadPower;
else
SetBacklightState(TBool(a1));
break;
case EDisplayHalBacklightOn:
kumemput32(a1,&iBacklightOn,sizeof(TInt));
break;
case EDisplayHalModeCount:
{
TInt ndm = KConfigLcdNumberOfDisplayModes;
kumemput32(a1, &ndm, sizeof(ndm));
break;
}
case EDisplayHalSetMode:
if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetMode")))
return KErrPermissionDenied;
r = SetDisplayMode((TInt)a1);
break;
case EDisplayHalMode:
kumemput32(a1, &iVideoInfo.iDisplayMode, sizeof(iVideoInfo.iDisplayMode));
break;
case EDisplayHalSetPaletteEntry:
if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetPaletteEntry")))
return KErrPermissionDenied;
r = SetPaletteEntry((TInt)a1, (TInt)a2);
break;
case EDisplayHalPaletteEntry:
{
TInt entry;
kumemget32(&entry, a1, sizeof(TInt));
TInt x;
r = GetPaletteEntry(entry, &x);
if (r == KErrNone)
kumemput32(a2, &x, sizeof(x));
break;
}
case EDisplayHalSetState:
{
if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetState")))
return KErrPermissionDenied;
if ((TBool)a1)
{
WsSwitchOnScreen();
}
else
{
WsSwitchOffScreen();
}
break;
}
case EDisplayHalState:
kumemput32(a1, &iDisplayOn, sizeof(TBool));
break;
case EDisplayHalColors:
{
TInt mdc = KConfigLcdMaxDisplayColors;
kumemput32(a1, &mdc, sizeof(mdc));
break;
}
case EDisplayHalCurrentModeInfo:
{
TPckgBuf<TVideoInfoV01> vPckg;
r = GetCurrentDisplayModeInfo(vPckg(), (TBool)a2);
if (KErrNone == r)
Kern::InfoCopy(*(TDes8*)a1,vPckg);
}
break;
case EDisplayHalSpecifiedModeInfo:
{
TPckgBuf<TVideoInfoV01> vPckg;
TInt mode;
kumemget32(&mode, a1, sizeof(mode));
r = GetSpecifiedDisplayModeInfo(mode, vPckg());
if (KErrNone == r)
Kern::InfoCopy(*(TDes8*)a2,vPckg);
}
break;
case EDisplayHalSecure:
kumemput32(a1, &iSecureDisplay, sizeof(TBool));
break;
case EDisplayHalSetSecure:
{
if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetSecure")))
return KErrPermissionDenied;
SwitchDisplay((TBool)a1);
}
break;
default:
r=KErrNotSupported;
break;
}
return r;
}
DECLARE_STANDARD_EXTENSION()
{
__KTRACE_OPT(KPOWER,Kern::Printf("Starting LCD power manager"));
// create LCD power handler
TInt r=KErrNoMemory;
DLcdPowerHandler* pH=new DLcdPowerHandler;
if (pH)
r=pH->Create();
__KTRACE_OPT(KPOWER,Kern::Printf("Returns %d",r));
return r;
}