forked from Minki/linux
staging: sm750fb: add sm750 to staging
sm750 of Silicon Motion is pci-e display controller device and has features like dual display and 2D acceleration. This patch adds the driver to staging. Signed-off-by: Sudip Mukherjee <sudip@vectorindia.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
c3d6047d95
commit
81dee67e21
@ -58,6 +58,8 @@ source "drivers/staging/iio/Kconfig"
|
||||
|
||||
source "drivers/staging/sm7xxfb/Kconfig"
|
||||
|
||||
source "drivers/staging/sm750fb/Kconfig"
|
||||
|
||||
source "drivers/staging/xgifb/Kconfig"
|
||||
|
||||
source "drivers/staging/emxx_udc/Kconfig"
|
||||
|
@ -23,6 +23,7 @@ obj-$(CONFIG_VT6656) += vt6656/
|
||||
obj-$(CONFIG_VME_BUS) += vme/
|
||||
obj-$(CONFIG_IIO) += iio/
|
||||
obj-$(CONFIG_FB_SM7XX) += sm7xxfb/
|
||||
obj-$(CONFIG_FB_SM7XX) += sm750fb/
|
||||
obj-$(CONFIG_FB_XGI) += xgifb/
|
||||
obj-$(CONFIG_USB_EMXX) += emxx_udc/
|
||||
obj-$(CONFIG_FT1000) += ft1000/
|
||||
|
10
drivers/staging/sm750fb/Kconfig
Normal file
10
drivers/staging/sm750fb/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
config FB_SM750
|
||||
tristate "Silicon Motion SM750 framebuffer support"
|
||||
depends on FB && PCI
|
||||
help
|
||||
Frame buffer driver for the Silicon Motion SM750 chip
|
||||
with 2D accelearion and dual head support.
|
||||
|
||||
This driver is also available as a module. The module will be
|
||||
called sm750fb. If you want to compile it as a module, say M
|
||||
here and read <file:Documentation/kbuild/modules.txt>.
|
4
drivers/staging/sm750fb/Makefile
Normal file
4
drivers/staging/sm750fb/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
obj-$(CONFIG_FB_SM750) += sm750fb.o
|
||||
|
||||
sm750fb-objs := sm750.o sm750_hw.o sm750_accel.o sm750_cursor.o ddk750_chip.o ddk750_power.o ddk750_mode.o
|
||||
sm750fb-objs += ddk750_display.o ddk750_help.o ddk750_swi2c.o ddk750_sii164.o ddk750_dvi.o ddk750_hwi2c.o
|
15
drivers/staging/sm750fb/TODO
Normal file
15
drivers/staging/sm750fb/TODO
Normal file
@ -0,0 +1,15 @@
|
||||
TODO:
|
||||
- lots of clechpatch cleanup
|
||||
- use kernel coding style
|
||||
- refine the code and remove unused code
|
||||
- check on hardware effects of removal of USE_HW_I2C and USE_DVICHIP (these two
|
||||
are supposed to be sample code which is given here if someone wants to
|
||||
use those functionalities)
|
||||
- move it to drivers/video/fbdev
|
||||
- modify the code for drm framework
|
||||
|
||||
Please send any patches to
|
||||
Greg Kroah-Hartman <greg@kroah.com>
|
||||
Sudip Mukherjee <sudipm.mukherjee@gmail.com>
|
||||
Teddy Wang <teddy.wang@siliconmotion.com>
|
||||
Sudip Mukherjee <sudip@vectorindia.org>
|
24
drivers/staging/sm750fb/ddk750.h
Normal file
24
drivers/staging/sm750fb/ddk750.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef DDK750_H__
|
||||
#define DDK750_H__
|
||||
/*******************************************************************
|
||||
*
|
||||
* Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
|
||||
*
|
||||
* All rights are reserved. Reproduction or in part is prohibited
|
||||
* without the written consent of the copyright owner.
|
||||
*
|
||||
* RegSC.h --- SM718 SDK
|
||||
* This file contains the definitions for the System Configuration registers.
|
||||
*
|
||||
*******************************************************************/
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_mode.h"
|
||||
#include "ddk750_chip.h"
|
||||
#include "ddk750_display.h"
|
||||
#include "ddk750_power.h"
|
||||
#include "ddk750_help.h"
|
||||
#ifdef USE_HW_I2C
|
||||
#include "ddk750_hwi2c.h"
|
||||
#endif
|
||||
#include "ddk750_swi2c.h"
|
||||
#endif
|
639
drivers/staging/sm750fb/ddk750_chip.c
Normal file
639
drivers/staging/sm750fb/ddk750_chip.c
Normal file
@ -0,0 +1,639 @@
|
||||
#include "ddk750_help.h"
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_chip.h"
|
||||
#include "ddk750_power.h"
|
||||
typedef struct _pllcalparam{
|
||||
unsigned char power;/* d : 0~ 6*/
|
||||
unsigned char pod;
|
||||
unsigned char od;
|
||||
unsigned char value;/* value of 2 power d (2^d) */
|
||||
}
|
||||
pllcalparam;
|
||||
|
||||
|
||||
logical_chip_type_t getChipType()
|
||||
{
|
||||
unsigned short physicalID;
|
||||
char physicalRev;
|
||||
logical_chip_type_t chip;
|
||||
|
||||
physicalID = devId750;//either 0x718 or 0x750
|
||||
physicalRev = revId750;
|
||||
|
||||
if (physicalID == 0x718)
|
||||
{
|
||||
chip = SM718;
|
||||
}
|
||||
else if (physicalID == 0x750)
|
||||
{
|
||||
chip = SM750;
|
||||
/* SM750 and SM750LE are different in their revision ID only. */
|
||||
if (physicalRev == SM750LE_REVISION_ID){
|
||||
chip = SM750LE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
chip = SM_UNKNOWN;
|
||||
}
|
||||
|
||||
return chip;
|
||||
}
|
||||
|
||||
|
||||
inline unsigned int twoToPowerOfx(unsigned long x)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned long result = 1;
|
||||
|
||||
for (i=1; i<=x; i++)
|
||||
result *= 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline unsigned int calcPLL(pll_value_t *pPLL)
|
||||
{
|
||||
return (pPLL->inputFreq * pPLL->M / pPLL->N / twoToPowerOfx(pPLL->OD) / twoToPowerOfx(pPLL->POD));
|
||||
}
|
||||
|
||||
unsigned int getPllValue(clock_type_t clockType, pll_value_t *pPLL)
|
||||
{
|
||||
unsigned int ulPllReg = 0;
|
||||
|
||||
pPLL->inputFreq = DEFAULT_INPUT_CLOCK;
|
||||
pPLL->clockType = clockType;
|
||||
|
||||
switch (clockType)
|
||||
{
|
||||
case MXCLK_PLL:
|
||||
ulPllReg = PEEK32(MXCLK_PLL_CTRL);
|
||||
break;
|
||||
case PRIMARY_PLL:
|
||||
ulPllReg = PEEK32(PANEL_PLL_CTRL);
|
||||
break;
|
||||
case SECONDARY_PLL:
|
||||
ulPllReg = PEEK32(CRT_PLL_CTRL);
|
||||
break;
|
||||
case VGA0_PLL:
|
||||
ulPllReg = PEEK32(VGA_PLL0_CTRL);
|
||||
break;
|
||||
case VGA1_PLL:
|
||||
ulPllReg = PEEK32(VGA_PLL1_CTRL);
|
||||
break;
|
||||
}
|
||||
|
||||
pPLL->M = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, M);
|
||||
pPLL->N = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, N);
|
||||
pPLL->OD = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, OD);
|
||||
pPLL->POD = FIELD_GET(ulPllReg, PANEL_PLL_CTRL, POD);
|
||||
|
||||
return calcPLL(pPLL);
|
||||
}
|
||||
|
||||
|
||||
unsigned int getChipClock()
|
||||
{
|
||||
pll_value_t pll;
|
||||
#if 1
|
||||
if(getChipType() == SM750LE)
|
||||
return MHz(130);
|
||||
#endif
|
||||
|
||||
return getPllValue(MXCLK_PLL, &pll);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function set up the main chip clock.
|
||||
*
|
||||
* Input: Frequency to be set.
|
||||
*/
|
||||
void setChipClock(unsigned int frequency)
|
||||
{
|
||||
pll_value_t pll;
|
||||
unsigned int ulActualMxClk;
|
||||
#if 1
|
||||
/* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */
|
||||
if (getChipType() == SM750LE)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (frequency != 0)
|
||||
{
|
||||
/*
|
||||
* Set up PLL, a structure to hold the value to be set in clocks.
|
||||
*/
|
||||
pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */
|
||||
pll.clockType = MXCLK_PLL;
|
||||
|
||||
/*
|
||||
* Call calcPllValue() to fill up the other fields for PLL structure.
|
||||
* Sometime, the chip cannot set up the exact clock required by User.
|
||||
* Return value from calcPllValue() gives the actual possible clock.
|
||||
*/
|
||||
ulActualMxClk = calcPllValue(frequency, &pll);
|
||||
|
||||
/* Master Clock Control: MXCLK_PLL */
|
||||
POKE32(MXCLK_PLL_CTRL, formatPllReg(&pll));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setMemoryClock(unsigned int frequency)
|
||||
{
|
||||
unsigned int ulReg, divisor;
|
||||
#if 1
|
||||
/* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */
|
||||
if (getChipType() == SM750LE)
|
||||
return;
|
||||
#endif
|
||||
if (frequency != 0)
|
||||
{
|
||||
/* Set the frequency to the maximum frequency that the DDR Memory can take
|
||||
which is 336MHz. */
|
||||
if (frequency > MHz(336))
|
||||
frequency = MHz(336);
|
||||
|
||||
/* Calculate the divisor */
|
||||
divisor = (unsigned int) roundedDiv(getChipClock(), frequency);
|
||||
|
||||
/* Set the corresponding divisor in the register. */
|
||||
ulReg = PEEK32(CURRENT_GATE);
|
||||
switch(divisor)
|
||||
{
|
||||
default:
|
||||
case 1:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_1);
|
||||
break;
|
||||
case 2:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_2);
|
||||
break;
|
||||
case 3:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_3);
|
||||
break;
|
||||
case 4:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_4);
|
||||
break;
|
||||
}
|
||||
|
||||
setCurrentGate(ulReg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function set up the master clock (MCLK).
|
||||
*
|
||||
* Input: Frequency to be set.
|
||||
*
|
||||
* NOTE:
|
||||
* The maximum frequency the engine can run is 168MHz.
|
||||
*/
|
||||
void setMasterClock(unsigned int frequency)
|
||||
{
|
||||
unsigned int ulReg, divisor;
|
||||
#if 1
|
||||
/* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */
|
||||
if (getChipType() == SM750LE)
|
||||
return;
|
||||
#endif
|
||||
if (frequency != 0)
|
||||
{
|
||||
/* Set the frequency to the maximum frequency that the SM750 engine can
|
||||
run, which is about 190 MHz. */
|
||||
if (frequency > MHz(190))
|
||||
frequency = MHz(190);
|
||||
|
||||
/* Calculate the divisor */
|
||||
divisor = (unsigned int) roundedDiv(getChipClock(), frequency);
|
||||
|
||||
/* Set the corresponding divisor in the register. */
|
||||
ulReg = PEEK32(CURRENT_GATE);
|
||||
switch(divisor)
|
||||
{
|
||||
default:
|
||||
case 3:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_3);
|
||||
break;
|
||||
case 4:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_4);
|
||||
break;
|
||||
case 6:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_6);
|
||||
break;
|
||||
case 8:
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_8);
|
||||
break;
|
||||
}
|
||||
|
||||
setCurrentGate(ulReg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int ddk750_getVMSize()
|
||||
{
|
||||
unsigned int reg;
|
||||
unsigned int data;
|
||||
|
||||
/* sm750le only use 64 mb memory*/
|
||||
if(getChipType() == SM750LE)
|
||||
return MB(64);
|
||||
|
||||
/* for 750,always use power mode0*/
|
||||
reg = PEEK32(MODE0_GATE);
|
||||
reg = FIELD_SET(reg,MODE0_GATE,GPIO,ON);
|
||||
POKE32(MODE0_GATE,reg);
|
||||
|
||||
/* get frame buffer size from GPIO */
|
||||
reg = FIELD_GET(PEEK32(MISC_CTRL),MISC_CTRL,LOCALMEM_SIZE);
|
||||
switch(reg){
|
||||
case MISC_CTRL_LOCALMEM_SIZE_8M: data = MB(8); break; /* 8 Mega byte */
|
||||
case MISC_CTRL_LOCALMEM_SIZE_16M: data = MB(16); break; /* 16 Mega byte */
|
||||
case MISC_CTRL_LOCALMEM_SIZE_32M: data = MB(32); break; /* 32 Mega byte */
|
||||
case MISC_CTRL_LOCALMEM_SIZE_64M: data = MB(64); break; /* 64 Mega byte */
|
||||
default: data = 0;break;
|
||||
}
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
int ddk750_initHw(initchip_param_t * pInitParam)
|
||||
{
|
||||
|
||||
unsigned int ulReg;
|
||||
#if 0
|
||||
//move the code to map regiter function.
|
||||
if(getChipType() == SM718){
|
||||
/* turn on big endian bit*/
|
||||
ulReg = PEEK32(0x74);
|
||||
/* now consider register definition in a big endian pattern*/
|
||||
POKE32(0x74,ulReg|0x80000000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
if (pInitParam->powerMode != 0 )
|
||||
pInitParam->powerMode = 0;
|
||||
setPowerMode(pInitParam->powerMode);
|
||||
|
||||
/* Enable display power gate & LOCALMEM power gate*/
|
||||
ulReg = PEEK32(CURRENT_GATE);
|
||||
ulReg = FIELD_SET(ulReg, CURRENT_GATE, DISPLAY, ON);
|
||||
ulReg = FIELD_SET(ulReg,CURRENT_GATE,LOCALMEM,ON);
|
||||
setCurrentGate(ulReg);
|
||||
|
||||
if(getChipType() != SM750LE){
|
||||
/* set panel pll and graphic mode via mmio_88 */
|
||||
ulReg = PEEK32(VGA_CONFIGURATION);
|
||||
ulReg = FIELD_SET(ulReg,VGA_CONFIGURATION,PLL,PANEL);
|
||||
ulReg = FIELD_SET(ulReg,VGA_CONFIGURATION,MODE,GRAPHIC);
|
||||
POKE32(VGA_CONFIGURATION,ulReg);
|
||||
}else{
|
||||
#if defined(__i386__) || defined( __x86_64__)
|
||||
/* set graphic mode via IO method */
|
||||
outb_p(0x88,0x3d4);
|
||||
outb_p(0x06,0x3d5);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the Main Chip Clock */
|
||||
setChipClock(MHz((unsigned int)pInitParam->chipClock));
|
||||
|
||||
/* Set up memory clock. */
|
||||
setMemoryClock(MHz(pInitParam->memClock));
|
||||
|
||||
/* Set up master clock */
|
||||
setMasterClock(MHz(pInitParam->masterClock));
|
||||
|
||||
|
||||
/* Reset the memory controller. If the memory controller is not reset in SM750,
|
||||
the system might hang when sw accesses the memory.
|
||||
The memory should be resetted after changing the MXCLK.
|
||||
*/
|
||||
if (pInitParam->resetMemory == 1)
|
||||
{
|
||||
ulReg = PEEK32(MISC_CTRL);
|
||||
ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, RESET);
|
||||
POKE32(MISC_CTRL, ulReg);
|
||||
|
||||
ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, NORMAL);
|
||||
POKE32(MISC_CTRL, ulReg);
|
||||
}
|
||||
|
||||
if (pInitParam->setAllEngOff == 1)
|
||||
{
|
||||
enable2DEngine(0);
|
||||
|
||||
/* Disable Overlay, if a former application left it on */
|
||||
ulReg = PEEK32(VIDEO_DISPLAY_CTRL);
|
||||
ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE);
|
||||
POKE32(VIDEO_DISPLAY_CTRL, ulReg);
|
||||
|
||||
/* Disable video alpha, if a former application left it on */
|
||||
ulReg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL);
|
||||
ulReg = FIELD_SET(ulReg, VIDEO_ALPHA_DISPLAY_CTRL, PLANE, DISABLE);
|
||||
POKE32(VIDEO_ALPHA_DISPLAY_CTRL, ulReg);
|
||||
|
||||
/* Disable alpha plane, if a former application left it on */
|
||||
ulReg = PEEK32(ALPHA_DISPLAY_CTRL);
|
||||
ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE);
|
||||
POKE32(ALPHA_DISPLAY_CTRL, ulReg);
|
||||
|
||||
#if 0
|
||||
/* Disable LCD hardware cursor, if a former application left it on */
|
||||
ulReg = PEEK32(PANEL_HWC_ADDRESS);
|
||||
ulReg = FIELD_SET(ulReg, PANEL_HWC_ADDRESS, ENABLE, DISABLE);
|
||||
POKE32(PANEL_HWC_ADDRESS, ulReg);
|
||||
|
||||
/* Disable CRT hardware cursor, if a former application left it on */
|
||||
ulReg = PEEK32(CRT_HWC_ADDRESS);
|
||||
ulReg = FIELD_SET(ulReg, CRT_HWC_ADDRESS, ENABLE, DISABLE);
|
||||
POKE32(CRT_HWC_ADDRESS, ulReg);
|
||||
|
||||
/* Disable ZV Port 0, if a former application left it on */
|
||||
ulReg = PEEK32(ZV0_CAPTURE_CTRL);
|
||||
ulReg = FIELD_SET(ulReg, ZV0_CAPTURE_CTRL, CAP, DISABLE);
|
||||
POKE32(ZV0_CAPTURE_CTRL, ulReg);
|
||||
|
||||
/* Disable ZV Port 1, if a former application left it on */
|
||||
ulReg = PEEK32(ZV1_CAPTURE_CTRL);
|
||||
ulReg = FIELD_SET(ulReg, ZV1_CAPTURE_CTRL, CAP, DISABLE);
|
||||
POKE32(ZV1_CAPTURE_CTRL, ulReg);
|
||||
|
||||
/* Disable ZV Port Power, if a former application left it on */
|
||||
enableZVPort(0);
|
||||
/* Disable DMA Channel, if a former application left it on */
|
||||
ulReg = PEEK32(DMA_ABORT_INTERRUPT);
|
||||
ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT);
|
||||
POKE32(DMA_ABORT_INTERRUPT, ulReg);
|
||||
|
||||
/* Disable i2c */
|
||||
enableI2C(0);
|
||||
#endif
|
||||
/* Disable DMA Channel, if a former application left it on */
|
||||
ulReg = PEEK32(DMA_ABORT_INTERRUPT);
|
||||
ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT);
|
||||
POKE32(DMA_ABORT_INTERRUPT, ulReg);
|
||||
|
||||
/* Disable DMA Power, if a former application left it on */
|
||||
enableDMA(0);
|
||||
}
|
||||
|
||||
/* We can add more initialization as needed. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
unsigned int absDiff(unsigned int a, unsigned int b)
|
||||
{
|
||||
if ( a > b )
|
||||
return(a - b);
|
||||
else
|
||||
return(b - a);
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
monk liu @ 4/6/2011:
|
||||
re-write the calculatePLL function of ddk750.
|
||||
the original version function does not use some mathematics tricks and shortcut
|
||||
when it doing the calculation of the best N,M,D combination
|
||||
I think this version gives a little upgrade in speed
|
||||
|
||||
750 pll clock formular:
|
||||
Request Clock = (Input Clock * M )/(N * X)
|
||||
|
||||
Input Clock = 14318181 hz
|
||||
X = 2 power D
|
||||
D ={0,1,2,3,4,5,6}
|
||||
M = {1,...,255}
|
||||
N = {2,...,15}
|
||||
*/
|
||||
unsigned int calcPllValue(unsigned int request_orig,pll_value_t *pll)
|
||||
{
|
||||
/* used for primary and secondary channel pixel clock pll */
|
||||
static pllcalparam xparm_PIXEL[] = {
|
||||
/* 2^0 = 1*/ {0,0,0,1},
|
||||
/* 2^ 1 =2*/ {1,0,1,2},
|
||||
/* 2^ 2 = 4*/ {2,0,2,4},
|
||||
{3,0,3,8},
|
||||
{4,1,3,16},
|
||||
{5,2,3,32},
|
||||
/* 2^6 = 64 */ {6,3,3,64},
|
||||
};
|
||||
|
||||
/* used for MXCLK (chip clock) */
|
||||
static pllcalparam xparm_MXCLK[] = {
|
||||
/* 2^0 = 1*/ {0,0,0,1},
|
||||
/* 2^ 1 =2*/ {1,0,1,2},
|
||||
/* 2^ 2 = 4*/ {2,0,2,4},
|
||||
{3,0,3,8},
|
||||
};
|
||||
|
||||
/* as sm750 register definition, N located in 2,15 and M located in 1,255 */
|
||||
int N,M,X,d;
|
||||
int xcnt;
|
||||
int miniDiff;
|
||||
unsigned int RN,quo,rem,fl_quo;
|
||||
unsigned int input,request;
|
||||
unsigned int tmpClock,ret;
|
||||
pllcalparam * xparm;
|
||||
|
||||
#if 1
|
||||
if (getChipType() == SM750LE)
|
||||
{
|
||||
/* SM750LE don't have prgrammable PLL and M/N values to work on.
|
||||
Just return the requested clock. */
|
||||
return request_orig;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = 0;
|
||||
miniDiff = ~0;
|
||||
request = request_orig / 1000;
|
||||
input = pll->inputFreq / 1000;
|
||||
|
||||
/* for MXCLK register , no POD provided, so need be treated differently */
|
||||
|
||||
if(pll->clockType != MXCLK_PLL){
|
||||
xparm = &xparm_PIXEL[0];
|
||||
xcnt = sizeof(xparm_PIXEL)/sizeof(xparm_PIXEL[0]);
|
||||
}else{
|
||||
xparm = &xparm_MXCLK[0];
|
||||
xcnt = sizeof(xparm_MXCLK)/sizeof(xparm_MXCLK[0]);
|
||||
}
|
||||
|
||||
|
||||
for(N = 15;N>1;N--)
|
||||
{
|
||||
/* RN will not exceed maximum long if @request <= 285 MHZ (for 32bit cpu) */
|
||||
RN = N * request;
|
||||
quo = RN / input;
|
||||
rem = RN % input;/* rem always small than 14318181 */
|
||||
fl_quo = (rem * 10000 /input);
|
||||
|
||||
for(d = xcnt - 1;d >= 0;d--){
|
||||
X = xparm[d].value;
|
||||
M = quo*X;
|
||||
M += fl_quo * X / 10000;
|
||||
/* round step */
|
||||
M += (fl_quo*X % 10000)>5000?1:0;
|
||||
if(M < 256 && M > 0)
|
||||
{
|
||||
unsigned int diff;
|
||||
tmpClock = pll->inputFreq *M / N / X;
|
||||
diff = absDiff(tmpClock,request_orig);
|
||||
if(diff < miniDiff)
|
||||
{
|
||||
pll->M = M;
|
||||
pll->N = N;
|
||||
pll->OD = xparm[d].od;
|
||||
pll->POD = xparm[d].pod;
|
||||
miniDiff = diff;
|
||||
ret = tmpClock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printk("Finally: pll->n[%lu],m[%lu],od[%lu],pod[%lu]\n",pll->N,pll->M,pll->OD,pll->POD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int calcPllValue2(
|
||||
unsigned int ulRequestClk, /* Required pixel clock in Hz unit */
|
||||
pll_value_t *pPLL /* Structure to hold the value to be set in PLL */
|
||||
)
|
||||
{
|
||||
unsigned int M, N, OD, POD = 0, diff, pllClk, odPower, podPower;
|
||||
unsigned int bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */
|
||||
unsigned int ret;
|
||||
/* Init PLL structure to know states */
|
||||
pPLL->M = 0;
|
||||
pPLL->N = 0;
|
||||
pPLL->OD = 0;
|
||||
pPLL->POD = 0;
|
||||
|
||||
/* Sanity check: None at the moment */
|
||||
|
||||
/* Convert everything in Khz range in order to avoid calculation overflow */
|
||||
pPLL->inputFreq /= 1000;
|
||||
ulRequestClk /= 1000;
|
||||
|
||||
#ifndef VALIDATION_CHIP
|
||||
/* The maximum of post divider is 8. */
|
||||
for (POD=0; POD<=3; POD++)
|
||||
#endif
|
||||
{
|
||||
|
||||
#ifndef VALIDATION_CHIP
|
||||
/* MXCLK_PLL does not have post divider. */
|
||||
if ((POD > 0) && (pPLL->clockType == MXCLK_PLL))
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Work out 2 to the power of POD */
|
||||
podPower = twoToPowerOfx(POD);
|
||||
|
||||
/* OD has only 2 bits [15:14] and its value must between 0 to 3 */
|
||||
for (OD=0; OD<=3; OD++)
|
||||
{
|
||||
/* Work out 2 to the power of OD */
|
||||
odPower = twoToPowerOfx(OD);
|
||||
|
||||
#ifdef VALIDATION_CHIP
|
||||
if (odPower > 4)
|
||||
podPower = 4;
|
||||
else
|
||||
podPower = odPower;
|
||||
#endif
|
||||
|
||||
/* N has 4 bits [11:8] and its value must between 2 and 15.
|
||||
The N == 1 will behave differently --> Result is not correct. */
|
||||
for (N=2; N<=15; N++)
|
||||
{
|
||||
/* The formula for PLL is ulRequestClk = inputFreq * M / N / (2^OD)
|
||||
In the following steps, we try to work out a best M value given the others are known.
|
||||
To avoid decimal calculation, we use 1000 as multiplier for up to 3 decimal places of accuracy.
|
||||
*/
|
||||
M = ulRequestClk * N * odPower * 1000 / pPLL->inputFreq;
|
||||
M = roundedDiv(M, 1000);
|
||||
|
||||
/* M field has only 8 bits, reject value bigger than 8 bits */
|
||||
if (M < 256)
|
||||
{
|
||||
/* Calculate the actual clock for a given M & N */
|
||||
pllClk = pPLL->inputFreq * M / N / odPower / podPower;
|
||||
|
||||
/* How much are we different from the requirement */
|
||||
diff = absDiff(pllClk, ulRequestClk);
|
||||
|
||||
if (diff < bestDiff)
|
||||
{
|
||||
bestDiff = diff;
|
||||
|
||||
/* Store M and N values */
|
||||
pPLL->M = M;
|
||||
pPLL->N = N;
|
||||
pPLL->OD = OD;
|
||||
|
||||
#ifdef VALIDATION_CHIP
|
||||
if (OD > 2)
|
||||
POD = 2;
|
||||
else
|
||||
POD = OD;
|
||||
#endif
|
||||
|
||||
pPLL->POD = POD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore input frequency from Khz to hz unit */
|
||||
// pPLL->inputFreq *= 1000;
|
||||
ulRequestClk *= 1000;
|
||||
pPLL->inputFreq = DEFAULT_INPUT_CLOCK; /* Default reference clock */
|
||||
|
||||
/* Output debug information */
|
||||
//DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Requested Frequency = %d\n", ulRequestClk));
|
||||
//DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Input CLK = %dHz, M=%d, N=%d, OD=%d, POD=%d\n", pPLL->inputFreq, pPLL->M, pPLL->N, pPLL->OD, pPLL->POD));
|
||||
|
||||
/* Return actual frequency that the PLL can set */
|
||||
ret = calcPLL(pPLL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned int formatPllReg(pll_value_t *pPLL)
|
||||
{
|
||||
unsigned int ulPllReg = 0;
|
||||
|
||||
/* Note that all PLL's have the same format. Here, we just use Panel PLL parameter
|
||||
to work out the bit fields in the register.
|
||||
On returning a 32 bit number, the value can be applied to any PLL in the calling function.
|
||||
*/
|
||||
ulPllReg =
|
||||
FIELD_SET( 0, PANEL_PLL_CTRL, BYPASS, OFF)
|
||||
| FIELD_SET( 0, PANEL_PLL_CTRL, POWER, ON)
|
||||
| FIELD_SET( 0, PANEL_PLL_CTRL, INPUT, OSC)
|
||||
#ifndef VALIDATION_CHIP
|
||||
| FIELD_VALUE(0, PANEL_PLL_CTRL, POD, pPLL->POD)
|
||||
#endif
|
||||
| FIELD_VALUE(0, PANEL_PLL_CTRL, OD, pPLL->OD)
|
||||
| FIELD_VALUE(0, PANEL_PLL_CTRL, N, pPLL->N)
|
||||
| FIELD_VALUE(0, PANEL_PLL_CTRL, M, pPLL->M);
|
||||
|
||||
return(ulPllReg);
|
||||
}
|
||||
|
||||
|
83
drivers/staging/sm750fb/ddk750_chip.h
Normal file
83
drivers/staging/sm750fb/ddk750_chip.h
Normal file
@ -0,0 +1,83 @@
|
||||
#ifndef DDK750_CHIP_H__
|
||||
#define DDK750_CHIP_H__
|
||||
#define DEFAULT_INPUT_CLOCK 14318181 /* Default reference clock */
|
||||
#define SM750LE_REVISION_ID (char)0xfe
|
||||
|
||||
/* This is all the chips recognized by this library */
|
||||
typedef enum _logical_chip_type_t
|
||||
{
|
||||
SM_UNKNOWN,
|
||||
SM718,
|
||||
SM750,
|
||||
SM750LE,
|
||||
}
|
||||
logical_chip_type_t;
|
||||
|
||||
|
||||
typedef enum _clock_type_t
|
||||
{
|
||||
MXCLK_PLL,
|
||||
PRIMARY_PLL,
|
||||
SECONDARY_PLL,
|
||||
VGA0_PLL,
|
||||
VGA1_PLL,
|
||||
}
|
||||
clock_type_t;
|
||||
|
||||
typedef struct _pll_value_t
|
||||
{
|
||||
clock_type_t clockType;
|
||||
unsigned long inputFreq; /* Input clock frequency to the PLL */
|
||||
|
||||
/* Use this when clockType = PANEL_PLL */
|
||||
unsigned long M;
|
||||
unsigned long N;
|
||||
unsigned long OD;
|
||||
unsigned long POD;
|
||||
}
|
||||
pll_value_t;
|
||||
|
||||
/* input struct to initChipParam() function */
|
||||
typedef struct _initchip_param_t
|
||||
{
|
||||
unsigned short powerMode; /* Use power mode 0 or 1 */
|
||||
unsigned short chipClock; /* Speed of main chip clock in MHz unit
|
||||
0 = keep the current clock setting
|
||||
Others = the new main chip clock
|
||||
*/
|
||||
unsigned short memClock; /* Speed of memory clock in MHz unit
|
||||
0 = keep the current clock setting
|
||||
Others = the new memory clock
|
||||
*/
|
||||
unsigned short masterClock; /* Speed of master clock in MHz unit
|
||||
0 = keep the current clock setting
|
||||
Others = the new master clock
|
||||
*/
|
||||
unsigned short setAllEngOff; /* 0 = leave all engine state untouched.
|
||||
1 = make sure they are off: 2D, Overlay,
|
||||
video alpha, alpha, hardware cursors
|
||||
*/
|
||||
unsigned char resetMemory; /* 0 = Do not reset the memory controller
|
||||
1 = Reset the memory controller
|
||||
*/
|
||||
|
||||
/* More initialization parameter can be added if needed */
|
||||
}
|
||||
initchip_param_t;
|
||||
|
||||
|
||||
logical_chip_type_t getChipType(void);
|
||||
unsigned int calcPllValue(unsigned int request,pll_value_t *pll);
|
||||
unsigned int calcPllValue2(unsigned int,pll_value_t *);
|
||||
unsigned int formatPllReg(pll_value_t *pPLL);
|
||||
void ddk750_set_mmio(volatile unsigned char *,unsigned short,char);
|
||||
unsigned int ddk750_getVMSize(void);
|
||||
int ddk750_initHw(initchip_param_t *);
|
||||
unsigned int getPllValue(clock_type_t clockType, pll_value_t *pPLL);
|
||||
unsigned int getChipClock(void);
|
||||
void setChipClock(unsigned int);
|
||||
void setMemoryClock(unsigned int frequency);
|
||||
void setMasterClock(unsigned int frequency);
|
||||
|
||||
|
||||
#endif
|
318
drivers/staging/sm750fb/ddk750_display.c
Normal file
318
drivers/staging/sm750fb/ddk750_display.c
Normal file
@ -0,0 +1,318 @@
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_help.h"
|
||||
#include "ddk750_display.h"
|
||||
#include "ddk750_power.h"
|
||||
#include "ddk750_dvi.h"
|
||||
|
||||
#define primaryWaitVerticalSync(delay) waitNextVerticalSync(0,delay)
|
||||
|
||||
static void setDisplayControl(int ctrl,int dispState)
|
||||
{
|
||||
/* state != 0 means turn on both timing & plane en_bit */
|
||||
unsigned long ulDisplayCtrlReg, ulReservedBits;
|
||||
int cnt;
|
||||
|
||||
cnt = 0;
|
||||
|
||||
/* Set the primary display control */
|
||||
if (!ctrl)
|
||||
{
|
||||
ulDisplayCtrlReg = PEEK32(PANEL_DISPLAY_CTRL);
|
||||
/* Turn on/off the Panel display control */
|
||||
if (dispState)
|
||||
{
|
||||
/* Timing should be enabled first before enabling the plane
|
||||
* because changing at the same time does not guarantee that
|
||||
* the plane will also enabled or disabled.
|
||||
*/
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
PANEL_DISPLAY_CTRL, TIMING, ENABLE);
|
||||
POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
PANEL_DISPLAY_CTRL, PLANE, ENABLE);
|
||||
|
||||
/* Added some masks to mask out the reserved bits.
|
||||
* Sometimes, the reserved bits are set/reset randomly when
|
||||
* writing to the PRIMARY_DISPLAY_CTRL, therefore, the register
|
||||
* reserved bits are needed to be masked out.
|
||||
*/
|
||||
ulReservedBits = FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
|
||||
FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
|
||||
FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE);
|
||||
|
||||
/* Somehow the register value on the plane is not set
|
||||
* until a few delay. Need to write
|
||||
* and read it a couple times
|
||||
*/
|
||||
do
|
||||
{
|
||||
cnt++;
|
||||
POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
} while((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) !=
|
||||
(ulDisplayCtrlReg & ~ulReservedBits));
|
||||
printk("Set Panel Plane enbit:after tried %d times\n",cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When turning off, there is no rule on the programming
|
||||
* sequence since whenever the clock is off, then it does not
|
||||
* matter whether the plane is enabled or disabled.
|
||||
* Note: Modifying the plane bit will take effect on the
|
||||
* next vertical sync. Need to find out if it is necessary to
|
||||
* wait for 1 vsync before modifying the timing enable bit.
|
||||
* */
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
PANEL_DISPLAY_CTRL, PLANE, DISABLE);
|
||||
POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
PANEL_DISPLAY_CTRL, TIMING, DISABLE);
|
||||
POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
}
|
||||
|
||||
}
|
||||
/* Set the secondary display control */
|
||||
else
|
||||
{
|
||||
ulDisplayCtrlReg = PEEK32(CRT_DISPLAY_CTRL);
|
||||
|
||||
if (dispState)
|
||||
{
|
||||
/* Timing should be enabled first before enabling the plane because changing at the
|
||||
same time does not guarantee that the plane will also enabled or disabled.
|
||||
*/
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
CRT_DISPLAY_CTRL, TIMING, ENABLE);
|
||||
POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
CRT_DISPLAY_CTRL, PLANE, ENABLE);
|
||||
|
||||
/* Added some masks to mask out the reserved bits.
|
||||
* Sometimes, the reserved bits are set/reset randomly when
|
||||
* writing to the PRIMARY_DISPLAY_CTRL, therefore, the register
|
||||
* reserved bits are needed to be masked out.
|
||||
*/
|
||||
|
||||
ulReservedBits = FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
|
||||
FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
|
||||
FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE) |
|
||||
FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_4_MASK, ENABLE);
|
||||
|
||||
do
|
||||
{
|
||||
cnt++;
|
||||
POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
} while((PEEK32(CRT_DISPLAY_CTRL) & ~ulReservedBits) !=
|
||||
(ulDisplayCtrlReg & ~ulReservedBits));
|
||||
printk("Set Crt Plane enbit:after tried %d times\n",cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When turning off, there is no rule on the programming
|
||||
* sequence since whenever the clock is off, then it does not
|
||||
* matter whether the plane is enabled or disabled.
|
||||
* Note: Modifying the plane bit will take effect on the next
|
||||
* vertical sync. Need to find out if it is necessary to
|
||||
* wait for 1 vsync before modifying the timing enable bit.
|
||||
*/
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
CRT_DISPLAY_CTRL, PLANE, DISABLE);
|
||||
POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
|
||||
ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg,
|
||||
CRT_DISPLAY_CTRL, TIMING, DISABLE);
|
||||
POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void waitNextVerticalSync(int ctrl,int delay)
|
||||
{
|
||||
unsigned int status;
|
||||
if(!ctrl){
|
||||
/* primary controller */
|
||||
|
||||
/* Do not wait when the Primary PLL is off or display control is already off.
|
||||
This will prevent the software to wait forever. */
|
||||
if ((FIELD_GET(PEEK32(PANEL_PLL_CTRL), PANEL_PLL_CTRL, POWER) ==
|
||||
PANEL_PLL_CTRL_POWER_OFF) ||
|
||||
(FIELD_GET(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, TIMING) ==
|
||||
PANEL_DISPLAY_CTRL_TIMING_DISABLE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (delay-- > 0)
|
||||
{
|
||||
/* Wait for end of vsync. */
|
||||
do
|
||||
{
|
||||
status = FIELD_GET(PEEK32(SYSTEM_CTRL),
|
||||
SYSTEM_CTRL,
|
||||
PANEL_VSYNC);
|
||||
}
|
||||
while (status == SYSTEM_CTRL_PANEL_VSYNC_ACTIVE);
|
||||
|
||||
/* Wait for start of vsync. */
|
||||
do
|
||||
{
|
||||
status = FIELD_GET(PEEK32(SYSTEM_CTRL),
|
||||
SYSTEM_CTRL,
|
||||
PANEL_VSYNC);
|
||||
}
|
||||
while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE);
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
/* Do not wait when the Primary PLL is off or display control is already off.
|
||||
This will prevent the software to wait forever. */
|
||||
if ((FIELD_GET(PEEK32(CRT_PLL_CTRL), CRT_PLL_CTRL, POWER) ==
|
||||
CRT_PLL_CTRL_POWER_OFF) ||
|
||||
(FIELD_GET(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, TIMING) ==
|
||||
CRT_DISPLAY_CTRL_TIMING_DISABLE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (delay-- > 0)
|
||||
{
|
||||
/* Wait for end of vsync. */
|
||||
do
|
||||
{
|
||||
status = FIELD_GET(PEEK32(SYSTEM_CTRL),
|
||||
SYSTEM_CTRL,
|
||||
CRT_VSYNC);
|
||||
}
|
||||
while (status == SYSTEM_CTRL_CRT_VSYNC_ACTIVE);
|
||||
|
||||
/* Wait for start of vsync. */
|
||||
do
|
||||
{
|
||||
status = FIELD_GET(PEEK32(SYSTEM_CTRL),
|
||||
SYSTEM_CTRL,
|
||||
CRT_VSYNC);
|
||||
}
|
||||
while (status == SYSTEM_CTRL_CRT_VSYNC_INACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void swPanelPowerSequence_sm750le(int disp,int delay)
|
||||
{
|
||||
unsigned int reg;
|
||||
reg = PEEK32(DISPLAY_CONTROL_750LE);
|
||||
if(disp)
|
||||
reg |= 0xf;
|
||||
else
|
||||
reg &= ~0xf;
|
||||
POKE32(DISPLAY_CONTROL_750LE,reg);
|
||||
}
|
||||
|
||||
static void swPanelPowerSequence(int disp,int delay)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
/* disp should be 1 to open sequence */
|
||||
reg = PEEK32(PANEL_DISPLAY_CTRL);
|
||||
reg = FIELD_VALUE(reg,PANEL_DISPLAY_CTRL,FPEN,disp);
|
||||
POKE32(PANEL_DISPLAY_CTRL,reg);
|
||||
primaryWaitVerticalSync(delay);
|
||||
|
||||
|
||||
reg = PEEK32(PANEL_DISPLAY_CTRL);
|
||||
reg = FIELD_VALUE(reg,PANEL_DISPLAY_CTRL,DATA,disp);
|
||||
POKE32(PANEL_DISPLAY_CTRL,reg);
|
||||
primaryWaitVerticalSync(delay);
|
||||
|
||||
reg = PEEK32(PANEL_DISPLAY_CTRL);
|
||||
reg = FIELD_VALUE(reg,PANEL_DISPLAY_CTRL,VBIASEN,disp);
|
||||
POKE32(PANEL_DISPLAY_CTRL,reg);
|
||||
primaryWaitVerticalSync(delay);
|
||||
|
||||
|
||||
reg = PEEK32(PANEL_DISPLAY_CTRL);
|
||||
reg = FIELD_VALUE(reg,PANEL_DISPLAY_CTRL,FPEN,disp);
|
||||
POKE32(PANEL_DISPLAY_CTRL,reg);
|
||||
primaryWaitVerticalSync(delay);
|
||||
|
||||
}
|
||||
|
||||
void ddk750_setLogicalDispOut(disp_output_t output)
|
||||
{
|
||||
unsigned int reg;
|
||||
if(output & PNL_2_USAGE){
|
||||
/* set panel path controller select */
|
||||
reg = PEEK32(PANEL_DISPLAY_CTRL);
|
||||
reg = FIELD_VALUE(reg,PANEL_DISPLAY_CTRL,SELECT,(output & PNL_2_MASK)>>PNL_2_OFFSET);
|
||||
POKE32(PANEL_DISPLAY_CTRL,reg);
|
||||
}
|
||||
|
||||
if(output & CRT_2_USAGE){
|
||||
/* set crt path controller select */
|
||||
reg = PEEK32(CRT_DISPLAY_CTRL);
|
||||
reg = FIELD_VALUE(reg,CRT_DISPLAY_CTRL,SELECT,(output & CRT_2_MASK)>>CRT_2_OFFSET);
|
||||
/*se blank off */
|
||||
reg = FIELD_SET(reg,CRT_DISPLAY_CTRL,BLANK,OFF);
|
||||
POKE32(CRT_DISPLAY_CTRL,reg);
|
||||
|
||||
}
|
||||
|
||||
if(output & PRI_TP_USAGE){
|
||||
/* set primary timing and plane en_bit */
|
||||
setDisplayControl(0,(output&PRI_TP_MASK)>>PRI_TP_OFFSET);
|
||||
}
|
||||
|
||||
if(output & SEC_TP_USAGE){
|
||||
/* set secondary timing and plane en_bit*/
|
||||
setDisplayControl(1,(output&SEC_TP_MASK)>>SEC_TP_OFFSET);
|
||||
}
|
||||
|
||||
if(output & PNL_SEQ_USAGE){
|
||||
/* set panel sequence */
|
||||
swPanelPowerSequence((output&PNL_SEQ_MASK)>>PNL_SEQ_OFFSET,4);
|
||||
}
|
||||
|
||||
if(output & DAC_USAGE)
|
||||
setDAC((output & DAC_MASK)>>DAC_OFFSET);
|
||||
|
||||
if(output & DPMS_USAGE)
|
||||
ddk750_setDPMS((output & DPMS_MASK) >> DPMS_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
int ddk750_initDVIDisp()
|
||||
{
|
||||
/* Initialize DVI. If the dviInit fail and the VendorID or the DeviceID are
|
||||
not zeroed, then set the failure flag. If it is zeroe, it might mean
|
||||
that the system is in Dual CRT Monitor configuration. */
|
||||
|
||||
/* De-skew enabled with default 111b value.
|
||||
This will fix some artifacts problem in some mode on board 2.2.
|
||||
Somehow this fix does not affect board 2.1.
|
||||
*/
|
||||
if ((dviInit(1, /* Select Rising Edge */
|
||||
1, /* Select 24-bit bus */
|
||||
0, /* Select Single Edge clock */
|
||||
1, /* Enable HSync as is */
|
||||
1, /* Enable VSync as is */
|
||||
1, /* Enable De-skew */
|
||||
7, /* Set the de-skew setting to maximum setup */
|
||||
1, /* Enable continuous Sync */
|
||||
1, /* Enable PLL Filter */
|
||||
4 /* Use the recommended value for PLL Filter value */
|
||||
) != 0) && (dviGetVendorID() != 0x0000) && (dviGetDeviceID() != 0x0000))
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* TODO: Initialize other display component */
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
160
drivers/staging/sm750fb/ddk750_display.h
Normal file
160
drivers/staging/sm750fb/ddk750_display.h
Normal file
@ -0,0 +1,160 @@
|
||||
#ifndef DDK750_DISPLAY_H__
|
||||
#define DDK750_DISPLAY_H__
|
||||
|
||||
/* panel path select
|
||||
80000[29:28]
|
||||
*/
|
||||
|
||||
#define PNL_2_OFFSET 0
|
||||
#define PNL_2_MASK (3 << PNL_2_OFFSET)
|
||||
#define PNL_2_USAGE (PNL_2_MASK << 16)
|
||||
#define PNL_2_PRI ((0 << PNL_2_OFFSET)|PNL_2_USAGE)
|
||||
#define PNL_2_SEC ((2 << PNL_2_OFFSET)|PNL_2_USAGE)
|
||||
|
||||
|
||||
/* primary timing & plane enable bit
|
||||
1: 80000[8] & 80000[2] on
|
||||
0: both off
|
||||
*/
|
||||
#define PRI_TP_OFFSET 4
|
||||
#define PRI_TP_MASK (1 << PRI_TP_OFFSET)
|
||||
#define PRI_TP_USAGE (PRI_TP_MASK << 16)
|
||||
#define PRI_TP_ON ((0x1 << PRI_TP_OFFSET)|PRI_TP_USAGE)
|
||||
#define PRI_TP_OFF ((0x0 << PRI_TP_OFFSET)|PRI_TP_USAGE)
|
||||
|
||||
|
||||
/* panel sequency status
|
||||
80000[27:24]
|
||||
*/
|
||||
#define PNL_SEQ_OFFSET 6
|
||||
#define PNL_SEQ_MASK (1 << PNL_SEQ_OFFSET)
|
||||
#define PNL_SEQ_USAGE (PNL_SEQ_MASK << 16)
|
||||
#define PNL_SEQ_ON ((1 << PNL_SEQ_OFFSET)|PNL_SEQ_USAGE)
|
||||
#define PNL_SEQ_OFF ((0 << PNL_SEQ_OFFSET)|PNL_SEQ_USAGE)
|
||||
|
||||
/* dual digital output
|
||||
80000[19]
|
||||
*/
|
||||
#define DUAL_TFT_OFFSET 8
|
||||
#define DUAL_TFT_MASK (1 << DUAL_TFT_OFFSET)
|
||||
#define DUAL_TFT_USAGE (DUAL_TFT_MASK << 16)
|
||||
#define DUAL_TFT_ON ((1 << DUAL_TFT_OFFSET)|DUAL_TFT_USAGE)
|
||||
#define DUAL_TFT_OFF ((0 << DUAL_TFT_OFFSET)|DUAL_TFT_USAGE)
|
||||
|
||||
/* secondary timing & plane enable bit
|
||||
1:80200[8] & 80200[2] on
|
||||
0: both off
|
||||
*/
|
||||
#define SEC_TP_OFFSET 5
|
||||
#define SEC_TP_MASK (1<< SEC_TP_OFFSET)
|
||||
#define SEC_TP_USAGE (SEC_TP_MASK << 16)
|
||||
#define SEC_TP_ON ((0x1 << SEC_TP_OFFSET)|SEC_TP_USAGE)
|
||||
#define SEC_TP_OFF ((0x0 << SEC_TP_OFFSET)|SEC_TP_USAGE)
|
||||
|
||||
/* crt path select
|
||||
80200[19:18]
|
||||
*/
|
||||
#define CRT_2_OFFSET 2
|
||||
#define CRT_2_MASK (3 << CRT_2_OFFSET)
|
||||
#define CRT_2_USAGE (CRT_2_MASK << 16)
|
||||
#define CRT_2_PRI ((0x0 << CRT_2_OFFSET)|CRT_2_USAGE)
|
||||
#define CRT_2_SEC ((0x2 << CRT_2_OFFSET)|CRT_2_USAGE)
|
||||
|
||||
|
||||
/* DAC affect both DVI and DSUB
|
||||
4[20]
|
||||
*/
|
||||
#define DAC_OFFSET 7
|
||||
#define DAC_MASK (1 << DAC_OFFSET)
|
||||
#define DAC_USAGE (DAC_MASK << 16)
|
||||
#define DAC_ON ((0x0<< DAC_OFFSET)|DAC_USAGE)
|
||||
#define DAC_OFF ((0x1 << DAC_OFFSET)|DAC_USAGE)
|
||||
|
||||
/* DPMS only affect D-SUB head
|
||||
0[31:30]
|
||||
*/
|
||||
#define DPMS_OFFSET 9
|
||||
#define DPMS_MASK (3 << DPMS_OFFSET)
|
||||
#define DPMS_USAGE (DPMS_MASK << 16)
|
||||
#define DPMS_OFF ((3 << DPMS_OFFSET)|DPMS_USAGE)
|
||||
#define DPMS_ON ((0 << DPMS_OFFSET)|DPMS_USAGE)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
LCD1 means panel path TFT1 & panel path DVI (so enable DAC)
|
||||
CRT means crt path DSUB
|
||||
*/
|
||||
#if 0
|
||||
typedef enum _disp_output_t
|
||||
{
|
||||
NO_DISPLAY = DPMS_OFF,
|
||||
|
||||
LCD1_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|DPMS_OFF|DAC_ON,
|
||||
LCD1_SEC = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|DPMS_OFF|DAC_ON,
|
||||
|
||||
LCD2_PRI = CRT_2_PRI|PRI_TP_ON|DUAL_TFT_ON|DPMS_OFF,
|
||||
LCD2_SEC = CRT_2_SEC|SEC_TP_ON|DUAL_TFT_ON|DPMS_OFF,
|
||||
|
||||
DSUB_PRI = CRT_2_PRI|PRI_TP_ON|DAC_ON,
|
||||
DSUB_SEC = CRT_2_SEC|SEC_TP_ON|DAC_ON,
|
||||
|
||||
LCD1_DSUB_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|
|
||||
CRT_2_PRI|SEC_TP_OFF|DAC_ON,
|
||||
|
||||
LCD1_DSUB_SEC = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|
|
||||
CRT_2_SEC|PRI_TP_OFF|DAC_ON,
|
||||
|
||||
/* LCD1 show primary and DSUB show secondary */
|
||||
LCD1_DSUB_DUAL = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|
|
||||
CRT_2_SEC|SEC_TP_ON|DAC_ON,
|
||||
|
||||
/* LCD1 show secondary and DSUB show primary */
|
||||
LCD1_DSUB_DUAL_SWAP = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|
|
||||
CRT_2_PRI|PRI_TP_ON|DAC_ON,
|
||||
|
||||
LCD1_LCD2_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|
|
||||
CRT_2_PRI|SEC_TP_OFF|DPMS_OFF|DUAL_TFT_ON,
|
||||
|
||||
LCD1_LCD2_SEC = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|
|
||||
CRT_2_SEC|PRI_TP_OFF|DPMS_OFF|DUAL_TFT_ON,
|
||||
|
||||
LCD1_LCD2_DSUB_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|DAC_ON|
|
||||
CRT_2_PRI|SEC_TP_OFF|DPMS_ON|DUAL_TFT_ON,
|
||||
|
||||
LCD1_LCD2_DSUB_SEC = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|DAC_ON|
|
||||
CRT_2_SEC|PRI_TP_OFF|DPMS_ON|DUAL_TFT_ON,
|
||||
|
||||
|
||||
}
|
||||
disp_output_t;
|
||||
#else
|
||||
typedef enum _disp_output_t{
|
||||
do_LCD1_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|DAC_ON,
|
||||
do_LCD1_SEC = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|DAC_ON,
|
||||
#if 0
|
||||
do_LCD2_PRI = CRT_2_PRI|PRI_TP_ON,
|
||||
do_LCD2_SEC = CRT_2_SEC|SEC_TP_ON,
|
||||
#else
|
||||
do_LCD2_PRI = CRT_2_PRI|PRI_TP_ON|DUAL_TFT_ON,
|
||||
do_LCD2_SEC = CRT_2_SEC|SEC_TP_ON|DUAL_TFT_ON,
|
||||
#endif
|
||||
/*
|
||||
do_DSUB_PRI = CRT_2_PRI|PRI_TP_ON|DPMS_ON|DAC_ON,
|
||||
do_DSUB_SEC = CRT_2_SEC|SEC_TP_ON|DPMS_ON|DAC_ON,
|
||||
*/
|
||||
#if 0
|
||||
do_CRT_PRI = CRT_2_PRI|PRI_TP_ON,
|
||||
do_CRT_SEC = CRT_2_SEC|SEC_TP_ON,
|
||||
#else
|
||||
do_CRT_PRI = CRT_2_PRI|PRI_TP_ON|DPMS_ON|DAC_ON,
|
||||
do_CRT_SEC = CRT_2_SEC|SEC_TP_ON|DPMS_ON|DAC_ON,
|
||||
#endif
|
||||
}
|
||||
disp_output_t;
|
||||
#endif
|
||||
|
||||
void ddk750_setLogicalDispOut(disp_output_t);
|
||||
int ddk750_initDVIDisp(void);
|
||||
|
||||
#endif
|
99
drivers/staging/sm750fb/ddk750_dvi.c
Normal file
99
drivers/staging/sm750fb/ddk750_dvi.c
Normal file
@ -0,0 +1,99 @@
|
||||
#define USE_DVICHIP
|
||||
#ifdef USE_DVICHIP
|
||||
#include "ddk750_help.h"
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_dvi.h"
|
||||
#include "ddk750_sii164.h"
|
||||
|
||||
|
||||
/* This global variable contains all the supported driver and its corresponding
|
||||
function API. Please set the function pointer to NULL whenever the function
|
||||
is not supported. */
|
||||
static dvi_ctrl_device_t g_dcftSupportedDviController[] =
|
||||
{
|
||||
#ifdef DVI_CTRL_SII164
|
||||
{
|
||||
.pfnInit = sii164InitChip,
|
||||
.pfnGetVendorId = sii164GetVendorID,
|
||||
.pfnGetDeviceId = sii164GetDeviceID,
|
||||
#ifdef SII164_FULL_FUNCTIONS
|
||||
.pfnResetChip = sii164ResetChip,
|
||||
.pfnGetChipString = sii164GetChipString,
|
||||
.pfnSetPower = sii164SetPower,
|
||||
.pfnEnableHotPlugDetection = sii164EnableHotPlugDetection,
|
||||
.pfnIsConnected = sii164IsConnected,
|
||||
.pfnCheckInterrupt = sii164CheckInterrupt,
|
||||
.pfnClearInterrupt = sii164ClearInterrupt,
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
int dviInit(
|
||||
unsigned char edgeSelect,
|
||||
unsigned char busSelect,
|
||||
unsigned char dualEdgeClkSelect,
|
||||
unsigned char hsyncEnable,
|
||||
unsigned char vsyncEnable,
|
||||
unsigned char deskewEnable,
|
||||
unsigned char deskewSetting,
|
||||
unsigned char continuousSyncEnable,
|
||||
unsigned char pllFilterEnable,
|
||||
unsigned char pllFilterValue
|
||||
)
|
||||
{
|
||||
dvi_ctrl_device_t *pCurrentDviCtrl;
|
||||
pCurrentDviCtrl = g_dcftSupportedDviController;
|
||||
if(pCurrentDviCtrl->pfnInit != NULL)
|
||||
{
|
||||
return pCurrentDviCtrl->pfnInit(edgeSelect, busSelect, dualEdgeClkSelect, hsyncEnable,
|
||||
vsyncEnable, deskewEnable, deskewSetting, continuousSyncEnable,
|
||||
pllFilterEnable, pllFilterValue);
|
||||
}
|
||||
return -1;//error
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dviGetVendorID
|
||||
* This function gets the vendor ID of the DVI controller chip.
|
||||
*
|
||||
* Output:
|
||||
* Vendor ID
|
||||
*/
|
||||
unsigned short dviGetVendorID()
|
||||
{
|
||||
dvi_ctrl_device_t *pCurrentDviCtrl;
|
||||
|
||||
//pCurrentDviCtrl = getDviCtrl();
|
||||
pCurrentDviCtrl = g_dcftSupportedDviController;
|
||||
if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0)
|
||||
return pCurrentDviCtrl->pfnGetVendorId();
|
||||
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dviGetDeviceID
|
||||
* This function gets the device ID of the DVI controller chip.
|
||||
*
|
||||
* Output:
|
||||
* Device ID
|
||||
*/
|
||||
unsigned short dviGetDeviceID()
|
||||
{
|
||||
dvi_ctrl_device_t *pCurrentDviCtrl;
|
||||
|
||||
// pCurrentDviCtrl = getDviCtrl();
|
||||
pCurrentDviCtrl = g_dcftSupportedDviController;
|
||||
if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0)
|
||||
return pCurrentDviCtrl->pfnGetDeviceId();
|
||||
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
67
drivers/staging/sm750fb/ddk750_dvi.h
Normal file
67
drivers/staging/sm750fb/ddk750_dvi.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef DDK750_DVI_H__
|
||||
#define DDK750_DVI_H__
|
||||
|
||||
/* dvi chip stuffs structros */
|
||||
|
||||
typedef long (*PFN_DVICTRL_INIT)(
|
||||
unsigned char edgeSelect,
|
||||
unsigned char busSelect,
|
||||
unsigned char dualEdgeClkSelect,
|
||||
unsigned char hsyncEnable,
|
||||
unsigned char vsyncEnable,
|
||||
unsigned char deskewEnable,
|
||||
unsigned char deskewSetting,
|
||||
unsigned char continuousSyncEnable,
|
||||
unsigned char pllFilterEnable,
|
||||
unsigned char pllFilterValue);
|
||||
typedef void (*PFN_DVICTRL_RESETCHIP)(void);
|
||||
typedef char* (*PFN_DVICTRL_GETCHIPSTRING)(void);
|
||||
typedef unsigned short (*PFN_DVICTRL_GETVENDORID)(void);
|
||||
typedef unsigned short (*PFN_DVICTRL_GETDEVICEID)(void);
|
||||
typedef void (*PFN_DVICTRL_SETPOWER)(unsigned char powerUp);
|
||||
typedef void (*PFN_DVICTRL_HOTPLUGDETECTION)(unsigned char enableHotPlug);
|
||||
typedef unsigned char (*PFN_DVICTRL_ISCONNECTED)(void);
|
||||
typedef unsigned char (*PFN_DVICTRL_CHECKINTERRUPT)(void);
|
||||
typedef void (*PFN_DVICTRL_CLEARINTERRUPT)(void);
|
||||
|
||||
|
||||
|
||||
/* Structure to hold all the function pointer to the DVI Controller. */
|
||||
typedef struct _dvi_ctrl_device_t
|
||||
{
|
||||
PFN_DVICTRL_INIT pfnInit;
|
||||
PFN_DVICTRL_RESETCHIP pfnResetChip;
|
||||
PFN_DVICTRL_GETCHIPSTRING pfnGetChipString;
|
||||
PFN_DVICTRL_GETVENDORID pfnGetVendorId;
|
||||
PFN_DVICTRL_GETDEVICEID pfnGetDeviceId;
|
||||
PFN_DVICTRL_SETPOWER pfnSetPower;
|
||||
PFN_DVICTRL_HOTPLUGDETECTION pfnEnableHotPlugDetection;
|
||||
PFN_DVICTRL_ISCONNECTED pfnIsConnected;
|
||||
PFN_DVICTRL_CHECKINTERRUPT pfnCheckInterrupt;
|
||||
PFN_DVICTRL_CLEARINTERRUPT pfnClearInterrupt;
|
||||
} dvi_ctrl_device_t;
|
||||
#define DVI_CTRL_SII164
|
||||
|
||||
|
||||
|
||||
/* dvi functions prototype */
|
||||
int dviInit(
|
||||
unsigned char edgeSelect,
|
||||
unsigned char busSelect,
|
||||
unsigned char dualEdgeClkSelect,
|
||||
unsigned char hsyncEnable,
|
||||
unsigned char vsyncEnable,
|
||||
unsigned char deskewEnable,
|
||||
unsigned char deskewSetting,
|
||||
unsigned char continuousSyncEnable,
|
||||
unsigned char pllFilterEnable,
|
||||
unsigned char pllFilterValue
|
||||
);
|
||||
|
||||
unsigned short dviGetVendorID(void);
|
||||
unsigned short dviGetDeviceID(void);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
19
drivers/staging/sm750fb/ddk750_help.c
Normal file
19
drivers/staging/sm750fb/ddk750_help.c
Normal file
@ -0,0 +1,19 @@
|
||||
//#include "ddk750_reg.h"
|
||||
//#include "ddk750_chip.h"
|
||||
#include "ddk750_help.h"
|
||||
|
||||
volatile unsigned char __iomem * mmio750 = NULL;
|
||||
char revId750 = 0;
|
||||
unsigned short devId750 = 0;
|
||||
|
||||
/* after driver mapped io registers, use this function first */
|
||||
void ddk750_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId)
|
||||
{
|
||||
mmio750 = addr;
|
||||
devId750 = devId;
|
||||
revId750 = revId;
|
||||
if(revId == 0xfe)
|
||||
printk("found sm750le\n");
|
||||
}
|
||||
|
||||
|
29
drivers/staging/sm750fb/ddk750_help.h
Normal file
29
drivers/staging/sm750fb/ddk750_help.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef DDK750_HELP_H__
|
||||
#define DDK750_HELP_H__
|
||||
#include "ddk750_chip.h"
|
||||
#ifndef USE_INTERNAL_REGISTER_ACCESS
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "sm750_help.h"
|
||||
|
||||
|
||||
#if 0
|
||||
/* if 718 big endian turned on,be aware that don't use this driver for general use,only for ppc big-endian */
|
||||
#warning "big endian on target cpu and enable nature big endian support of 718 capability !"
|
||||
#define PEEK32(addr) __raw_readl((void __iomem *)(mmio750)+(addr))
|
||||
#define POKE32(addr,data) __raw_writel((data),(void __iomem*)(mmio750)+(addr))
|
||||
#else /* software control endianess */
|
||||
#define PEEK32(addr) readl((addr)+mmio750)
|
||||
#define POKE32(addr,data) writel((data),(addr)+mmio750)
|
||||
#endif
|
||||
|
||||
extern volatile unsigned char __iomem * mmio750;
|
||||
extern char revId750;
|
||||
extern unsigned short devId750;
|
||||
#else
|
||||
/* implement if you want use it*/
|
||||
#endif
|
||||
|
||||
#endif
|
271
drivers/staging/sm750fb/ddk750_hwi2c.c
Normal file
271
drivers/staging/sm750fb/ddk750_hwi2c.c
Normal file
@ -0,0 +1,271 @@
|
||||
#define USE_HW_I2C
|
||||
#ifdef USE_HW_I2C
|
||||
#include "ddk750_help.h"
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_hwi2c.h"
|
||||
#include "ddk750_power.h"
|
||||
|
||||
#define MAX_HWI2C_FIFO 16
|
||||
#define HWI2C_WAIT_TIMEOUT 0xF0000
|
||||
|
||||
|
||||
int hwI2CInit(
|
||||
unsigned char busSpeedMode
|
||||
)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
/* Enable GPIO 30 & 31 as IIC clock & data */
|
||||
value = PEEK32(GPIO_MUX);
|
||||
|
||||
value = FIELD_SET(value, GPIO_MUX, 30, I2C) |
|
||||
FIELD_SET(0, GPIO_MUX, 31, I2C);
|
||||
POKE32(GPIO_MUX, value);
|
||||
|
||||
/* Enable Hardware I2C power.
|
||||
TODO: Check if we need to enable GPIO power?
|
||||
*/
|
||||
enableI2C(1);
|
||||
|
||||
/* Enable the I2C Controller and set the bus speed mode */
|
||||
value = PEEK32(I2C_CTRL);
|
||||
if (busSpeedMode == 0)
|
||||
value = FIELD_SET(value, I2C_CTRL, MODE, STANDARD);
|
||||
else
|
||||
value = FIELD_SET(value, I2C_CTRL, MODE, FAST);
|
||||
value = FIELD_SET(value, I2C_CTRL, EN, ENABLE);
|
||||
POKE32(I2C_CTRL, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hwI2CClose(void)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
/* Disable I2C controller */
|
||||
value = PEEK32(I2C_CTRL);
|
||||
value = FIELD_SET(value, I2C_CTRL, EN, DISABLE);
|
||||
POKE32(I2C_CTRL, value);
|
||||
|
||||
/* Disable I2C Power */
|
||||
enableI2C(0);
|
||||
|
||||
/* Set GPIO 30 & 31 back as GPIO pins */
|
||||
value = PEEK32(GPIO_MUX);
|
||||
value = FIELD_SET(value, GPIO_MUX, 30, GPIO);
|
||||
value = FIELD_SET(value, GPIO_MUX, 31, GPIO);
|
||||
POKE32(GPIO_MUX, value);
|
||||
}
|
||||
|
||||
|
||||
long hwI2CWaitTXDone(void)
|
||||
{
|
||||
unsigned int timeout;
|
||||
|
||||
/* Wait until the transfer is completed. */
|
||||
timeout = HWI2C_WAIT_TIMEOUT;
|
||||
while ((FIELD_GET(PEEK32(I2C_STATUS), I2C_STATUS, TX) != I2C_STATUS_TX_COMPLETED) &&
|
||||
(timeout != 0))
|
||||
timeout--;
|
||||
|
||||
if (timeout == 0)
|
||||
return (-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function writes data to the i2c slave device registers.
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address
|
||||
* length - Total number of bytes to be written to the device
|
||||
* pBuffer - The buffer that contains the data to be written to the
|
||||
* i2c device.
|
||||
*
|
||||
* Return Value:
|
||||
* Total number of bytes those are actually written.
|
||||
*/
|
||||
unsigned int hwI2CWriteData(
|
||||
unsigned char deviceAddress,
|
||||
unsigned int length,
|
||||
unsigned char *pBuffer
|
||||
)
|
||||
{
|
||||
unsigned char count, i;
|
||||
unsigned int totalBytes = 0;
|
||||
|
||||
/* Set the Device Address */
|
||||
POKE32(I2C_SLAVE_ADDRESS, deviceAddress & ~0x01);
|
||||
|
||||
/* Write data.
|
||||
* Note:
|
||||
* Only 16 byte can be accessed per i2c start instruction.
|
||||
*/
|
||||
do
|
||||
{
|
||||
/* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */
|
||||
POKE32(I2C_RESET, 0);
|
||||
|
||||
/* Set the number of bytes to be written */
|
||||
if (length < MAX_HWI2C_FIFO)
|
||||
count = length - 1;
|
||||
else
|
||||
count = MAX_HWI2C_FIFO - 1;
|
||||
POKE32(I2C_BYTE_COUNT, count);
|
||||
|
||||
/* Move the data to the I2C data register */
|
||||
for (i = 0; i <= count; i++)
|
||||
POKE32(I2C_DATA0 + i, *pBuffer++);
|
||||
|
||||
/* Start the I2C */
|
||||
POKE32(I2C_CTRL, FIELD_SET(PEEK32(I2C_CTRL), I2C_CTRL, CTRL, START));
|
||||
|
||||
/* Wait until the transfer is completed. */
|
||||
if (hwI2CWaitTXDone() != 0)
|
||||
break;
|
||||
|
||||
/* Substract length */
|
||||
length -= (count + 1);
|
||||
|
||||
/* Total byte written */
|
||||
totalBytes += (count + 1);
|
||||
|
||||
} while (length > 0);
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function reads data from the slave device and stores them
|
||||
* in the given buffer
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address
|
||||
* length - Total number of bytes to be read
|
||||
* pBuffer - Pointer to a buffer to be filled with the data read
|
||||
* from the slave device. It has to be the same size as the
|
||||
* length to make sure that it can keep all the data read.
|
||||
*
|
||||
* Return Value:
|
||||
* Total number of actual bytes read from the slave device
|
||||
*/
|
||||
unsigned int hwI2CReadData(
|
||||
unsigned char deviceAddress,
|
||||
unsigned int length,
|
||||
unsigned char *pBuffer
|
||||
)
|
||||
{
|
||||
unsigned char count, i;
|
||||
unsigned int totalBytes = 0;
|
||||
|
||||
/* Set the Device Address */
|
||||
POKE32(I2C_SLAVE_ADDRESS, deviceAddress | 0x01);
|
||||
|
||||
/* Read data and save them to the buffer.
|
||||
* Note:
|
||||
* Only 16 byte can be accessed per i2c start instruction.
|
||||
*/
|
||||
do
|
||||
{
|
||||
/* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */
|
||||
POKE32(I2C_RESET, 0);
|
||||
|
||||
/* Set the number of bytes to be read */
|
||||
if (length <= MAX_HWI2C_FIFO)
|
||||
count = length - 1;
|
||||
else
|
||||
count = MAX_HWI2C_FIFO - 1;
|
||||
POKE32(I2C_BYTE_COUNT, count);
|
||||
|
||||
/* Start the I2C */
|
||||
POKE32(I2C_CTRL, FIELD_SET(PEEK32(I2C_CTRL), I2C_CTRL, CTRL, START));
|
||||
|
||||
/* Wait until transaction done. */
|
||||
if (hwI2CWaitTXDone() != 0)
|
||||
break;
|
||||
|
||||
/* Save the data to the given buffer */
|
||||
for (i = 0; i <= count; i++)
|
||||
*pBuffer++ = PEEK32(I2C_DATA0 + i);
|
||||
|
||||
/* Substract length by 16 */
|
||||
length -= (count + 1);
|
||||
|
||||
/* Number of bytes read. */
|
||||
totalBytes += (count + 1);
|
||||
|
||||
} while (length > 0);
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function reads the slave device's register
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address which register
|
||||
* to be read from
|
||||
* registerIndex - Slave device's register to be read
|
||||
*
|
||||
* Return Value:
|
||||
* Register value
|
||||
*/
|
||||
unsigned char hwI2CReadReg(
|
||||
unsigned char deviceAddress,
|
||||
unsigned char registerIndex
|
||||
)
|
||||
{
|
||||
unsigned char value = (0xFF);
|
||||
|
||||
if (hwI2CWriteData(deviceAddress, 1, ®isterIndex) == 1)
|
||||
hwI2CReadData(deviceAddress, 1, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function writes a value to the slave device's register
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address which register
|
||||
* to be written
|
||||
* registerIndex - Slave device's register to be written
|
||||
* data - Data to be written to the register
|
||||
*
|
||||
* Result:
|
||||
* 0 - Success
|
||||
* -1 - Fail
|
||||
*/
|
||||
int hwI2CWriteReg(
|
||||
unsigned char deviceAddress,
|
||||
unsigned char registerIndex,
|
||||
unsigned char data
|
||||
)
|
||||
{
|
||||
unsigned char value[2];
|
||||
|
||||
value[0] = registerIndex;
|
||||
value[1] = data;
|
||||
if (hwI2CWriteData(deviceAddress, 2, value) == 2)
|
||||
return 0;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
10
drivers/staging/sm750fb/ddk750_hwi2c.h
Normal file
10
drivers/staging/sm750fb/ddk750_hwi2c.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef DDK750_HWI2C_H__
|
||||
#define DDK750_HWI2C_H__
|
||||
|
||||
/* hwi2c functions */
|
||||
int hwI2CInit(unsigned char busSpeedMode);
|
||||
void hwI2CClose(void);
|
||||
|
||||
unsigned char hwI2CReadReg(unsigned char deviceAddress,unsigned char registerIndex);
|
||||
int hwI2CWriteReg(unsigned char deviceAddress,unsigned char registerIndex,unsigned char data);
|
||||
#endif
|
205
drivers/staging/sm750fb/ddk750_mode.c
Normal file
205
drivers/staging/sm750fb/ddk750_mode.c
Normal file
@ -0,0 +1,205 @@
|
||||
|
||||
#include "ddk750_help.h"
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_mode.h"
|
||||
#include "ddk750_chip.h"
|
||||
|
||||
/*
|
||||
SM750LE only:
|
||||
This function takes care extra registers and bit fields required to set
|
||||
up a mode in SM750LE
|
||||
|
||||
Explanation about Display Control register:
|
||||
HW only supports 7 predefined pixel clocks, and clock select is
|
||||
in bit 29:27 of Display Control register.
|
||||
*/
|
||||
static unsigned long displayControlAdjust_SM750LE(mode_parameter_t *pModeParam, unsigned long dispControl)
|
||||
{
|
||||
unsigned long x, y;
|
||||
|
||||
x = pModeParam->horizontal_display_end;
|
||||
y = pModeParam->vertical_display_end;
|
||||
|
||||
/* SM750LE has to set up the top-left and bottom-right
|
||||
registers as well.
|
||||
Note that normal SM750/SM718 only use those two register for
|
||||
auto-centering mode.
|
||||
*/
|
||||
POKE32(CRT_AUTO_CENTERING_TL,
|
||||
FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, TOP, 0)
|
||||
| FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, LEFT, 0));
|
||||
|
||||
POKE32(CRT_AUTO_CENTERING_BR,
|
||||
FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, BOTTOM, y-1)
|
||||
| FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, RIGHT, x-1));
|
||||
|
||||
/* Assume common fields in dispControl have been properly set before
|
||||
calling this function.
|
||||
This function only sets the extra fields in dispControl.
|
||||
*/
|
||||
|
||||
/* Clear bit 29:27 of display control register */
|
||||
dispControl &= FIELD_CLEAR(CRT_DISPLAY_CTRL, CLK);
|
||||
|
||||
/* Set bit 29:27 of display control register for the right clock */
|
||||
/* Note that SM750LE only need to supported 7 resoluitons. */
|
||||
if ( x == 800 && y == 600 )
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL41);
|
||||
else if (x == 1024 && y == 768)
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL65);
|
||||
else if (x == 1152 && y == 864)
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80);
|
||||
else if (x == 1280 && y == 768)
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80);
|
||||
else if (x == 1280 && y == 720)
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL74);
|
||||
else if (x == 1280 && y == 960)
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108);
|
||||
else if (x == 1280 && y == 1024)
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108);
|
||||
else /* default to VGA clock */
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL25);
|
||||
|
||||
/* Set bit 25:24 of display controller */
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CRTSELECT, CRT);
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, RGBBIT, 24BIT);
|
||||
|
||||
/* Set bit 14 of display controller */
|
||||
dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW);
|
||||
|
||||
POKE32(CRT_DISPLAY_CTRL, dispControl);
|
||||
|
||||
return dispControl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* only timing related registers will be programed */
|
||||
static int programModeRegisters(mode_parameter_t * pModeParam,pll_value_t * pll)
|
||||
{
|
||||
int ret = 0;
|
||||
int cnt = 0;
|
||||
unsigned int ulTmpValue,ulReg;
|
||||
if(pll->clockType == SECONDARY_PLL)
|
||||
{
|
||||
/* programe secondary pixel clock */
|
||||
POKE32(CRT_PLL_CTRL,formatPllReg(pll));
|
||||
POKE32(CRT_HORIZONTAL_TOTAL,
|
||||
FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1)
|
||||
| FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1));
|
||||
|
||||
POKE32(CRT_HORIZONTAL_SYNC,
|
||||
FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width)
|
||||
| FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1));
|
||||
|
||||
POKE32(CRT_VERTICAL_TOTAL,
|
||||
FIELD_VALUE(0, CRT_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1)
|
||||
| FIELD_VALUE(0, CRT_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1));
|
||||
|
||||
POKE32(CRT_VERTICAL_SYNC,
|
||||
FIELD_VALUE(0, CRT_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height)
|
||||
| FIELD_VALUE(0, CRT_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1));
|
||||
|
||||
|
||||
ulTmpValue = FIELD_VALUE(0,CRT_DISPLAY_CTRL,VSYNC_PHASE,pModeParam->vertical_sync_polarity)|
|
||||
FIELD_VALUE(0,CRT_DISPLAY_CTRL,HSYNC_PHASE,pModeParam->horizontal_sync_polarity)|
|
||||
FIELD_SET(0,CRT_DISPLAY_CTRL,TIMING,ENABLE)|
|
||||
FIELD_SET(0,CRT_DISPLAY_CTRL,PLANE,ENABLE);
|
||||
|
||||
|
||||
if(getChipType() == SM750LE){
|
||||
displayControlAdjust_SM750LE(pModeParam,ulTmpValue);
|
||||
}else{
|
||||
ulReg = PEEK32(CRT_DISPLAY_CTRL)
|
||||
& FIELD_CLEAR(CRT_DISPLAY_CTRL,VSYNC_PHASE)
|
||||
& FIELD_CLEAR(CRT_DISPLAY_CTRL,HSYNC_PHASE)
|
||||
& FIELD_CLEAR(CRT_DISPLAY_CTRL,TIMING)
|
||||
& FIELD_CLEAR(CRT_DISPLAY_CTRL,PLANE);
|
||||
|
||||
POKE32(CRT_DISPLAY_CTRL,ulTmpValue|ulReg);
|
||||
}
|
||||
|
||||
}
|
||||
else if(pll->clockType == PRIMARY_PLL)
|
||||
{
|
||||
unsigned int ulReservedBits;
|
||||
POKE32(PANEL_PLL_CTRL,formatPllReg(pll));
|
||||
|
||||
POKE32(PANEL_HORIZONTAL_TOTAL,
|
||||
FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1)
|
||||
| FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1));
|
||||
|
||||
POKE32(PANEL_HORIZONTAL_SYNC,
|
||||
FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width)
|
||||
| FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1));
|
||||
|
||||
POKE32(PANEL_VERTICAL_TOTAL,
|
||||
FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1)
|
||||
| FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1));
|
||||
|
||||
POKE32(PANEL_VERTICAL_SYNC,
|
||||
FIELD_VALUE(0, PANEL_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height)
|
||||
| FIELD_VALUE(0, PANEL_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1));
|
||||
|
||||
ulTmpValue = FIELD_VALUE(0,PANEL_DISPLAY_CTRL,VSYNC_PHASE,pModeParam->vertical_sync_polarity)|
|
||||
FIELD_VALUE(0,PANEL_DISPLAY_CTRL,HSYNC_PHASE,pModeParam->horizontal_sync_polarity)|
|
||||
FIELD_VALUE(0,PANEL_DISPLAY_CTRL,CLOCK_PHASE,pModeParam->clock_phase_polarity)|
|
||||
FIELD_SET(0,PANEL_DISPLAY_CTRL,TIMING,ENABLE)|
|
||||
FIELD_SET(0,PANEL_DISPLAY_CTRL,PLANE,ENABLE);
|
||||
|
||||
ulReservedBits = FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
|
||||
FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
|
||||
FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE)|
|
||||
FIELD_SET(0,PANEL_DISPLAY_CTRL,VSYNC,ACTIVE_LOW);
|
||||
|
||||
ulReg = (PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits)
|
||||
& FIELD_CLEAR(PANEL_DISPLAY_CTRL, CLOCK_PHASE)
|
||||
& FIELD_CLEAR(PANEL_DISPLAY_CTRL, VSYNC_PHASE)
|
||||
& FIELD_CLEAR(PANEL_DISPLAY_CTRL, HSYNC_PHASE)
|
||||
& FIELD_CLEAR(PANEL_DISPLAY_CTRL, TIMING)
|
||||
& FIELD_CLEAR(PANEL_DISPLAY_CTRL, PLANE);
|
||||
|
||||
|
||||
/* May a hardware bug or just my test chip (not confirmed).
|
||||
* PANEL_DISPLAY_CTRL register seems requiring few writes
|
||||
* before a value can be succesfully written in.
|
||||
* Added some masks to mask out the reserved bits.
|
||||
* Note: This problem happens by design. The hardware will wait for the
|
||||
* next vertical sync to turn on/off the plane.
|
||||
*/
|
||||
|
||||
POKE32(PANEL_DISPLAY_CTRL,ulTmpValue|ulReg);
|
||||
#if 1
|
||||
while((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != (ulTmpValue|ulReg))
|
||||
{
|
||||
cnt++;
|
||||
if(cnt > 1000)
|
||||
break;
|
||||
POKE32(PANEL_DISPLAY_CTRL,ulTmpValue|ulReg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ddk750_setModeTiming(mode_parameter_t * parm,clock_type_t clock)
|
||||
{
|
||||
pll_value_t pll;
|
||||
unsigned int uiActualPixelClk;
|
||||
pll.inputFreq = DEFAULT_INPUT_CLOCK;
|
||||
pll.clockType = clock;
|
||||
|
||||
uiActualPixelClk = calcPllValue(parm->pixel_clock,&pll);
|
||||
if(getChipType() == SM750LE){
|
||||
/* set graphic mode via IO method */
|
||||
outb_p(0x88,0x3d4);
|
||||
outb_p(0x06,0x3d5);
|
||||
}
|
||||
programModeRegisters(parm,&pll);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
43
drivers/staging/sm750fb/ddk750_mode.h
Normal file
43
drivers/staging/sm750fb/ddk750_mode.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef DDK750_MODE_H__
|
||||
#define DDK750_MODE_H__
|
||||
|
||||
#include "ddk750_chip.h"
|
||||
|
||||
typedef enum _spolarity_t
|
||||
{
|
||||
POS = 0, /* positive */
|
||||
NEG, /* negative */
|
||||
}
|
||||
spolarity_t;
|
||||
|
||||
|
||||
typedef struct _mode_parameter_t
|
||||
{
|
||||
/* Horizontal timing. */
|
||||
unsigned long horizontal_total;
|
||||
unsigned long horizontal_display_end;
|
||||
unsigned long horizontal_sync_start;
|
||||
unsigned long horizontal_sync_width;
|
||||
spolarity_t horizontal_sync_polarity;
|
||||
|
||||
/* Vertical timing. */
|
||||
unsigned long vertical_total;
|
||||
unsigned long vertical_display_end;
|
||||
unsigned long vertical_sync_start;
|
||||
unsigned long vertical_sync_height;
|
||||
spolarity_t vertical_sync_polarity;
|
||||
|
||||
/* Refresh timing. */
|
||||
unsigned long pixel_clock;
|
||||
unsigned long horizontal_frequency;
|
||||
unsigned long vertical_frequency;
|
||||
|
||||
/* Clock Phase. This clock phase only applies to Panel. */
|
||||
spolarity_t clock_phase_polarity;
|
||||
}
|
||||
mode_parameter_t;
|
||||
|
||||
int ddk750_setModeTiming(mode_parameter_t *,clock_type_t);
|
||||
|
||||
|
||||
#endif
|
239
drivers/staging/sm750fb/ddk750_power.c
Normal file
239
drivers/staging/sm750fb/ddk750_power.c
Normal file
@ -0,0 +1,239 @@
|
||||
#include "ddk750_help.h"
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_power.h"
|
||||
|
||||
void ddk750_setDPMS(DPMS_t state)
|
||||
{
|
||||
unsigned int value;
|
||||
if(getChipType() == SM750LE){
|
||||
value = PEEK32(CRT_DISPLAY_CTRL);
|
||||
POKE32(CRT_DISPLAY_CTRL,FIELD_VALUE(value,CRT_DISPLAY_CTRL,DPMS,state));
|
||||
}else{
|
||||
value = PEEK32(SYSTEM_CTRL);
|
||||
value= FIELD_VALUE(value,SYSTEM_CTRL,DPMS,state);
|
||||
POKE32(SYSTEM_CTRL, value);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getPowerMode()
|
||||
{
|
||||
if(getChipType() == SM750LE)
|
||||
return 0;
|
||||
return (FIELD_GET(PEEK32(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SM50x can operate in one of three modes: 0, 1 or Sleep.
|
||||
* On hardware reset, power mode 0 is default.
|
||||
*/
|
||||
void setPowerMode(unsigned int powerMode)
|
||||
{
|
||||
unsigned int control_value = 0;
|
||||
|
||||
control_value = PEEK32(POWER_MODE_CTRL);
|
||||
|
||||
if(getChipType() == SM750LE)
|
||||
return;
|
||||
|
||||
switch (powerMode)
|
||||
{
|
||||
case POWER_MODE_CTRL_MODE_MODE0:
|
||||
control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0);
|
||||
break;
|
||||
|
||||
case POWER_MODE_CTRL_MODE_MODE1:
|
||||
control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE1);
|
||||
break;
|
||||
|
||||
case POWER_MODE_CTRL_MODE_SLEEP:
|
||||
control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, SLEEP);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set up other fields in Power Control Register */
|
||||
if (powerMode == POWER_MODE_CTRL_MODE_SLEEP)
|
||||
{
|
||||
control_value =
|
||||
#ifdef VALIDATION_CHIP
|
||||
FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, OFF) |
|
||||
#endif
|
||||
FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, OFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
control_value =
|
||||
#ifdef VALIDATION_CHIP
|
||||
FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, ON) |
|
||||
#endif
|
||||
FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, ON);
|
||||
}
|
||||
|
||||
/* Program new power mode. */
|
||||
POKE32(POWER_MODE_CTRL, control_value);
|
||||
}
|
||||
|
||||
void setCurrentGate(unsigned int gate)
|
||||
{
|
||||
unsigned int gate_reg;
|
||||
unsigned int mode;
|
||||
|
||||
/* Get current power mode. */
|
||||
mode = getPowerMode();
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case POWER_MODE_CTRL_MODE_MODE0:
|
||||
gate_reg = MODE0_GATE;
|
||||
break;
|
||||
|
||||
case POWER_MODE_CTRL_MODE_MODE1:
|
||||
gate_reg = MODE1_GATE;
|
||||
break;
|
||||
|
||||
default:
|
||||
gate_reg = MODE0_GATE;
|
||||
break;
|
||||
}
|
||||
POKE32(gate_reg, gate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function enable/disable the 2D engine.
|
||||
*/
|
||||
void enable2DEngine(unsigned int enable)
|
||||
{
|
||||
uint32_t gate;
|
||||
|
||||
gate = PEEK32(CURRENT_GATE);
|
||||
if (enable)
|
||||
{
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, DE, ON);
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, CSC, ON);
|
||||
}
|
||||
else
|
||||
{
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, DE, OFF);
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, CSC, OFF);
|
||||
}
|
||||
|
||||
setCurrentGate(gate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function enable/disable the ZV Port.
|
||||
*/
|
||||
void enableZVPort(unsigned int enable)
|
||||
{
|
||||
uint32_t gate;
|
||||
|
||||
/* Enable ZV Port Gate */
|
||||
gate = PEEK32(CURRENT_GATE);
|
||||
if (enable)
|
||||
{
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, ON);
|
||||
#if 1
|
||||
/* Using Software I2C */
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON);
|
||||
#else
|
||||
/* Using Hardware I2C */
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable ZV Port Gate. There is no way to know whether the GPIO pins are being used
|
||||
or not. Therefore, do not disable the GPIO gate. */
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, OFF);
|
||||
}
|
||||
|
||||
setCurrentGate(gate);
|
||||
}
|
||||
|
||||
|
||||
void enableSSP(unsigned int enable)
|
||||
{
|
||||
uint32_t gate;
|
||||
|
||||
/* Enable SSP Gate */
|
||||
gate = PEEK32(CURRENT_GATE);
|
||||
if (enable)
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, SSP, ON);
|
||||
else
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, SSP, OFF);
|
||||
|
||||
setCurrentGate(gate);
|
||||
}
|
||||
|
||||
void enableDMA(unsigned int enable)
|
||||
{
|
||||
uint32_t gate;
|
||||
|
||||
/* Enable DMA Gate */
|
||||
gate = PEEK32(CURRENT_GATE);
|
||||
if (enable)
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, DMA, ON);
|
||||
else
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, DMA, OFF);
|
||||
|
||||
setCurrentGate(gate);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function enable/disable the GPIO Engine
|
||||
*/
|
||||
void enableGPIO(unsigned int enable)
|
||||
{
|
||||
uint32_t gate;
|
||||
|
||||
/* Enable GPIO Gate */
|
||||
gate = PEEK32(CURRENT_GATE);
|
||||
if (enable)
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON);
|
||||
else
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, GPIO, OFF);
|
||||
|
||||
setCurrentGate(gate);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function enable/disable the PWM Engine
|
||||
*/
|
||||
void enablePWM(unsigned int enable)
|
||||
{
|
||||
uint32_t gate;
|
||||
|
||||
/* Enable PWM Gate */
|
||||
gate = PEEK32(CURRENT_GATE);
|
||||
if (enable)
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, PWM, ON);
|
||||
else
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, PWM, OFF);
|
||||
|
||||
setCurrentGate(gate);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function enable/disable the I2C Engine
|
||||
*/
|
||||
void enableI2C(unsigned int enable)
|
||||
{
|
||||
uint32_t gate;
|
||||
|
||||
/* Enable I2C Gate */
|
||||
gate = PEEK32(CURRENT_GATE);
|
||||
if (enable)
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON);
|
||||
else
|
||||
gate = FIELD_SET(gate, CURRENT_GATE, I2C, OFF);
|
||||
|
||||
setCurrentGate(gate);
|
||||
}
|
||||
|
||||
|
71
drivers/staging/sm750fb/ddk750_power.h
Normal file
71
drivers/staging/sm750fb/ddk750_power.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef DDK750_POWER_H__
|
||||
#define DDK750_POWER_H__
|
||||
|
||||
typedef enum _DPMS_t
|
||||
{
|
||||
crtDPMS_ON = 0x0,
|
||||
crtDPMS_STANDBY = 0x1,
|
||||
crtDPMS_SUSPEND = 0x2,
|
||||
crtDPMS_OFF = 0x3,
|
||||
}
|
||||
DPMS_t;
|
||||
|
||||
#define setDAC(off) \
|
||||
{ \
|
||||
POKE32(MISC_CTRL,FIELD_VALUE(PEEK32(MISC_CTRL), \
|
||||
MISC_CTRL, \
|
||||
DAC_POWER, \
|
||||
off)); \
|
||||
}
|
||||
|
||||
void ddk750_setDPMS(DPMS_t);
|
||||
|
||||
unsigned int getPowerMode(void);
|
||||
|
||||
/*
|
||||
* This function sets the current power mode
|
||||
*/
|
||||
void setPowerMode(unsigned int powerMode);
|
||||
|
||||
/*
|
||||
* This function sets current gate
|
||||
*/
|
||||
void setCurrentGate(unsigned int gate);
|
||||
|
||||
/*
|
||||
* This function enable/disable the 2D engine.
|
||||
*/
|
||||
void enable2DEngine(unsigned int enable);
|
||||
|
||||
/*
|
||||
* This function enable/disable the ZV Port
|
||||
*/
|
||||
void enableZVPort(unsigned int enable);
|
||||
|
||||
/*
|
||||
* This function enable/disable the DMA Engine
|
||||
*/
|
||||
void enableDMA(unsigned int enable);
|
||||
|
||||
/*
|
||||
* This function enable/disable the GPIO Engine
|
||||
*/
|
||||
void enableGPIO(unsigned int enable);
|
||||
|
||||
/*
|
||||
* This function enable/disable the PWM Engine
|
||||
*/
|
||||
void enablePWM(unsigned int enable);
|
||||
|
||||
/*
|
||||
* This function enable/disable the I2C Engine
|
||||
*/
|
||||
void enableI2C(unsigned int enable);
|
||||
|
||||
/*
|
||||
* This function enable/disable the SSP.
|
||||
*/
|
||||
void enableSSP(unsigned int enable);
|
||||
|
||||
|
||||
#endif
|
2616
drivers/staging/sm750fb/ddk750_reg.h
Normal file
2616
drivers/staging/sm750fb/ddk750_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
425
drivers/staging/sm750fb/ddk750_sii164.c
Normal file
425
drivers/staging/sm750fb/ddk750_sii164.c
Normal file
@ -0,0 +1,425 @@
|
||||
#define USE_DVICHIP
|
||||
#ifdef USE_DVICHIP
|
||||
|
||||
#include "ddk750_sii164.h"
|
||||
#include "ddk750_hwi2c.h"
|
||||
|
||||
/* I2C Address of each SII164 chip */
|
||||
#define SII164_I2C_ADDRESS 0x70
|
||||
|
||||
/* Define this definition to use hardware i2c. */
|
||||
#define USE_HW_I2C
|
||||
|
||||
#ifdef USE_HW_I2C
|
||||
#define i2cWriteReg hwI2CWriteReg
|
||||
#define i2cReadReg hwI2CReadReg
|
||||
#else
|
||||
#define i2cWriteReg swI2CWriteReg
|
||||
#define i2cReadReg swI2CReadReg
|
||||
#endif
|
||||
|
||||
/* SII164 Vendor and Device ID */
|
||||
#define SII164_VENDOR_ID 0x0001
|
||||
#define SII164_DEVICE_ID 0x0006
|
||||
|
||||
#ifdef SII164_FULL_FUNCTIONS
|
||||
/* Name of the DVI Controller chip */
|
||||
static char *gDviCtrlChipName = "Silicon Image SiI 164";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* sii164GetVendorID
|
||||
* This function gets the vendor ID of the DVI controller chip.
|
||||
*
|
||||
* Output:
|
||||
* Vendor ID
|
||||
*/
|
||||
unsigned short sii164GetVendorID()
|
||||
{
|
||||
unsigned short vendorID;
|
||||
|
||||
vendorID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) |
|
||||
(unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW);
|
||||
|
||||
return vendorID;
|
||||
}
|
||||
|
||||
/*
|
||||
* sii164GetDeviceID
|
||||
* This function gets the device ID of the DVI controller chip.
|
||||
*
|
||||
* Output:
|
||||
* Device ID
|
||||
*/
|
||||
unsigned short sii164GetDeviceID()
|
||||
{
|
||||
unsigned short deviceID;
|
||||
|
||||
deviceID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) |
|
||||
(unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW);
|
||||
|
||||
return deviceID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* DVI.C will handle all SiI164 chip stuffs and try it best to make code minimal and useful */
|
||||
|
||||
/*
|
||||
* sii164InitChip
|
||||
* This function initialize and detect the DVI controller chip.
|
||||
*
|
||||
* Input:
|
||||
* edgeSelect - Edge Select:
|
||||
* 0 = Input data is falling edge latched (falling edge
|
||||
* latched first in dual edge mode)
|
||||
* 1 = Input data is rising edge latched (rising edge
|
||||
* latched first in dual edge mode)
|
||||
* busSelect - Input Bus Select:
|
||||
* 0 = Input data bus is 12-bits wide
|
||||
* 1 = Input data bus is 24-bits wide
|
||||
* dualEdgeClkSelect - Dual Edge Clock Select
|
||||
* 0 = Input data is single edge latched
|
||||
* 1 = Input data is dual edge latched
|
||||
* hsyncEnable - Horizontal Sync Enable:
|
||||
* 0 = HSYNC input is transmitted as fixed LOW
|
||||
* 1 = HSYNC input is transmitted as is
|
||||
* vsyncEnable - Vertical Sync Enable:
|
||||
* 0 = VSYNC input is transmitted as fixed LOW
|
||||
* 1 = VSYNC input is transmitted as is
|
||||
* deskewEnable - De-skewing Enable:
|
||||
* 0 = De-skew disabled
|
||||
* 1 = De-skew enabled
|
||||
* deskewSetting - De-skewing Setting (increment of 260psec)
|
||||
* 0 = 1 step --> minimum setup / maximum hold
|
||||
* 1 = 2 step
|
||||
* 2 = 3 step
|
||||
* 3 = 4 step
|
||||
* 4 = 5 step
|
||||
* 5 = 6 step
|
||||
* 6 = 7 step
|
||||
* 7 = 8 step --> maximum setup / minimum hold
|
||||
* continuousSyncEnable- SYNC Continuous:
|
||||
* 0 = Disable
|
||||
* 1 = Enable
|
||||
* pllFilterEnable - PLL Filter Enable
|
||||
* 0 = Disable PLL Filter
|
||||
* 1 = Enable PLL Filter
|
||||
* pllFilterValue - PLL Filter characteristics:
|
||||
* 0~7 (recommended value is 4)
|
||||
*
|
||||
* Output:
|
||||
* 0 - Success
|
||||
* -1 - Fail.
|
||||
*/
|
||||
long sii164InitChip(
|
||||
unsigned char edgeSelect,
|
||||
unsigned char busSelect,
|
||||
unsigned char dualEdgeClkSelect,
|
||||
unsigned char hsyncEnable,
|
||||
unsigned char vsyncEnable,
|
||||
unsigned char deskewEnable,
|
||||
unsigned char deskewSetting,
|
||||
unsigned char continuousSyncEnable,
|
||||
unsigned char pllFilterEnable,
|
||||
unsigned char pllFilterValue
|
||||
)
|
||||
{
|
||||
//unsigned char ucRegIndex, ucRegValue;
|
||||
//unsigned char ucDeviceAddress,
|
||||
unsigned char config;
|
||||
//unsigned long delayCount;
|
||||
|
||||
/* Initialize the i2c bus */
|
||||
#ifdef USE_HW_I2C
|
||||
/* Use fast mode. */
|
||||
hwI2CInit(1);
|
||||
#else
|
||||
swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
|
||||
#endif
|
||||
|
||||
/* Check if SII164 Chip exists */
|
||||
if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID))
|
||||
{
|
||||
|
||||
#ifdef DDKDEBUG
|
||||
//sii164PrintRegisterValues();
|
||||
#endif
|
||||
/*
|
||||
* Initialize SII164 controller chip.
|
||||
*/
|
||||
|
||||
/* Select the edge */
|
||||
if (edgeSelect == 0)
|
||||
config = SII164_CONFIGURATION_LATCH_FALLING;
|
||||
else
|
||||
config = SII164_CONFIGURATION_LATCH_RISING;
|
||||
|
||||
/* Select bus wide */
|
||||
if (busSelect == 0)
|
||||
config |= SII164_CONFIGURATION_BUS_12BITS;
|
||||
else
|
||||
config |= SII164_CONFIGURATION_BUS_24BITS;
|
||||
|
||||
/* Select Dual/Single Edge Clock */
|
||||
if (dualEdgeClkSelect == 0)
|
||||
config |= SII164_CONFIGURATION_CLOCK_SINGLE;
|
||||
else
|
||||
config |= SII164_CONFIGURATION_CLOCK_DUAL;
|
||||
|
||||
/* Select HSync Enable */
|
||||
if (hsyncEnable == 0)
|
||||
config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW;
|
||||
else
|
||||
config |= SII164_CONFIGURATION_HSYNC_AS_IS;
|
||||
|
||||
/* Select VSync Enable */
|
||||
if (vsyncEnable == 0)
|
||||
config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW;
|
||||
else
|
||||
config |= SII164_CONFIGURATION_VSYNC_AS_IS;
|
||||
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
|
||||
|
||||
/* De-skew enabled with default 111b value.
|
||||
This will fix some artifacts problem in some mode on board 2.2.
|
||||
Somehow this fix does not affect board 2.1.
|
||||
*/
|
||||
if (deskewEnable == 0)
|
||||
config = SII164_DESKEW_DISABLE;
|
||||
else
|
||||
config = SII164_DESKEW_ENABLE;
|
||||
|
||||
switch (deskewSetting)
|
||||
{
|
||||
case 0:
|
||||
config |= SII164_DESKEW_1_STEP;
|
||||
break;
|
||||
case 1:
|
||||
config |= SII164_DESKEW_2_STEP;
|
||||
break;
|
||||
case 2:
|
||||
config |= SII164_DESKEW_3_STEP;
|
||||
break;
|
||||
case 3:
|
||||
config |= SII164_DESKEW_4_STEP;
|
||||
break;
|
||||
case 4:
|
||||
config |= SII164_DESKEW_5_STEP;
|
||||
break;
|
||||
case 5:
|
||||
config |= SII164_DESKEW_6_STEP;
|
||||
break;
|
||||
case 6:
|
||||
config |= SII164_DESKEW_7_STEP;
|
||||
break;
|
||||
case 7:
|
||||
config |= SII164_DESKEW_8_STEP;
|
||||
break;
|
||||
}
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config);
|
||||
|
||||
/* Enable/Disable Continuous Sync. */
|
||||
if (continuousSyncEnable == 0)
|
||||
config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE;
|
||||
else
|
||||
config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE;
|
||||
|
||||
/* Enable/Disable PLL Filter */
|
||||
if (pllFilterEnable == 0)
|
||||
config |= SII164_PLL_FILTER_DISABLE;
|
||||
else
|
||||
config |= SII164_PLL_FILTER_ENABLE;
|
||||
|
||||
/* Set the PLL Filter value */
|
||||
config |= ((pllFilterValue & 0x07) << 1);
|
||||
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config);
|
||||
|
||||
/* Recover from Power Down and enable output. */
|
||||
config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
|
||||
config |= SII164_CONFIGURATION_POWER_NORMAL;
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
|
||||
|
||||
#ifdef DDKDEBUG
|
||||
//sii164PrintRegisterValues();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return -1 if initialization fails. */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* below sii164 function is not neccessary */
|
||||
|
||||
#ifdef SII164_FULL_FUNCTIONS
|
||||
|
||||
/*
|
||||
* sii164ResetChip
|
||||
* This function resets the DVI Controller Chip.
|
||||
*/
|
||||
void sii164ResetChip()
|
||||
{
|
||||
/* Power down */
|
||||
sii164SetPower(0);
|
||||
sii164SetPower(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sii164GetChipString
|
||||
* This function returns a char string name of the current DVI Controller chip.
|
||||
* It's convenient for application need to display the chip name.
|
||||
*/
|
||||
char *sii164GetChipString()
|
||||
{
|
||||
return gDviCtrlChipName;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sii164SetPower
|
||||
* This function sets the power configuration of the DVI Controller Chip.
|
||||
*
|
||||
* Input:
|
||||
* powerUp - Flag to set the power down or up
|
||||
*/
|
||||
void sii164SetPower(
|
||||
unsigned char powerUp
|
||||
)
|
||||
{
|
||||
unsigned char config;
|
||||
|
||||
config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
|
||||
if (powerUp == 1)
|
||||
{
|
||||
/* Power up the chip */
|
||||
config &= ~SII164_CONFIGURATION_POWER_MASK;
|
||||
config |= SII164_CONFIGURATION_POWER_NORMAL;
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Power down the chip */
|
||||
config &= ~SII164_CONFIGURATION_POWER_MASK;
|
||||
config |= SII164_CONFIGURATION_POWER_DOWN;
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sii164SelectHotPlugDetectionMode
|
||||
* This function selects the mode of the hot plug detection.
|
||||
*/
|
||||
static void sii164SelectHotPlugDetectionMode(
|
||||
sii164_hot_plug_mode_t hotPlugMode
|
||||
)
|
||||
{
|
||||
unsigned char detectReg;
|
||||
|
||||
detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG;
|
||||
switch (hotPlugMode)
|
||||
{
|
||||
case SII164_HOTPLUG_DISABLE:
|
||||
detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH;
|
||||
break;
|
||||
case SII164_HOTPLUG_USE_MDI:
|
||||
detectReg &= ~SII164_DETECT_INTERRUPT_MASK;
|
||||
detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN;
|
||||
detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI;
|
||||
break;
|
||||
case SII164_HOTPLUG_USE_RSEN:
|
||||
detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN;
|
||||
break;
|
||||
case SII164_HOTPLUG_USE_HTPLG:
|
||||
detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG;
|
||||
break;
|
||||
}
|
||||
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg);
|
||||
}
|
||||
|
||||
/*
|
||||
* sii164EnableHotPlugDetection
|
||||
* This function enables the Hot Plug detection.
|
||||
*
|
||||
* enableHotPlug - Enable (=1) / disable (=0) Hot Plug detection
|
||||
*/
|
||||
void sii164EnableHotPlugDetection(
|
||||
unsigned char enableHotPlug
|
||||
)
|
||||
{
|
||||
unsigned char detectReg;
|
||||
detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
|
||||
|
||||
/* Depending on each DVI controller, need to enable the hot plug based on each
|
||||
individual chip design. */
|
||||
if (enableHotPlug != 0)
|
||||
sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI);
|
||||
else
|
||||
sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* sii164IsConnected
|
||||
* Check if the DVI Monitor is connected.
|
||||
*
|
||||
* Output:
|
||||
* 0 - Not Connected
|
||||
* 1 - Connected
|
||||
*/
|
||||
unsigned char sii164IsConnected()
|
||||
{
|
||||
unsigned char hotPlugValue;
|
||||
|
||||
hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_HOT_PLUG_STATUS_MASK;
|
||||
if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sii164CheckInterrupt
|
||||
* Checks if interrupt has occured.
|
||||
*
|
||||
* Output:
|
||||
* 0 - No interrupt
|
||||
* 1 - Interrupt occurs
|
||||
*/
|
||||
unsigned char sii164CheckInterrupt()
|
||||
{
|
||||
unsigned char detectReg;
|
||||
|
||||
detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_MONITOR_STATE_MASK;
|
||||
if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sii164ClearInterrupt
|
||||
* Clear the hot plug interrupt.
|
||||
*/
|
||||
void sii164ClearInterrupt()
|
||||
{
|
||||
unsigned char detectReg;
|
||||
|
||||
/* Clear the MDI interrupt */
|
||||
detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
|
||||
i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg | SII164_DETECT_MONITOR_STATE_CLEAR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
172
drivers/staging/sm750fb/ddk750_sii164.h
Normal file
172
drivers/staging/sm750fb/ddk750_sii164.h
Normal file
@ -0,0 +1,172 @@
|
||||
#ifndef DDK750_SII164_H__
|
||||
#define DDK750_SII164_H__
|
||||
|
||||
#define USE_DVICHIP
|
||||
|
||||
/* Hot Plug detection mode structure */
|
||||
typedef enum _sii164_hot_plug_mode_t
|
||||
{
|
||||
SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit (always high). */
|
||||
SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */
|
||||
SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */
|
||||
SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */
|
||||
} sii164_hot_plug_mode_t;
|
||||
|
||||
|
||||
/* Silicon Image SiI164 chip prototype */
|
||||
long sii164InitChip(
|
||||
unsigned char edgeSelect,
|
||||
unsigned char busSelect,
|
||||
unsigned char dualEdgeClkSelect,
|
||||
unsigned char hsyncEnable,
|
||||
unsigned char vsyncEnable,
|
||||
unsigned char deskewEnable,
|
||||
unsigned char deskewSetting,
|
||||
unsigned char continuousSyncEnable,
|
||||
unsigned char pllFilterEnable,
|
||||
unsigned char pllFilterValue
|
||||
);
|
||||
|
||||
unsigned short sii164GetVendorID(void);
|
||||
unsigned short sii164GetDeviceID(void);
|
||||
|
||||
|
||||
#ifdef SII164_FULL_FUNCTIONS
|
||||
void sii164ResetChip(void);
|
||||
char *sii164GetChipString(void);
|
||||
void sii164SetPower(unsigned char powerUp);
|
||||
void sii164EnableHotPlugDetection(unsigned char enableHotPlug);
|
||||
unsigned char sii164IsConnected(void);
|
||||
unsigned char sii164CheckInterrupt(void);
|
||||
void sii164ClearInterrupt(void);
|
||||
#endif
|
||||
/* below register definination is used for Silicon Image SiI164 DVI controller chip */
|
||||
/*
|
||||
* Vendor ID registers
|
||||
*/
|
||||
#define SII164_VENDOR_ID_LOW 0x00
|
||||
#define SII164_VENDOR_ID_HIGH 0x01
|
||||
|
||||
/*
|
||||
* Device ID registers
|
||||
*/
|
||||
#define SII164_DEVICE_ID_LOW 0x02
|
||||
#define SII164_DEVICE_ID_HIGH 0x03
|
||||
|
||||
/*
|
||||
* Device Revision
|
||||
*/
|
||||
#define SII164_DEVICE_REVISION 0x04
|
||||
|
||||
/*
|
||||
* Frequency Limitation registers
|
||||
*/
|
||||
#define SII164_FREQUENCY_LIMIT_LOW 0x06
|
||||
#define SII164_FREQUENCY_LIMIT_HIGH 0x07
|
||||
|
||||
/*
|
||||
* Power Down and Input Signal Configuration registers
|
||||
*/
|
||||
#define SII164_CONFIGURATION 0x08
|
||||
|
||||
/* Power down (PD) */
|
||||
#define SII164_CONFIGURATION_POWER_DOWN 0x00
|
||||
#define SII164_CONFIGURATION_POWER_NORMAL 0x01
|
||||
#define SII164_CONFIGURATION_POWER_MASK 0x01
|
||||
|
||||
/* Input Edge Latch Select (EDGE) */
|
||||
#define SII164_CONFIGURATION_LATCH_FALLING 0x00
|
||||
#define SII164_CONFIGURATION_LATCH_RISING 0x02
|
||||
|
||||
/* Bus Select (BSEL) */
|
||||
#define SII164_CONFIGURATION_BUS_12BITS 0x00
|
||||
#define SII164_CONFIGURATION_BUS_24BITS 0x04
|
||||
|
||||
/* Dual Edge Clock Select (DSEL) */
|
||||
#define SII164_CONFIGURATION_CLOCK_SINGLE 0x00
|
||||
#define SII164_CONFIGURATION_CLOCK_DUAL 0x08
|
||||
|
||||
/* Horizontal Sync Enable (HEN) */
|
||||
#define SII164_CONFIGURATION_HSYNC_FORCE_LOW 0x00
|
||||
#define SII164_CONFIGURATION_HSYNC_AS_IS 0x10
|
||||
|
||||
/* Vertical Sync Enable (VEN) */
|
||||
#define SII164_CONFIGURATION_VSYNC_FORCE_LOW 0x00
|
||||
#define SII164_CONFIGURATION_VSYNC_AS_IS 0x20
|
||||
|
||||
/*
|
||||
* Detection registers
|
||||
*/
|
||||
#define SII164_DETECT 0x09
|
||||
|
||||
/* Monitor Detect Interrupt (MDI) */
|
||||
#define SII164_DETECT_MONITOR_STATE_CHANGE 0x00
|
||||
#define SII164_DETECT_MONITOR_STATE_NO_CHANGE 0x01
|
||||
#define SII164_DETECT_MONITOR_STATE_CLEAR 0x01
|
||||
#define SII164_DETECT_MONITOR_STATE_MASK 0x01
|
||||
|
||||
/* Hot Plug detect Input (HTPLG) */
|
||||
#define SII164_DETECT_HOT_PLUG_STATUS_OFF 0x00
|
||||
#define SII164_DETECT_HOT_PLUG_STATUS_ON 0x02
|
||||
#define SII164_DETECT_HOT_PLUG_STATUS_MASK 0x02
|
||||
|
||||
/* Receiver Sense (RSEN) */
|
||||
#define SII164_DETECT_RECEIVER_SENSE_NOT_DETECTED 0x00
|
||||
#define SII164_DETECT_RECEIVER_SENSE_DETECTED 0x04
|
||||
|
||||
/* Interrupt Generation Method (TSEL) */
|
||||
#define SII164_DETECT_INTERRUPT_BY_RSEN_PIN 0x00
|
||||
#define SII164_DETECT_INTERRUPT_BY_HTPLG_PIN 0x08
|
||||
#define SII164_DETECT_INTERRUPT_MASK 0x08
|
||||
|
||||
/* Monitor Sense Output (MSEN) */
|
||||
#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH 0x00
|
||||
#define SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI 0x10
|
||||
#define SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN 0x20
|
||||
#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG 0x30
|
||||
#define SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG 0x30
|
||||
|
||||
/*
|
||||
* Skewing registers
|
||||
*/
|
||||
#define SII164_DESKEW 0x0A
|
||||
|
||||
/* General Purpose Input (CTL[3:1]) */
|
||||
#define SII164_DESKEW_GENERAL_PURPOSE_INPUT_MASK 0x0E
|
||||
|
||||
/* De-skewing Enable bit (DKEN) */
|
||||
#define SII164_DESKEW_DISABLE 0x00
|
||||
#define SII164_DESKEW_ENABLE 0x10
|
||||
|
||||
/* De-skewing Setting (DK[3:1])*/
|
||||
#define SII164_DESKEW_1_STEP 0x00
|
||||
#define SII164_DESKEW_2_STEP 0x20
|
||||
#define SII164_DESKEW_3_STEP 0x40
|
||||
#define SII164_DESKEW_4_STEP 0x60
|
||||
#define SII164_DESKEW_5_STEP 0x80
|
||||
#define SII164_DESKEW_6_STEP 0xA0
|
||||
#define SII164_DESKEW_7_STEP 0xC0
|
||||
#define SII164_DESKEW_8_STEP 0xE0
|
||||
|
||||
/*
|
||||
* User Configuration Data registers (CFG 7:0)
|
||||
*/
|
||||
#define SII164_USER_CONFIGURATION 0x0B
|
||||
|
||||
/*
|
||||
* PLL registers
|
||||
*/
|
||||
#define SII164_PLL 0x0C
|
||||
|
||||
/* PLL Filter Value (PLLF) */
|
||||
#define SII164_PLL_FILTER_VALUE_MASK 0x0E
|
||||
|
||||
/* PLL Filter Enable (PFEN) */
|
||||
#define SII164_PLL_FILTER_DISABLE 0x00
|
||||
#define SII164_PLL_FILTER_ENABLE 0x01
|
||||
|
||||
/* Sync Continuous (SCNT) */
|
||||
#define SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE 0x00
|
||||
#define SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE 0x80
|
||||
|
||||
#endif
|
535
drivers/staging/sm750fb/ddk750_swi2c.c
Normal file
535
drivers/staging/sm750fb/ddk750_swi2c.c
Normal file
@ -0,0 +1,535 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
|
||||
*
|
||||
* All rights are reserved. Reproduction or in part is prohibited
|
||||
* without the written consent of the copyright owner.
|
||||
*
|
||||
* swi2c.c --- SM750/SM718 DDK
|
||||
* This file contains the source code for I2C using software
|
||||
* implementation.
|
||||
*
|
||||
*******************************************************************/
|
||||
#include "ddk750_help.h"
|
||||
#include "ddk750_reg.h"
|
||||
#include "ddk750_swi2c.h"
|
||||
#include "ddk750_power.h"
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* I2C Software Master Driver:
|
||||
* ===========================
|
||||
* Each i2c cycle is split into 4 sections. Each of these section marks
|
||||
* a point in time where the SCL or SDA may be changed.
|
||||
*
|
||||
* 1 Cycle == | Section I. | Section 2. | Section 3. | Section 4. |
|
||||
* +-------------+-------------+-------------+-------------+
|
||||
* | SCL set LOW |SCL no change| SCL set HIGH|SCL no change|
|
||||
*
|
||||
* ____________ _____________
|
||||
* SCL == XXXX _____________ ____________ /
|
||||
*
|
||||
* I.e. the SCL may only be changed in section 1. and section 3. while
|
||||
* the SDA may only be changed in section 2. and section 4. The table
|
||||
* below gives the changes for these 2 lines in the varios sections.
|
||||
*
|
||||
* Section changes Table:
|
||||
* ======================
|
||||
* blank = no change, L = set bit LOW, H = set bit HIGH
|
||||
*
|
||||
* | 1.| 2.| 3.| 4.|
|
||||
* ---------------+---+---+---+---+
|
||||
* Tx Start SDA | | H | | L |
|
||||
* SCL | L | | H | |
|
||||
* ---------------+---+---+---+---+
|
||||
* Tx Stop SDA | | L | | H |
|
||||
* SCL | L | | H | |
|
||||
* ---------------+---+---+---+---+
|
||||
* Tx bit H SDA | | H | | |
|
||||
* SCL | L | | H | |
|
||||
* ---------------+---+---+---+---+
|
||||
* Tx bit L SDA | | L | | |
|
||||
* SCL | L | | H | |
|
||||
* ---------------+---+---+---+---+
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
/* GPIO pins used for this I2C. It ranges from 0 to 63. */
|
||||
static unsigned char g_i2cClockGPIO = DEFAULT_I2C_SCL;
|
||||
static unsigned char g_i2cDataGPIO = DEFAULT_I2C_SDA;
|
||||
|
||||
/*
|
||||
* Below is the variable declaration for the GPIO pin register usage
|
||||
* for the i2c Clock and i2c Data.
|
||||
*
|
||||
* Note:
|
||||
* Notice that the GPIO usage for the i2c clock and i2c Data are
|
||||
* separated. This is to make this code flexible enough when
|
||||
* two separate GPIO pins for the clock and data are located
|
||||
* in two different GPIO register set (worst case).
|
||||
*/
|
||||
|
||||
/* i2c Clock GPIO Register usage */
|
||||
static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX;
|
||||
static unsigned long g_i2cClkGPIODataReg = GPIO_DATA;
|
||||
static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
|
||||
|
||||
/* i2c Data GPIO Register usage */
|
||||
static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX;
|
||||
static unsigned long g_i2cDataGPIODataReg = GPIO_DATA;
|
||||
static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
|
||||
|
||||
static unsigned char peekIO(unsigned short port,unsigned short index)
|
||||
{
|
||||
#if defined(__i386__) || defined( __x86_64__)
|
||||
outb_p(index,port);
|
||||
return inb_p(port+1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This function puts a delay between command
|
||||
*/
|
||||
static void swI2CWait(void)
|
||||
{
|
||||
/* find a bug:
|
||||
* peekIO method works well before suspend/resume
|
||||
* but after suspend, peekIO(0x3ce,0x61) & 0x10
|
||||
* always be non-zero,which makes the while loop
|
||||
* never finish.
|
||||
* use non-ultimate for loop below is safe
|
||||
* */
|
||||
#if 0
|
||||
/* Change wait algorithm to use PCI bus clock,
|
||||
it's more reliable than counter loop ..
|
||||
write 0x61 to 0x3ce and read from 0x3cf
|
||||
*/
|
||||
while(peekIO(0x3ce,0x61) & 0x10);
|
||||
#else
|
||||
int i, Temp;
|
||||
|
||||
for(i=0; i<600; i++)
|
||||
{
|
||||
Temp = i;
|
||||
Temp += i;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This function set/reset the SCL GPIO pin
|
||||
*
|
||||
* Parameters:
|
||||
* value - Bit value to set to the SCL or SDA (0 = low, 1 = high)
|
||||
*
|
||||
* Notes:
|
||||
* When setting SCL to high, just set the GPIO as input where the pull up
|
||||
* resistor will pull the signal up. Do not use software to pull up the
|
||||
* signal because the i2c will fail when other device try to drive the
|
||||
* signal due to SM50x will drive the signal to always high.
|
||||
*/
|
||||
void swI2CSCL(unsigned char value)
|
||||
{
|
||||
unsigned long ulGPIOData;
|
||||
unsigned long ulGPIODirection;
|
||||
|
||||
ulGPIODirection = PEEK32(g_i2cClkGPIODataDirReg);
|
||||
if (value) /* High */
|
||||
{
|
||||
/* Set direction as input. This will automatically pull the signal up. */
|
||||
ulGPIODirection &= ~(1 << g_i2cClockGPIO);
|
||||
POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
|
||||
}
|
||||
else /* Low */
|
||||
{
|
||||
/* Set the signal down */
|
||||
ulGPIOData = PEEK32(g_i2cClkGPIODataReg);
|
||||
ulGPIOData &= ~(1 << g_i2cClockGPIO);
|
||||
POKE32(g_i2cClkGPIODataReg, ulGPIOData);
|
||||
|
||||
/* Set direction as output */
|
||||
ulGPIODirection |= (1 << g_i2cClockGPIO);
|
||||
POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function set/reset the SDA GPIO pin
|
||||
*
|
||||
* Parameters:
|
||||
* value - Bit value to set to the SCL or SDA (0 = low, 1 = high)
|
||||
*
|
||||
* Notes:
|
||||
* When setting SCL to high, just set the GPIO as input where the pull up
|
||||
* resistor will pull the signal up. Do not use software to pull up the
|
||||
* signal because the i2c will fail when other device try to drive the
|
||||
* signal due to SM50x will drive the signal to always high.
|
||||
*/
|
||||
void swI2CSDA(unsigned char value)
|
||||
{
|
||||
unsigned long ulGPIOData;
|
||||
unsigned long ulGPIODirection;
|
||||
|
||||
ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
|
||||
if (value) /* High */
|
||||
{
|
||||
/* Set direction as input. This will automatically pull the signal up. */
|
||||
ulGPIODirection &= ~(1 << g_i2cDataGPIO);
|
||||
POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
|
||||
}
|
||||
else /* Low */
|
||||
{
|
||||
/* Set the signal down */
|
||||
ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
|
||||
ulGPIOData &= ~(1 << g_i2cDataGPIO);
|
||||
POKE32(g_i2cDataGPIODataReg, ulGPIOData);
|
||||
|
||||
/* Set direction as output */
|
||||
ulGPIODirection |= (1 << g_i2cDataGPIO);
|
||||
POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function read the data from the SDA GPIO pin
|
||||
*
|
||||
* Return Value:
|
||||
* The SDA data bit sent by the Slave
|
||||
*/
|
||||
static unsigned char swI2CReadSDA(void)
|
||||
{
|
||||
unsigned long ulGPIODirection;
|
||||
unsigned long ulGPIOData;
|
||||
|
||||
/* Make sure that the direction is input (High) */
|
||||
ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
|
||||
if ((ulGPIODirection & (1 << g_i2cDataGPIO)) != (~(1 << g_i2cDataGPIO)))
|
||||
{
|
||||
ulGPIODirection &= ~(1 << g_i2cDataGPIO);
|
||||
POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
|
||||
}
|
||||
|
||||
/* Now read the SDA line */
|
||||
ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
|
||||
if (ulGPIOData & (1 << g_i2cDataGPIO))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma optimize( "", off )
|
||||
|
||||
/*
|
||||
* This function sends ACK signal
|
||||
*/
|
||||
static void swI2CAck(void)
|
||||
{
|
||||
return; /* Single byte read is ok without it. */
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sends the start command to the slave device
|
||||
*/
|
||||
void swI2CStart(void)
|
||||
{
|
||||
/* Start I2C */
|
||||
swI2CSDA(1);
|
||||
swI2CSCL(1);
|
||||
swI2CSDA(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sends the stop command to the slave device
|
||||
*/
|
||||
void swI2CStop(void)
|
||||
{
|
||||
/* Stop the I2C */
|
||||
swI2CSCL(1);
|
||||
swI2CSDA(0);
|
||||
swI2CSDA(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function writes one byte to the slave device
|
||||
*
|
||||
* Parameters:
|
||||
* data - Data to be write to the slave device
|
||||
*
|
||||
* Return Value:
|
||||
* 0 - Success
|
||||
* -1 - Fail to write byte
|
||||
*/
|
||||
long swI2CWriteByte(unsigned char data)
|
||||
{
|
||||
unsigned char value = data;
|
||||
int i;
|
||||
|
||||
/* Sending the data bit by bit */
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
/* Set SCL to low */
|
||||
swI2CSCL(0);
|
||||
|
||||
/* Send data bit */
|
||||
if ((value & 0x80) != 0)
|
||||
swI2CSDA(1);
|
||||
else
|
||||
swI2CSDA(0);
|
||||
|
||||
swI2CWait();
|
||||
|
||||
/* Toggle clk line to one */
|
||||
swI2CSCL(1);
|
||||
swI2CWait();
|
||||
|
||||
/* Shift byte to be sent */
|
||||
value = value << 1;
|
||||
}
|
||||
|
||||
/* Set the SCL Low and SDA High (prepare to get input) */
|
||||
swI2CSCL(0);
|
||||
swI2CSDA(1);
|
||||
|
||||
/* Set the SCL High for ack */
|
||||
swI2CWait();
|
||||
swI2CSCL(1);
|
||||
swI2CWait();
|
||||
|
||||
/* Read SDA, until SDA==0 */
|
||||
for(i=0; i<0xff; i++)
|
||||
{
|
||||
if (!swI2CReadSDA())
|
||||
break;
|
||||
|
||||
swI2CSCL(0);
|
||||
swI2CWait();
|
||||
swI2CSCL(1);
|
||||
swI2CWait();
|
||||
}
|
||||
|
||||
/* Set the SCL Low and SDA High */
|
||||
swI2CSCL(0);
|
||||
swI2CSDA(1);
|
||||
|
||||
if (i<0xff)
|
||||
return 0;
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads one byte from the slave device
|
||||
*
|
||||
* Parameters:
|
||||
* ack - Flag to indicate either to send the acknowledge
|
||||
* message to the slave device or not
|
||||
*
|
||||
* Return Value:
|
||||
* One byte data read from the Slave device
|
||||
*/
|
||||
unsigned char swI2CReadByte(unsigned char ack)
|
||||
{
|
||||
int i;
|
||||
unsigned char data = 0;
|
||||
|
||||
for(i=7; i>=0; i--)
|
||||
{
|
||||
/* Set the SCL to Low and SDA to High (Input) */
|
||||
swI2CSCL(0);
|
||||
swI2CSDA(1);
|
||||
swI2CWait();
|
||||
|
||||
/* Set the SCL High */
|
||||
swI2CSCL(1);
|
||||
swI2CWait();
|
||||
|
||||
/* Read data bits from SDA */
|
||||
data |= (swI2CReadSDA() << i);
|
||||
}
|
||||
|
||||
if (ack)
|
||||
swI2CAck();
|
||||
|
||||
/* Set the SCL Low and SDA High */
|
||||
swI2CSCL(0);
|
||||
swI2CSDA(1);
|
||||
|
||||
return data;
|
||||
}
|
||||
#pragma optimize( "", on )
|
||||
|
||||
/*
|
||||
* This function initializes GPIO port for SW I2C communication.
|
||||
*
|
||||
* Parameters:
|
||||
* i2cClkGPIO - The GPIO pin to be used as i2c SCL
|
||||
* i2cDataGPIO - The GPIO pin to be used as i2c SDA
|
||||
*
|
||||
* Return Value:
|
||||
* -1 - Fail to initialize the i2c
|
||||
* 0 - Success
|
||||
*/
|
||||
long swI2CInit_SM750LE(
|
||||
unsigned char i2cClkGPIO,
|
||||
unsigned char i2cDataGPIO
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize the GPIO pin for the i2c Clock Register */
|
||||
g_i2cClkGPIODataReg = GPIO_DATA_SM750LE;
|
||||
g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
|
||||
|
||||
/* Initialize the Clock GPIO Offset */
|
||||
g_i2cClockGPIO = i2cClkGPIO;
|
||||
|
||||
/* Initialize the GPIO pin for the i2c Data Register */
|
||||
g_i2cDataGPIODataReg = GPIO_DATA_SM750LE;
|
||||
g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
|
||||
|
||||
/* Initialize the Data GPIO Offset */
|
||||
g_i2cDataGPIO = i2cDataGPIO;
|
||||
|
||||
/* Note that SM750LE don't have GPIO MUX and power is always on */
|
||||
|
||||
/* Clear the i2c lines. */
|
||||
for(i=0; i<9; i++)
|
||||
swI2CStop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the i2c attributes and bus
|
||||
*
|
||||
* Parameters:
|
||||
* i2cClkGPIO - The GPIO pin to be used as i2c SCL
|
||||
* i2cDataGPIO - The GPIO pin to be used as i2c SDA
|
||||
*
|
||||
* Return Value:
|
||||
* -1 - Fail to initialize the i2c
|
||||
* 0 - Success
|
||||
*/
|
||||
long swI2CInit(
|
||||
unsigned char i2cClkGPIO,
|
||||
unsigned char i2cDataGPIO
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
|
||||
if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
|
||||
return (-1);
|
||||
|
||||
if (getChipType() == SM750LE)
|
||||
return( swI2CInit_SM750LE(i2cClkGPIO, i2cDataGPIO) );
|
||||
|
||||
/* Initialize the GPIO pin for the i2c Clock Register */
|
||||
g_i2cClkGPIOMuxReg = GPIO_MUX;
|
||||
g_i2cClkGPIODataReg = GPIO_DATA;
|
||||
g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
|
||||
|
||||
/* Initialize the Clock GPIO Offset */
|
||||
g_i2cClockGPIO = i2cClkGPIO;
|
||||
|
||||
/* Initialize the GPIO pin for the i2c Data Register */
|
||||
g_i2cDataGPIOMuxReg = GPIO_MUX;
|
||||
g_i2cDataGPIODataReg = GPIO_DATA;
|
||||
g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
|
||||
|
||||
/* Initialize the Data GPIO Offset */
|
||||
g_i2cDataGPIO = i2cDataGPIO;
|
||||
|
||||
/* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
|
||||
POKE32(g_i2cClkGPIOMuxReg,
|
||||
PEEK32(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO));
|
||||
POKE32(g_i2cDataGPIOMuxReg,
|
||||
PEEK32(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO));
|
||||
|
||||
/* Enable GPIO power */
|
||||
enableGPIO(1);
|
||||
|
||||
/* Clear the i2c lines. */
|
||||
for(i=0; i<9; i++)
|
||||
swI2CStop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads the slave device's register
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address which register
|
||||
* to be read from
|
||||
* registerIndex - Slave device's register to be read
|
||||
*
|
||||
* Return Value:
|
||||
* Register value
|
||||
*/
|
||||
unsigned char swI2CReadReg(
|
||||
unsigned char deviceAddress,
|
||||
unsigned char registerIndex
|
||||
)
|
||||
{
|
||||
unsigned char data;
|
||||
|
||||
/* Send the Start signal */
|
||||
swI2CStart();
|
||||
|
||||
/* Send the device address */
|
||||
swI2CWriteByte(deviceAddress);
|
||||
|
||||
/* Send the register index */
|
||||
swI2CWriteByte(registerIndex);
|
||||
|
||||
/* Get the bus again and get the data from the device read address */
|
||||
swI2CStart();
|
||||
swI2CWriteByte(deviceAddress + 1);
|
||||
data = swI2CReadByte(1);
|
||||
|
||||
/* Stop swI2C and release the bus */
|
||||
swI2CStop();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function writes a value to the slave device's register
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address which register
|
||||
* to be written
|
||||
* registerIndex - Slave device's register to be written
|
||||
* data - Data to be written to the register
|
||||
*
|
||||
* Result:
|
||||
* 0 - Success
|
||||
* -1 - Fail
|
||||
*/
|
||||
long swI2CWriteReg(
|
||||
unsigned char deviceAddress,
|
||||
unsigned char registerIndex,
|
||||
unsigned char data
|
||||
)
|
||||
{
|
||||
long returnValue = 0;
|
||||
|
||||
/* Send the Start signal */
|
||||
swI2CStart();
|
||||
|
||||
/* Send the device address and read the data. All should return success
|
||||
in order for the writing processed to be successful
|
||||
*/
|
||||
if ((swI2CWriteByte(deviceAddress) != 0) ||
|
||||
(swI2CWriteByte(registerIndex) != 0) ||
|
||||
(swI2CWriteByte(data) != 0))
|
||||
{
|
||||
returnValue = -1;
|
||||
}
|
||||
|
||||
/* Stop i2c and release the bus */
|
||||
swI2CStop();
|
||||
|
||||
return returnValue;
|
||||
}
|
92
drivers/staging/sm750fb/ddk750_swi2c.h
Normal file
92
drivers/staging/sm750fb/ddk750_swi2c.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
|
||||
*
|
||||
* All rights are reserved. Reproduction or in part is prohibited
|
||||
* without the written consent of the copyright owner.
|
||||
*
|
||||
* swi2c.h --- SM750/SM718 DDK
|
||||
* This file contains the definitions for i2c using software
|
||||
* implementation.
|
||||
*
|
||||
*******************************************************************/
|
||||
#ifndef _SWI2C_H_
|
||||
#define _SWI2C_H_
|
||||
|
||||
/* Default i2c CLK and Data GPIO. These are the default i2c pins */
|
||||
#define DEFAULT_I2C_SCL 30
|
||||
#define DEFAULT_I2C_SDA 31
|
||||
|
||||
/*
|
||||
* This function initializes the i2c attributes and bus
|
||||
*
|
||||
* Parameters:
|
||||
* i2cClkGPIO - The GPIO pin to be used as i2c SCL
|
||||
* i2cDataGPIO - The GPIO pin to be used as i2c SDA
|
||||
*
|
||||
* Return Value:
|
||||
* -1 - Fail to initialize the i2c
|
||||
* 0 - Success
|
||||
*/
|
||||
long swI2CInit(
|
||||
unsigned char i2cClkGPIO,
|
||||
unsigned char i2cDataGPIO
|
||||
);
|
||||
|
||||
/*
|
||||
* This function reads the slave device's register
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address which register
|
||||
* to be read from
|
||||
* registerIndex - Slave device's register to be read
|
||||
*
|
||||
* Return Value:
|
||||
* Register value
|
||||
*/
|
||||
unsigned char swI2CReadReg(
|
||||
unsigned char deviceAddress,
|
||||
unsigned char registerIndex
|
||||
);
|
||||
|
||||
/*
|
||||
* This function writes a value to the slave device's register
|
||||
*
|
||||
* Parameters:
|
||||
* deviceAddress - i2c Slave device address which register
|
||||
* to be written
|
||||
* registerIndex - Slave device's register to be written
|
||||
* data - Data to be written to the register
|
||||
*
|
||||
* Result:
|
||||
* 0 - Success
|
||||
* -1 - Fail
|
||||
*/
|
||||
long swI2CWriteReg(
|
||||
unsigned char deviceAddress,
|
||||
unsigned char registerIndex,
|
||||
unsigned char data
|
||||
);
|
||||
|
||||
/*
|
||||
* These two functions are used to toggle the data on the SCL and SDA I2C lines.
|
||||
* The used of these two functions are not recommended unless it is necessary.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function set/reset the SCL GPIO pin
|
||||
*
|
||||
* Parameters:
|
||||
* value - Bit value to set to the SCL or SDA (0 = low, 1 = high)
|
||||
*/
|
||||
void swI2CSCL(unsigned char value);
|
||||
|
||||
/*
|
||||
* This function set/reset the SDA GPIO pin
|
||||
*
|
||||
* Parameters:
|
||||
* value - Bit value to set to the SCL or SDA (0 = low, 1 = high)
|
||||
*/
|
||||
void swI2CSDA(unsigned char value);
|
||||
|
||||
#endif /* _SWI2C_H_ */
|
221
drivers/staging/sm750fb/modedb.h
Normal file
221
drivers/staging/sm750fb/modedb.h
Normal file
@ -0,0 +1,221 @@
|
||||
|
||||
static const struct fb_videomode modedb2[] = {
|
||||
{
|
||||
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
|
||||
NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 640x480 @ 60 Hz, 31.5 kHz hsync */
|
||||
NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 800x600 @ 56 Hz, 35.15 kHz hsync */
|
||||
NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */
|
||||
NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8,
|
||||
0, FB_VMODE_INTERLACED
|
||||
}, {
|
||||
/* 640x400 @ 85 Hz, 37.86 kHz hsync */
|
||||
NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
|
||||
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 640x480 @ 72 Hz, 36.5 kHz hsync */
|
||||
NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 640x480 @ 75 Hz, 37.50 kHz hsync */
|
||||
NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 800x600 @ 60 Hz, 37.8 kHz hsync */
|
||||
NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 640x480 @ 85 Hz, 43.27 kHz hsync */
|
||||
NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
|
||||
NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10,
|
||||
0, FB_VMODE_INTERLACED
|
||||
}, {
|
||||
/* 800x600 @ 72 Hz, 48.0 kHz hsync */
|
||||
NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1024x768 @ 60 Hz, 48.4 kHz hsync */
|
||||
NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 640x480 @ 100 Hz, 53.01 kHz hsync */
|
||||
NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1152x864 @ 60 Hz, 53.5 kHz hsync */
|
||||
NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 800x600 @ 85 Hz, 55.84 kHz hsync */
|
||||
NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1024x768 @ 70 Hz, 56.5 kHz hsync */
|
||||
NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1280x960-60 VESA */
|
||||
NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA
|
||||
}, {
|
||||
/* 1280x1024-60 VESA */
|
||||
NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA
|
||||
}, {
|
||||
/* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
|
||||
NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12,
|
||||
0, FB_VMODE_INTERLACED
|
||||
}, {
|
||||
/* 800x600 @ 100 Hz, 64.02 kHz hsync */
|
||||
NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1024x768 @ 76 Hz, 62.5 kHz hsync */
|
||||
NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1152x864 @ 70 Hz, 62.4 kHz hsync */
|
||||
NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1280x1024 @ 61 Hz, 64.2 kHz hsync */
|
||||
NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1400x1050 @ 60Hz, 63.9 kHz hsync */
|
||||
NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/
|
||||
NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/
|
||||
NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1024x768 @ 85 Hz, 70.24 kHz hsync */
|
||||
NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1152x864 @ 78 Hz, 70.8 kHz hsync */
|
||||
NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1280x1024 @ 70 Hz, 74.59 kHz hsync */
|
||||
NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1600x1200 @ 60Hz, 75.00 kHz hsync */
|
||||
NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1152x864 @ 84 Hz, 76.0 kHz hsync */
|
||||
NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1280x1024 @ 74 Hz, 78.85 kHz hsync */
|
||||
NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1024x768 @ 100Hz, 80.21 kHz hsync */
|
||||
NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1280x1024 @ 76 Hz, 81.13 kHz hsync */
|
||||
NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1600x1200 @ 70 Hz, 87.50 kHz hsync */
|
||||
NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1152x864 @ 100 Hz, 89.62 kHz hsync */
|
||||
NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1280x1024 @ 85 Hz, 91.15 kHz hsync */
|
||||
NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1600x1200 @ 75 Hz, 93.75 kHz hsync */
|
||||
NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1600x1200 @ 85 Hz, 105.77 kHz hsync */
|
||||
NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1280x1024 @ 100 Hz, 107.16 kHz hsync */
|
||||
NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1800x1440 @ 64Hz, 96.15 kHz hsync */
|
||||
NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 1800x1440 @ 70Hz, 104.52 kHz hsync */
|
||||
NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3,
|
||||
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 512x384 @ 78 Hz, 31.50 kHz hsync */
|
||||
NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 512x384 @ 85 Hz, 34.38 kHz hsync */
|
||||
NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */
|
||||
NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */
|
||||
NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 320x240 @ 72 Hz, 36.5 kHz hsync */
|
||||
NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */
|
||||
NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 400x300 @ 60 Hz, 37.8 kHz hsync */
|
||||
NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 400x300 @ 72 Hz, 48.0 kHz hsync */
|
||||
NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */
|
||||
NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 480x300 @ 60 Hz, 37.8 kHz hsync */
|
||||
NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 480x300 @ 63 Hz, 39.6 kHz hsync */
|
||||
NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2,
|
||||
0, FB_VMODE_DOUBLE
|
||||
}, {
|
||||
/* 480x300 @ 72 Hz, 48.0 kHz hsync */
|
||||
NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3,
|
||||
0, FB_VMODE_DOUBLE
|
||||
},
|
||||
};
|
||||
static const int nmodedb2 = sizeof(modedb2);
|
38
drivers/staging/sm750fb/readme
Normal file
38
drivers/staging/sm750fb/readme
Normal file
@ -0,0 +1,38 @@
|
||||
Introduction:
|
||||
SM750 of Silicon MOtion is pci express display controller device.
|
||||
The SM750 embedded graphics features include:
|
||||
- dual display
|
||||
- 2D acceleration
|
||||
- 16MB integrated video memory
|
||||
|
||||
About the kernel module paramter of driver:
|
||||
|
||||
Use 1280,8bpp index color and 60 hz mode:
|
||||
insmod ./sm750fb.ko g_option="1280x1024-8@60"
|
||||
|
||||
Disable MTRR,Disable 2d acceleration,Disable hardware cursor,
|
||||
and use a 800x600 mode :
|
||||
insmod ./sm750fb.ko g_option="noaccel:nomtrr:nohwc:800x600"
|
||||
|
||||
dual frame buffer for driver with "dual" parameter
|
||||
insmod ./sm750fb.ko g_option="dual,800x600:1024x768"
|
||||
it will create fb0 and fb1 (or fb1,fb2 if fb0 already exist) under /dev
|
||||
and user can use con2fb to link fbX and ttyX
|
||||
|
||||
Notes:
|
||||
1) if you build the driver with built-in method, the paramter
|
||||
you edited in the grub config file will be also the
|
||||
same format as above modular method,but additionaly add
|
||||
"video=sm750fb:"
|
||||
ahead of parameters,so,it looks like:
|
||||
video=sm750fb:noaccel,1280x1024@60,otherparam,etc...
|
||||
it equal to modular method with below command:
|
||||
insmod ./sm750fb.ko g_option="noaccel:1280x1024@60:otherparm:etc..."
|
||||
|
||||
2) if you put 800x600 into the paramter without bpp and
|
||||
refresh rate, kernel driver will defaulty use 16bpp and 60hz
|
||||
|
||||
Important:
|
||||
if you have vesafb enabled in your config then /dev/fb0 will be created by vesafb
|
||||
and this driver will use fb1, fb2. In that case, you need to configure your X-server
|
||||
to use fb1. Another simple althernative is to disable vesafb from your config.
|
1451
drivers/staging/sm750fb/sm750.c
Normal file
1451
drivers/staging/sm750fb/sm750.c
Normal file
File diff suppressed because it is too large
Load Diff
185
drivers/staging/sm750fb/sm750.h
Normal file
185
drivers/staging/sm750fb/sm750.h
Normal file
@ -0,0 +1,185 @@
|
||||
#ifndef LYNXDRV_H_
|
||||
#define LYNXDRV_H_
|
||||
|
||||
|
||||
|
||||
#define FB_ACCEL_SMI 0xab
|
||||
/* please use revision id to distinguish sm750le and sm750*/
|
||||
#define SPC_SM750 0
|
||||
|
||||
//#define SPC_SM750LE 8
|
||||
|
||||
#define MB(x) ((x)<<20)
|
||||
#define MHZ(x) ((x) * 1000000)
|
||||
/* align should be 2,4,8,16 */
|
||||
#define PADDING(align,data) (((data)+(align)-1)&(~((align) -1)))
|
||||
extern int smi_indent;
|
||||
|
||||
|
||||
struct lynx_accel{
|
||||
/* base virtual address of DPR registers */
|
||||
volatile unsigned char __iomem * dprBase;
|
||||
/* base virtual address of de data port */
|
||||
volatile unsigned char __iomem * dpPortBase;
|
||||
|
||||
/* function fointers */
|
||||
int (*de_init)(struct lynx_accel *);
|
||||
|
||||
int (*de_wait)(void);/* see if hardware ready to work */
|
||||
|
||||
int (*de_fillrect)(struct lynx_accel *,u32,u32,u32,
|
||||
u32,u32,u32,u32,u32,u32);
|
||||
|
||||
int (*de_copyarea)(struct lynx_accel *,u32,u32,u32,u32,
|
||||
u32,u32,u32,u32,
|
||||
u32,u32,u32,u32);
|
||||
|
||||
int (*de_imageblit)(struct lynx_accel *,const char *,u32,u32,u32,
|
||||
u32,u32,u32,u32,u32,u32,u32,u32,u32);
|
||||
|
||||
};
|
||||
|
||||
/* lynx_share stands for a presentation of two frame buffer
|
||||
that use one smi adaptor , it is similar to a basic class of C++
|
||||
*/
|
||||
struct lynx_share{
|
||||
/* common members */
|
||||
u16 devid;
|
||||
u8 revid;
|
||||
struct pci_dev * pdev;
|
||||
struct fb_info * fbinfo[2];
|
||||
struct lynx_accel accel;
|
||||
int accel_off;
|
||||
int dual;
|
||||
#ifdef CONFIG_MTRR
|
||||
int mtrr_off;
|
||||
struct{
|
||||
int vram;
|
||||
int vram_added;
|
||||
}mtrr;
|
||||
#endif
|
||||
/* all smi graphic adaptor got below attributes */
|
||||
resource_size_t vidmem_start;
|
||||
resource_size_t vidreg_start;
|
||||
resource_size_t vidmem_size;
|
||||
resource_size_t vidreg_size;
|
||||
volatile unsigned char __iomem * pvReg;
|
||||
unsigned char __iomem * pvMem;
|
||||
/* locks*/
|
||||
spinlock_t slock;
|
||||
/* function pointers */
|
||||
void (*suspend)(struct lynx_share*);
|
||||
void (*resume)(struct lynx_share*);
|
||||
};
|
||||
|
||||
struct lynx_cursor{
|
||||
/* cursor width ,height and size */
|
||||
int w;
|
||||
int h;
|
||||
int size;
|
||||
/* hardware limitation */
|
||||
int maxW;
|
||||
int maxH;
|
||||
/* base virtual address and offset of cursor image */
|
||||
char __iomem * vstart;
|
||||
int offset;
|
||||
/* mmio addr of hw cursor */
|
||||
volatile char __iomem * mmio;
|
||||
/* the lynx_share of this adaptor */
|
||||
struct lynx_share * share;
|
||||
/* proc_routines */
|
||||
void (*enable)(struct lynx_cursor *);
|
||||
void (*disable)(struct lynx_cursor *);
|
||||
void (*setSize)(struct lynx_cursor *,int,int);
|
||||
void (*setPos)(struct lynx_cursor *,int,int);
|
||||
void (*setColor)(struct lynx_cursor *,u32,u32);
|
||||
void (*setData)(struct lynx_cursor *,u16,const u8*,const u8*);
|
||||
};
|
||||
|
||||
struct lynxfb_crtc{
|
||||
unsigned char __iomem * vCursor;//virtual address of cursor
|
||||
unsigned char __iomem * vScreen;//virtual address of on_screen
|
||||
int oCursor;//cursor address offset in vidmem
|
||||
int oScreen;//onscreen address offset in vidmem
|
||||
int channel;/* which channel this crtc stands for*/
|
||||
resource_size_t vidmem_size;/* this view's video memory max size */
|
||||
|
||||
/* below attributes belong to info->fix, their value depends on specific adaptor*/
|
||||
u16 line_pad;/* padding information:0,1,2,4,8,16,... */
|
||||
u16 xpanstep;
|
||||
u16 ypanstep;
|
||||
u16 ywrapstep;
|
||||
|
||||
void * priv;
|
||||
|
||||
int(*proc_setMode)(struct lynxfb_crtc*,
|
||||
struct fb_var_screeninfo*,
|
||||
struct fb_fix_screeninfo*);
|
||||
|
||||
int(*proc_checkMode)(struct lynxfb_crtc*,struct fb_var_screeninfo*);
|
||||
int(*proc_setColReg)(struct lynxfb_crtc*,ushort,ushort,ushort,ushort);
|
||||
void (*clear)(struct lynxfb_crtc*);
|
||||
/* pan display */
|
||||
int(*proc_panDisplay)(struct lynxfb_crtc*, struct fb_var_screeninfo*,
|
||||
struct fb_info*);
|
||||
/* cursor information */
|
||||
struct lynx_cursor cursor;
|
||||
};
|
||||
|
||||
struct lynxfb_output{
|
||||
int dpms;
|
||||
int paths;
|
||||
/* which paths(s) this output stands for,for sm750:
|
||||
paths=1:means output for panel paths
|
||||
paths=2:means output for crt paths
|
||||
paths=3:means output for both panel and crt paths
|
||||
*/
|
||||
|
||||
int * channel;
|
||||
/* which channel these outputs linked with,for sm750:
|
||||
*channel=0 means primary channel
|
||||
*channel=1 means secondary channel
|
||||
output->channel ==> &crtc->channel
|
||||
*/
|
||||
void * priv;
|
||||
|
||||
int(*proc_setMode)(struct lynxfb_output*,
|
||||
struct fb_var_screeninfo*,
|
||||
struct fb_fix_screeninfo*);
|
||||
|
||||
int(*proc_checkMode)(struct lynxfb_output*,struct fb_var_screeninfo*);
|
||||
int(*proc_setBLANK)(struct lynxfb_output*,int);
|
||||
void (*clear)(struct lynxfb_output*);
|
||||
};
|
||||
|
||||
struct lynxfb_par{
|
||||
/* either 0 or 1 for dual head adaptor,0 is the older one registered */
|
||||
int index;
|
||||
unsigned int pseudo_palette[256];
|
||||
struct lynxfb_crtc crtc;
|
||||
struct lynxfb_output output;
|
||||
struct fb_info * info;
|
||||
struct lynx_share * share;
|
||||
};
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
|
||||
#define PS_TO_HZ(ps) \
|
||||
({ \
|
||||
unsigned long long hz = 1000*1000*1000*1000ULL; \
|
||||
do_div(hz,ps); \
|
||||
(unsigned long)hz;})
|
||||
|
||||
static inline unsigned long ps_to_hz(unsigned int psvalue)
|
||||
{
|
||||
unsigned long long numerator=1000*1000*1000*1000ULL;
|
||||
/* 10^12 / picosecond period gives frequency in Hz */
|
||||
do_div(numerator, psvalue);
|
||||
return (unsigned long)numerator;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
516
drivers/staging/sm750fb/sm750_accel.c
Normal file
516
drivers/staging/sm750fb/sm750_accel.c
Normal file
@ -0,0 +1,516 @@
|
||||
#include<linux/module.h>
|
||||
#include<linux/kernel.h>
|
||||
#include<linux/errno.h>
|
||||
#include<linux/string.h>
|
||||
#include<linux/mm.h>
|
||||
#include<linux/slab.h>
|
||||
#include<linux/delay.h>
|
||||
#include<linux/fb.h>
|
||||
#include<linux/ioport.h>
|
||||
#include<linux/init.h>
|
||||
#include<linux/pci.h>
|
||||
#include<linux/vmalloc.h>
|
||||
#include<linux/pagemap.h>
|
||||
#include <linux/console.h>
|
||||
#include<linux/platform_device.h>
|
||||
#include<linux/screen_info.h>
|
||||
|
||||
#include "sm750.h"
|
||||
#include "sm750_accel.h"
|
||||
#include "sm750_help.h"
|
||||
static inline void write_dpr(struct lynx_accel * accel,int offset,u32 regValue)
|
||||
{
|
||||
writel(regValue,accel->dprBase + offset);
|
||||
}
|
||||
|
||||
static inline u32 read_dpr(struct lynx_accel * accel,int offset)
|
||||
{
|
||||
return readl(accel->dprBase + offset);
|
||||
}
|
||||
|
||||
static inline void write_dpPort(struct lynx_accel * accel,u32 data)
|
||||
{
|
||||
writel(data,accel->dpPortBase);
|
||||
}
|
||||
|
||||
void hw_de_init(struct lynx_accel * accel)
|
||||
{
|
||||
/* setup 2d engine registers */
|
||||
u32 reg,clr;
|
||||
|
||||
write_dpr(accel,DE_MASKS,0xFFFFFFFF);
|
||||
|
||||
/* dpr1c */
|
||||
reg = FIELD_SET(0,DE_STRETCH_FORMAT,PATTERN_XY,NORMAL)|
|
||||
FIELD_VALUE(0,DE_STRETCH_FORMAT,PATTERN_Y,0)|
|
||||
FIELD_VALUE(0,DE_STRETCH_FORMAT,PATTERN_X,0)|
|
||||
FIELD_SET(0,DE_STRETCH_FORMAT,ADDRESSING,XY)|
|
||||
FIELD_VALUE(0,DE_STRETCH_FORMAT,SOURCE_HEIGHT,3);
|
||||
|
||||
clr = FIELD_CLEAR(DE_STRETCH_FORMAT,PATTERN_XY)&
|
||||
FIELD_CLEAR(DE_STRETCH_FORMAT,PATTERN_Y)&
|
||||
FIELD_CLEAR(DE_STRETCH_FORMAT,PATTERN_X)&
|
||||
FIELD_CLEAR(DE_STRETCH_FORMAT,ADDRESSING)&
|
||||
FIELD_CLEAR(DE_STRETCH_FORMAT,SOURCE_HEIGHT);
|
||||
|
||||
/* DE_STRETCH bpp format need be initilized in setMode routine */
|
||||
write_dpr(accel,DE_STRETCH_FORMAT,(read_dpr(accel,DE_STRETCH_FORMAT) & clr) | reg);
|
||||
|
||||
/* disable clipping and transparent */
|
||||
write_dpr(accel,DE_CLIP_TL,0);//dpr2c
|
||||
write_dpr(accel,DE_CLIP_BR,0);//dpr30
|
||||
|
||||
write_dpr(accel,DE_COLOR_COMPARE_MASK,0);//dpr24
|
||||
write_dpr(accel,DE_COLOR_COMPARE,0);
|
||||
|
||||
reg = FIELD_SET(0,DE_CONTROL,TRANSPARENCY,DISABLE)|
|
||||
FIELD_SET(0,DE_CONTROL,TRANSPARENCY_MATCH,OPAQUE)|
|
||||
FIELD_SET(0,DE_CONTROL,TRANSPARENCY_SELECT,SOURCE);
|
||||
|
||||
clr = FIELD_CLEAR(DE_CONTROL,TRANSPARENCY)&
|
||||
FIELD_CLEAR(DE_CONTROL,TRANSPARENCY_MATCH)&
|
||||
FIELD_CLEAR(DE_CONTROL,TRANSPARENCY_SELECT);
|
||||
|
||||
/* dpr0c */
|
||||
write_dpr(accel,DE_CONTROL,(read_dpr(accel,DE_CONTROL)&clr)|reg);
|
||||
}
|
||||
|
||||
/* set2dformat only be called from setmode functions
|
||||
* but if you need dual framebuffer driver,need call set2dformat
|
||||
* every time you use 2d function */
|
||||
|
||||
void hw_set2dformat(struct lynx_accel * accel,int fmt)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */
|
||||
reg = read_dpr(accel,DE_STRETCH_FORMAT);
|
||||
reg = FIELD_VALUE(reg,DE_STRETCH_FORMAT,PIXEL_FORMAT,fmt);
|
||||
write_dpr(accel,DE_STRETCH_FORMAT,reg);
|
||||
}
|
||||
|
||||
/* seems sm712 RectFill command is broken,so need use BitBlt to
|
||||
* replace it. */
|
||||
|
||||
int hw712_fillrect(struct lynx_accel * accel,
|
||||
u32 base,u32 pitch,u32 Bpp,
|
||||
u32 x,u32 y,u32 width,u32 height,
|
||||
u32 color,u32 rop)
|
||||
{
|
||||
u32 deCtrl;
|
||||
if(accel->de_wait() != 0)
|
||||
{
|
||||
/* int time wait and always busy,seems hardware
|
||||
* got something error */
|
||||
pr_debug("%s:De engine always bussy\n",__func__);
|
||||
return -1;
|
||||
}
|
||||
/* 24bpp 2d acceleration still not work,we already support 2d on
|
||||
* both 8/16/32 bpp now, so there is no harm if we disable 2d on
|
||||
* 24bpp for current stage. */
|
||||
#if 0
|
||||
if(Bpp == 3){
|
||||
width *= 3;
|
||||
x *= 3;
|
||||
write_dpr(accel,DE_PITCH,
|
||||
FIELD_VALUE(0,DE_PITCH,DESTINATION,pitch)|
|
||||
FIELD_VALUE(0,DE_PITCH,SOURCE,pitch));//dpr10
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
write_dpr(accel,DE_PITCH,
|
||||
FIELD_VALUE(0,DE_PITCH,DESTINATION,pitch/Bpp)|
|
||||
FIELD_VALUE(0,DE_PITCH,SOURCE,pitch/Bpp));//dpr10
|
||||
|
||||
}
|
||||
|
||||
write_dpr(accel,DE_FOREGROUND,color);//DPR14
|
||||
write_dpr(accel,DE_MONO_PATTERN_HIGH,~0);//DPR34
|
||||
write_dpr(accel,DE_MONO_PATTERN_LOW,~0);//DPR38
|
||||
|
||||
write_dpr(accel,DE_WINDOW_SOURCE_BASE,base);//dpr44
|
||||
write_dpr(accel,DE_WINDOW_DESTINATION_BASE,base);//dpr40
|
||||
|
||||
|
||||
write_dpr(accel,DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0,DE_WINDOW_WIDTH,DESTINATION,pitch/Bpp)|
|
||||
FIELD_VALUE(0,DE_WINDOW_WIDTH,SOURCE,pitch/Bpp));//dpr3c
|
||||
|
||||
|
||||
write_dpr(accel,DE_DESTINATION,
|
||||
FIELD_SET(0,DE_DESTINATION,WRAP,DISABLE)|
|
||||
FIELD_VALUE(0,DE_DESTINATION,X,x)|
|
||||
FIELD_VALUE(0,DE_DESTINATION,Y,y));//dpr4
|
||||
|
||||
write_dpr(accel,DE_DIMENSION,
|
||||
FIELD_VALUE(0,DE_DIMENSION,X,width)|
|
||||
FIELD_VALUE(0,DE_DIMENSION,Y_ET,height));//dpr8
|
||||
|
||||
deCtrl =
|
||||
FIELD_SET(0,DE_CONTROL,STATUS,START)|
|
||||
FIELD_SET(0,DE_CONTROL,COMMAND,BITBLT)|
|
||||
FIELD_SET(0,DE_CONTROL,ROP2_SOURCE,PATTERN)|
|
||||
FIELD_SET(0,DE_CONTROL,ROP_SELECT,ROP2)|
|
||||
FIELD_VALUE(0,DE_CONTROL,ROP,rop);//dpr0xc
|
||||
#if 0
|
||||
/* dump registers */
|
||||
int i;
|
||||
inf_msg("x,y,w,h = %d,%d,%d,%d\n",x,y,width,height);
|
||||
for(i=0x04;i<=0x44;i+=4){
|
||||
inf_msg("dpr%02x = %08x\n",i,read_dpr(accel,i));
|
||||
}
|
||||
inf_msg("deCtrl = %08x\n",deCtrl);
|
||||
#endif
|
||||
|
||||
write_dpr(accel,DE_CONTROL,deCtrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_fillrect(struct lynx_accel * accel,
|
||||
u32 base,u32 pitch,u32 Bpp,
|
||||
u32 x,u32 y,u32 width,u32 height,
|
||||
u32 color,u32 rop)
|
||||
{
|
||||
u32 deCtrl;
|
||||
|
||||
if(accel->de_wait() != 0)
|
||||
{
|
||||
/* int time wait and always busy,seems hardware
|
||||
* got something error */
|
||||
pr_debug("%s:De engine always bussy\n",__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_dpr(accel,DE_WINDOW_DESTINATION_BASE,base);//dpr40
|
||||
write_dpr(accel,DE_PITCH,
|
||||
FIELD_VALUE(0,DE_PITCH,DESTINATION,pitch/Bpp)|
|
||||
FIELD_VALUE(0,DE_PITCH,SOURCE,pitch/Bpp));//dpr10
|
||||
|
||||
write_dpr(accel,DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0,DE_WINDOW_WIDTH,DESTINATION,pitch/Bpp)|
|
||||
FIELD_VALUE(0,DE_WINDOW_WIDTH,SOURCE,pitch/Bpp));//dpr44
|
||||
|
||||
write_dpr(accel,DE_FOREGROUND,color);//DPR14
|
||||
|
||||
write_dpr(accel,DE_DESTINATION,
|
||||
FIELD_SET(0,DE_DESTINATION,WRAP,DISABLE)|
|
||||
FIELD_VALUE(0,DE_DESTINATION,X,x)|
|
||||
FIELD_VALUE(0,DE_DESTINATION,Y,y));//dpr4
|
||||
|
||||
write_dpr(accel,DE_DIMENSION,
|
||||
FIELD_VALUE(0,DE_DIMENSION,X,width)|
|
||||
FIELD_VALUE(0,DE_DIMENSION,Y_ET,height));//dpr8
|
||||
|
||||
deCtrl =
|
||||
FIELD_SET(0,DE_CONTROL,STATUS,START)|
|
||||
FIELD_SET(0,DE_CONTROL,DIRECTION,LEFT_TO_RIGHT)|
|
||||
FIELD_SET(0,DE_CONTROL,LAST_PIXEL,ON)|
|
||||
FIELD_SET(0,DE_CONTROL,COMMAND,RECTANGLE_FILL)|
|
||||
FIELD_SET(0,DE_CONTROL,ROP_SELECT,ROP2)|
|
||||
FIELD_VALUE(0,DE_CONTROL,ROP,rop);//dpr0xc
|
||||
|
||||
write_dpr(accel,DE_CONTROL,deCtrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_copyarea(
|
||||
struct lynx_accel * accel,
|
||||
unsigned int sBase, /* Address of source: offset in frame buffer */
|
||||
unsigned int sPitch, /* Pitch value of source surface in BYTE */
|
||||
unsigned int sx,
|
||||
unsigned int sy, /* Starting coordinate of source surface */
|
||||
unsigned int dBase, /* Address of destination: offset in frame buffer */
|
||||
unsigned int dPitch, /* Pitch value of destination surface in BYTE */
|
||||
unsigned int Bpp, /* Color depth of destination surface */
|
||||
unsigned int dx,
|
||||
unsigned int dy, /* Starting coordinate of destination surface */
|
||||
unsigned int width,
|
||||
unsigned int height, /* width and height of rectangle in pixel value */
|
||||
unsigned int rop2) /* ROP value */
|
||||
{
|
||||
unsigned int nDirection, de_ctrl;
|
||||
int opSign;
|
||||
nDirection = LEFT_TO_RIGHT;
|
||||
/* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
|
||||
opSign = 1;
|
||||
de_ctrl = 0;
|
||||
|
||||
/* If source and destination are the same surface, need to check for overlay cases */
|
||||
if (sBase == dBase && sPitch == dPitch)
|
||||
{
|
||||
/* Determine direction of operation */
|
||||
if (sy < dy)
|
||||
{
|
||||
/* +----------+
|
||||
|S |
|
||||
| +----------+
|
||||
| | | |
|
||||
| | | |
|
||||
+---|------+ |
|
||||
| D|
|
||||
+----------+ */
|
||||
|
||||
nDirection = BOTTOM_TO_TOP;
|
||||
}
|
||||
else if (sy > dy)
|
||||
{
|
||||
/* +----------+
|
||||
|D |
|
||||
| +----------+
|
||||
| | | |
|
||||
| | | |
|
||||
+---|------+ |
|
||||
| S|
|
||||
+----------+ */
|
||||
|
||||
nDirection = TOP_TO_BOTTOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* sy == dy */
|
||||
|
||||
if (sx <= dx)
|
||||
{
|
||||
/* +------+---+------+
|
||||
|S | | D|
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+------+---+------+ */
|
||||
|
||||
nDirection = RIGHT_TO_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* sx > dx */
|
||||
|
||||
/* +------+---+------+
|
||||
|D | | S|
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+------+---+------+ */
|
||||
|
||||
nDirection = LEFT_TO_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT))
|
||||
{
|
||||
sx += width - 1;
|
||||
sy += height - 1;
|
||||
dx += width - 1;
|
||||
dy += height - 1;
|
||||
opSign = (-1);
|
||||
}
|
||||
|
||||
/* Note:
|
||||
DE_FOREGROUND are DE_BACKGROUND are don't care.
|
||||
DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
|
||||
*/
|
||||
|
||||
/* 2D Source Base.
|
||||
It is an address offset (128 bit aligned) from the beginning of frame buffer.
|
||||
*/
|
||||
write_dpr(accel,DE_WINDOW_SOURCE_BASE, sBase);//dpr40
|
||||
|
||||
/* 2D Destination Base.
|
||||
It is an address offset (128 bit aligned) from the beginning of frame buffer.
|
||||
*/
|
||||
write_dpr(accel,DE_WINDOW_DESTINATION_BASE, dBase);//dpr44
|
||||
|
||||
#if 0
|
||||
/* Program pitch (distance between the 1st points of two adjacent lines).
|
||||
Note that input pitch is BYTE value, but the 2D Pitch register uses
|
||||
pixel values. Need Byte to pixel convertion.
|
||||
*/
|
||||
if(Bpp == 3){
|
||||
sx *= 3;
|
||||
dx *= 3;
|
||||
width *= 3;
|
||||
write_dpr(accel,DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) |
|
||||
FIELD_VALUE(0, DE_PITCH, SOURCE, sPitch));//dpr10
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
write_dpr(accel,DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/Bpp)) |
|
||||
FIELD_VALUE(0, DE_PITCH, SOURCE, (sPitch/Bpp)));//dpr10
|
||||
}
|
||||
|
||||
/* Screen Window width in Pixels.
|
||||
2D engine uses this value to calculate the linear address in frame buffer for a given point.
|
||||
*/
|
||||
write_dpr(accel,DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) |
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/Bpp)));//dpr3c
|
||||
|
||||
if (accel->de_wait() != 0){
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
write_dpr(accel,DE_SOURCE,
|
||||
FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_SOURCE, X_K1, sx) |
|
||||
FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));//dpr0
|
||||
write_dpr(accel,DE_DESTINATION,
|
||||
FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, dx) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, dy));//dpr04
|
||||
write_dpr(accel,DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, width) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));//dpr08
|
||||
|
||||
de_ctrl =
|
||||
FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
|
||||
FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
|
||||
FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
|
||||
((nDirection == RIGHT_TO_LEFT) ?
|
||||
FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
|
||||
: FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START);
|
||||
write_dpr(accel,DE_CONTROL,de_ctrl);//dpr0c
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int deGetTransparency(struct lynx_accel * accel)
|
||||
{
|
||||
unsigned int de_ctrl;
|
||||
|
||||
de_ctrl = read_dpr(accel,DE_CONTROL);
|
||||
|
||||
de_ctrl &=
|
||||
FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
|
||||
FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)|
|
||||
FIELD_MASK(DE_CONTROL_TRANSPARENCY);
|
||||
|
||||
return de_ctrl;
|
||||
}
|
||||
|
||||
int hw_imageblit(
|
||||
struct lynx_accel * accel,
|
||||
unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */
|
||||
int srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
|
||||
unsigned int startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
|
||||
unsigned int dBase, /* Address of destination: offset in frame buffer */
|
||||
unsigned int dPitch, /* Pitch value of destination surface in BYTE */
|
||||
unsigned int bytePerPixel, /* Color depth of destination surface */
|
||||
unsigned int dx,
|
||||
unsigned int dy, /* Starting coordinate of destination surface */
|
||||
unsigned int width,
|
||||
unsigned int height, /* width and height of rectange in pixel value */
|
||||
unsigned int fColor, /* Foreground color (corresponding to a 1 in the monochrome data */
|
||||
unsigned int bColor, /* Background color (corresponding to a 0 in the monochrome data */
|
||||
unsigned int rop2) /* ROP value */
|
||||
{
|
||||
unsigned int ulBytesPerScan;
|
||||
unsigned int ul4BytesPerScan;
|
||||
unsigned int ulBytesRemain;
|
||||
unsigned int de_ctrl = 0;
|
||||
unsigned char ajRemain[4];
|
||||
int i, j;
|
||||
|
||||
startBit &= 7; /* Just make sure the start bit is within legal range */
|
||||
ulBytesPerScan = (width + startBit + 7) / 8;
|
||||
ul4BytesPerScan = ulBytesPerScan & ~3;
|
||||
ulBytesRemain = ulBytesPerScan & 3;
|
||||
|
||||
if(accel->de_wait() != 0)
|
||||
{
|
||||
// inf_msg("*** ImageBlit return -1 ***\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 2D Source Base.
|
||||
Use 0 for HOST Blt.
|
||||
*/
|
||||
write_dpr(accel,DE_WINDOW_SOURCE_BASE, 0);
|
||||
|
||||
/* 2D Destination Base.
|
||||
It is an address offset (128 bit aligned) from the beginning of frame buffer.
|
||||
*/
|
||||
write_dpr(accel,DE_WINDOW_DESTINATION_BASE, dBase);
|
||||
#if 0
|
||||
/* Program pitch (distance between the 1st points of two adjacent lines).
|
||||
Note that input pitch is BYTE value, but the 2D Pitch register uses
|
||||
pixel values. Need Byte to pixel convertion.
|
||||
*/
|
||||
if(bytePerPixel == 3 ){
|
||||
dx *= 3;
|
||||
width *= 3;
|
||||
startBit *= 3;
|
||||
write_dpr(accel,DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) |
|
||||
FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch));//dpr10
|
||||
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
write_dpr(accel,DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
|
||||
FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel));//dpr10
|
||||
}
|
||||
|
||||
/* Screen Window width in Pixels.
|
||||
2D engine uses this value to calculate the linear address in frame buffer for a given point.
|
||||
*/
|
||||
write_dpr(accel,DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel)));
|
||||
|
||||
/* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
|
||||
For mono bitmap, use startBit for X_K1. */
|
||||
write_dpr(accel,DE_SOURCE,
|
||||
FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit));//dpr00
|
||||
|
||||
write_dpr(accel,DE_DESTINATION,
|
||||
FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, dx) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, dy));//dpr04
|
||||
|
||||
write_dpr(accel,DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, width) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));//dpr08
|
||||
|
||||
write_dpr(accel,DE_FOREGROUND, fColor);
|
||||
write_dpr(accel,DE_BACKGROUND, bColor);
|
||||
|
||||
de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
|
||||
FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
|
||||
FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
|
||||
FIELD_SET(0, DE_CONTROL, HOST, MONO) |
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START);
|
||||
|
||||
write_dpr(accel,DE_CONTROL, de_ctrl | deGetTransparency(accel));
|
||||
|
||||
/* Write MONO data (line by line) to 2D Engine data port */
|
||||
for (i=0; i<height; i++)
|
||||
{
|
||||
/* For each line, send the data in chunks of 4 bytes */
|
||||
for (j=0; j<(ul4BytesPerScan/4); j++)
|
||||
{
|
||||
write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
|
||||
}
|
||||
|
||||
if (ulBytesRemain)
|
||||
{
|
||||
memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
|
||||
write_dpPort(accel, *(unsigned int *)ajRemain);
|
||||
}
|
||||
|
||||
pSrcbuf += srcDelta;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
276
drivers/staging/sm750fb/sm750_accel.h
Normal file
276
drivers/staging/sm750fb/sm750_accel.h
Normal file
@ -0,0 +1,276 @@
|
||||
#ifndef ACCEL_H__
|
||||
#define ACCEL_H__
|
||||
|
||||
#define HW_ROP2_COPY 0xc
|
||||
#define HW_ROP2_XOR 0x6
|
||||
|
||||
/* notes: below address are the offset value from de_base_address (0x100000)*/
|
||||
|
||||
/* for sm718/750/502 de_base is at mmreg_1mb*/
|
||||
#define DE_BASE_ADDR_TYPE1 0x100000
|
||||
/* for sm712,de_base is at mmreg_32kb */
|
||||
#define DE_BASE_ADDR_TYPE2 0x8000
|
||||
/* for sm722,de_base is at mmreg_0 */
|
||||
#define DE_BASE_ADDR_TYPE3 0
|
||||
|
||||
/* type1 data port address is at mmreg_0x110000*/
|
||||
#define DE_PORT_ADDR_TYPE1 0x110000
|
||||
/* for sm712,data port address is at mmreg_0 */
|
||||
#define DE_PORT_ADDR_TYPE2 0x100000
|
||||
/* for sm722,data port address is at mmreg_1mb */
|
||||
#define DE_PORT_ADDR_TYPE3 0x100000
|
||||
|
||||
#define DE_SOURCE 0x0
|
||||
#define DE_SOURCE_WRAP 31:31
|
||||
#define DE_SOURCE_WRAP_DISABLE 0
|
||||
#define DE_SOURCE_WRAP_ENABLE 1
|
||||
#define DE_SOURCE_X_K1 29:16
|
||||
#define DE_SOURCE_Y_K2 15:0
|
||||
#define DE_SOURCE_X_K1_MONO 20:16
|
||||
|
||||
#define DE_DESTINATION 0x4
|
||||
#define DE_DESTINATION_WRAP 31:31
|
||||
#define DE_DESTINATION_WRAP_DISABLE 0
|
||||
#define DE_DESTINATION_WRAP_ENABLE 1
|
||||
#define DE_DESTINATION_X 28:16
|
||||
#define DE_DESTINATION_Y 15:0
|
||||
|
||||
#define DE_DIMENSION 0x8
|
||||
#define DE_DIMENSION_X 28:16
|
||||
#define DE_DIMENSION_Y_ET 15:0
|
||||
|
||||
#define DE_CONTROL 0xC
|
||||
#define DE_CONTROL_STATUS 31:31
|
||||
#define DE_CONTROL_STATUS_STOP 0
|
||||
#define DE_CONTROL_STATUS_START 1
|
||||
#define DE_CONTROL_PATTERN 30:30
|
||||
#define DE_CONTROL_PATTERN_MONO 0
|
||||
#define DE_CONTROL_PATTERN_COLOR 1
|
||||
#define DE_CONTROL_UPDATE_DESTINATION_X 29:29
|
||||
#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0
|
||||
#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1
|
||||
#define DE_CONTROL_QUICK_START 28:28
|
||||
#define DE_CONTROL_QUICK_START_DISABLE 0
|
||||
#define DE_CONTROL_QUICK_START_ENABLE 1
|
||||
#define DE_CONTROL_DIRECTION 27:27
|
||||
#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0
|
||||
#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1
|
||||
#define DE_CONTROL_MAJOR 26:26
|
||||
#define DE_CONTROL_MAJOR_X 0
|
||||
#define DE_CONTROL_MAJOR_Y 1
|
||||
#define DE_CONTROL_STEP_X 25:25
|
||||
#define DE_CONTROL_STEP_X_POSITIVE 1
|
||||
#define DE_CONTROL_STEP_X_NEGATIVE 0
|
||||
#define DE_CONTROL_STEP_Y 24:24
|
||||
#define DE_CONTROL_STEP_Y_POSITIVE 1
|
||||
#define DE_CONTROL_STEP_Y_NEGATIVE 0
|
||||
#define DE_CONTROL_STRETCH 23:23
|
||||
#define DE_CONTROL_STRETCH_DISABLE 0
|
||||
#define DE_CONTROL_STRETCH_ENABLE 1
|
||||
#define DE_CONTROL_HOST 22:22
|
||||
#define DE_CONTROL_HOST_COLOR 0
|
||||
#define DE_CONTROL_HOST_MONO 1
|
||||
#define DE_CONTROL_LAST_PIXEL 21:21
|
||||
#define DE_CONTROL_LAST_PIXEL_OFF 0
|
||||
#define DE_CONTROL_LAST_PIXEL_ON 1
|
||||
#define DE_CONTROL_COMMAND 20:16
|
||||
#define DE_CONTROL_COMMAND_BITBLT 0
|
||||
#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1
|
||||
#define DE_CONTROL_COMMAND_DE_TILE 2
|
||||
#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3
|
||||
#define DE_CONTROL_COMMAND_ALPHA_BLEND 4
|
||||
#define DE_CONTROL_COMMAND_RLE_STRIP 5
|
||||
#define DE_CONTROL_COMMAND_SHORT_STROKE 6
|
||||
#define DE_CONTROL_COMMAND_LINE_DRAW 7
|
||||
#define DE_CONTROL_COMMAND_HOST_WRITE 8
|
||||
#define DE_CONTROL_COMMAND_HOST_READ 9
|
||||
#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10
|
||||
#define DE_CONTROL_COMMAND_ROTATE 11
|
||||
#define DE_CONTROL_COMMAND_FONT 12
|
||||
#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15
|
||||
#define DE_CONTROL_ROP_SELECT 15:15
|
||||
#define DE_CONTROL_ROP_SELECT_ROP3 0
|
||||
#define DE_CONTROL_ROP_SELECT_ROP2 1
|
||||
#define DE_CONTROL_ROP2_SOURCE 14:14
|
||||
#define DE_CONTROL_ROP2_SOURCE_BITMAP 0
|
||||
#define DE_CONTROL_ROP2_SOURCE_PATTERN 1
|
||||
#define DE_CONTROL_MONO_DATA 13:12
|
||||
#define DE_CONTROL_MONO_DATA_NOT_PACKED 0
|
||||
#define DE_CONTROL_MONO_DATA_8_PACKED 1
|
||||
#define DE_CONTROL_MONO_DATA_16_PACKED 2
|
||||
#define DE_CONTROL_MONO_DATA_32_PACKED 3
|
||||
#define DE_CONTROL_REPEAT_ROTATE 11:11
|
||||
#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0
|
||||
#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1
|
||||
#define DE_CONTROL_TRANSPARENCY_MATCH 10:10
|
||||
#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0
|
||||
#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1
|
||||
#define DE_CONTROL_TRANSPARENCY_SELECT 9:9
|
||||
#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0
|
||||
#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1
|
||||
#define DE_CONTROL_TRANSPARENCY 8:8
|
||||
#define DE_CONTROL_TRANSPARENCY_DISABLE 0
|
||||
#define DE_CONTROL_TRANSPARENCY_ENABLE 1
|
||||
#define DE_CONTROL_ROP 7:0
|
||||
|
||||
// Pseudo fields.
|
||||
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR 27:24
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_225 0
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_135 1
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_315 2
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_45 3
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_270 4
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_90 5
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_180 8
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_0 10
|
||||
#define DE_CONTROL_ROTATION 25:24
|
||||
#define DE_CONTROL_ROTATION_0 0
|
||||
#define DE_CONTROL_ROTATION_270 1
|
||||
#define DE_CONTROL_ROTATION_90 2
|
||||
#define DE_CONTROL_ROTATION_180 3
|
||||
|
||||
#define DE_PITCH 0x000010
|
||||
#define DE_PITCH_DESTINATION 28:16
|
||||
#define DE_PITCH_SOURCE 12:0
|
||||
|
||||
#define DE_FOREGROUND 0x000014
|
||||
#define DE_FOREGROUND_COLOR 31:0
|
||||
|
||||
#define DE_BACKGROUND 0x000018
|
||||
#define DE_BACKGROUND_COLOR 31:0
|
||||
|
||||
#define DE_STRETCH_FORMAT 0x00001C
|
||||
#define DE_STRETCH_FORMAT_PATTERN_XY 30:30
|
||||
#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0
|
||||
#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1
|
||||
#define DE_STRETCH_FORMAT_PATTERN_Y 29:27
|
||||
#define DE_STRETCH_FORMAT_PATTERN_X 25:23
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21:20
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3
|
||||
|
||||
#define DE_STRETCH_FORMAT_ADDRESSING 19:16
|
||||
#define DE_STRETCH_FORMAT_ADDRESSING_XY 0
|
||||
#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15
|
||||
#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11:0
|
||||
|
||||
#define DE_COLOR_COMPARE 0x000020
|
||||
#define DE_COLOR_COMPARE_COLOR 23:0
|
||||
|
||||
#define DE_COLOR_COMPARE_MASK 0x000024
|
||||
#define DE_COLOR_COMPARE_MASK_MASKS 23:0
|
||||
|
||||
#define DE_MASKS 0x000028
|
||||
#define DE_MASKS_BYTE_MASK 31:16
|
||||
#define DE_MASKS_BIT_MASK 15:0
|
||||
|
||||
#define DE_CLIP_TL 0x00002C
|
||||
#define DE_CLIP_TL_TOP 31:16
|
||||
#define DE_CLIP_TL_STATUS 13:13
|
||||
#define DE_CLIP_TL_STATUS_DISABLE 0
|
||||
#define DE_CLIP_TL_STATUS_ENABLE 1
|
||||
#define DE_CLIP_TL_INHIBIT 12:12
|
||||
#define DE_CLIP_TL_INHIBIT_OUTSIDE 0
|
||||
#define DE_CLIP_TL_INHIBIT_INSIDE 1
|
||||
#define DE_CLIP_TL_LEFT 11:0
|
||||
|
||||
#define DE_CLIP_BR 0x000030
|
||||
#define DE_CLIP_BR_BOTTOM 31:16
|
||||
#define DE_CLIP_BR_RIGHT 12:0
|
||||
|
||||
#define DE_MONO_PATTERN_LOW 0x000034
|
||||
#define DE_MONO_PATTERN_LOW_PATTERN 31:0
|
||||
|
||||
#define DE_MONO_PATTERN_HIGH 0x000038
|
||||
#define DE_MONO_PATTERN_HIGH_PATTERN 31:0
|
||||
|
||||
#define DE_WINDOW_WIDTH 0x00003C
|
||||
#define DE_WINDOW_WIDTH_DESTINATION 28:16
|
||||
#define DE_WINDOW_WIDTH_SOURCE 12:0
|
||||
|
||||
#define DE_WINDOW_SOURCE_BASE 0x000040
|
||||
#define DE_WINDOW_SOURCE_BASE_EXT 27:27
|
||||
#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0
|
||||
#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1
|
||||
#define DE_WINDOW_SOURCE_BASE_CS 26:26
|
||||
#define DE_WINDOW_SOURCE_BASE_CS_0 0
|
||||
#define DE_WINDOW_SOURCE_BASE_CS_1 1
|
||||
#define DE_WINDOW_SOURCE_BASE_ADDRESS 25:0
|
||||
|
||||
#define DE_WINDOW_DESTINATION_BASE 0x000044
|
||||
#define DE_WINDOW_DESTINATION_BASE_EXT 27:27
|
||||
#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0
|
||||
#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1
|
||||
#define DE_WINDOW_DESTINATION_BASE_CS 26:26
|
||||
#define DE_WINDOW_DESTINATION_BASE_CS_0 0
|
||||
#define DE_WINDOW_DESTINATION_BASE_CS_1 1
|
||||
#define DE_WINDOW_DESTINATION_BASE_ADDRESS 25:0
|
||||
|
||||
#define DE_ALPHA 0x000048
|
||||
#define DE_ALPHA_VALUE 7:0
|
||||
|
||||
#define DE_WRAP 0x00004C
|
||||
#define DE_WRAP_X 31:16
|
||||
#define DE_WRAP_Y 15:0
|
||||
|
||||
#define DE_STATUS 0x000050
|
||||
#define DE_STATUS_CSC 1:1
|
||||
#define DE_STATUS_CSC_CLEAR 0
|
||||
#define DE_STATUS_CSC_NOT_ACTIVE 0
|
||||
#define DE_STATUS_CSC_ACTIVE 1
|
||||
#define DE_STATUS_2D 0:0
|
||||
#define DE_STATUS_2D_CLEAR 0
|
||||
#define DE_STATUS_2D_NOT_ACTIVE 0
|
||||
#define DE_STATUS_2D_ACTIVE 1
|
||||
|
||||
|
||||
|
||||
/* blt direction */
|
||||
#define TOP_TO_BOTTOM 0
|
||||
#define LEFT_TO_RIGHT 0
|
||||
#define BOTTOM_TO_TOP 1
|
||||
#define RIGHT_TO_LEFT 1
|
||||
|
||||
void hw_set2dformat(struct lynx_accel * accel,int fmt);
|
||||
|
||||
void hw_de_init(struct lynx_accel * accel);
|
||||
|
||||
int hw_fillrect(struct lynx_accel * accel,
|
||||
u32 base,u32 pitch,u32 Bpp,
|
||||
u32 x,u32 y,u32 width,u32 height,
|
||||
u32 color,u32 rop);
|
||||
|
||||
int hw_copyarea(
|
||||
struct lynx_accel * accel,
|
||||
unsigned int sBase, /* Address of source: offset in frame buffer */
|
||||
unsigned int sPitch, /* Pitch value of source surface in BYTE */
|
||||
unsigned int sx,
|
||||
unsigned int sy, /* Starting coordinate of source surface */
|
||||
unsigned int dBase, /* Address of destination: offset in frame buffer */
|
||||
unsigned int dPitch, /* Pitch value of destination surface in BYTE */
|
||||
unsigned int bpp, /* Color depth of destination surface */
|
||||
unsigned int dx,
|
||||
unsigned int dy, /* Starting coordinate of destination surface */
|
||||
unsigned int width,
|
||||
unsigned int height, /* width and height of rectangle in pixel value */
|
||||
unsigned int rop2);
|
||||
|
||||
int hw_imageblit(
|
||||
struct lynx_accel * accel,
|
||||
unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */
|
||||
int srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
|
||||
unsigned int startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
|
||||
unsigned int dBase, /* Address of destination: offset in frame buffer */
|
||||
unsigned int dPitch, /* Pitch value of destination surface in BYTE */
|
||||
unsigned int bytePerPixel, /* Color depth of destination surface */
|
||||
unsigned int dx,
|
||||
unsigned int dy, /* Starting coordinate of destination surface */
|
||||
unsigned int width,
|
||||
unsigned int height, /* width and height of rectange in pixel value */
|
||||
unsigned int fColor, /* Foreground color (corresponding to a 1 in the monochrome data */
|
||||
unsigned int bColor, /* Background color (corresponding to a 0 in the monochrome data */
|
||||
unsigned int rop2);
|
||||
#endif
|
254
drivers/staging/sm750fb/sm750_cursor.c
Normal file
254
drivers/staging/sm750fb/sm750_cursor.c
Normal file
@ -0,0 +1,254 @@
|
||||
#include<linux/module.h>
|
||||
#include<linux/kernel.h>
|
||||
#include<linux/errno.h>
|
||||
#include<linux/string.h>
|
||||
#include<linux/mm.h>
|
||||
#include<linux/slab.h>
|
||||
#include<linux/delay.h>
|
||||
#include<linux/fb.h>
|
||||
#include<linux/ioport.h>
|
||||
#include<linux/init.h>
|
||||
#include<linux/pci.h>
|
||||
#include<linux/vmalloc.h>
|
||||
#include<linux/pagemap.h>
|
||||
#include <linux/console.h>
|
||||
#include<linux/platform_device.h>
|
||||
#include<linux/screen_info.h>
|
||||
|
||||
#include "sm750.h"
|
||||
#include "sm750_help.h"
|
||||
#include "sm750_cursor.h"
|
||||
|
||||
|
||||
#define PEEK32(addr) \
|
||||
readl(cursor->mmio + (addr))
|
||||
|
||||
#define POKE32(addr,data) \
|
||||
writel((data),cursor->mmio + (addr))
|
||||
|
||||
/* cursor control for voyager and 718/750*/
|
||||
#define HWC_ADDRESS 0x0
|
||||
#define HWC_ADDRESS_ENABLE 31:31
|
||||
#define HWC_ADDRESS_ENABLE_DISABLE 0
|
||||
#define HWC_ADDRESS_ENABLE_ENABLE 1
|
||||
#define HWC_ADDRESS_EXT 27:27
|
||||
#define HWC_ADDRESS_EXT_LOCAL 0
|
||||
#define HWC_ADDRESS_EXT_EXTERNAL 1
|
||||
#define HWC_ADDRESS_CS 26:26
|
||||
#define HWC_ADDRESS_CS_0 0
|
||||
#define HWC_ADDRESS_CS_1 1
|
||||
#define HWC_ADDRESS_ADDRESS 25:0
|
||||
|
||||
#define HWC_LOCATION 0x4
|
||||
#define HWC_LOCATION_TOP 27:27
|
||||
#define HWC_LOCATION_TOP_INSIDE 0
|
||||
#define HWC_LOCATION_TOP_OUTSIDE 1
|
||||
#define HWC_LOCATION_Y 26:16
|
||||
#define HWC_LOCATION_LEFT 11:11
|
||||
#define HWC_LOCATION_LEFT_INSIDE 0
|
||||
#define HWC_LOCATION_LEFT_OUTSIDE 1
|
||||
#define HWC_LOCATION_X 10:0
|
||||
|
||||
#define HWC_COLOR_12 0x8
|
||||
#define HWC_COLOR_12_2_RGB565 31:16
|
||||
#define HWC_COLOR_12_1_RGB565 15:0
|
||||
|
||||
#define HWC_COLOR_3 0xC
|
||||
#define HWC_COLOR_3_RGB565 15:0
|
||||
|
||||
|
||||
/* hw_cursor_xxx works for voyager,718 and 750 */
|
||||
void hw_cursor_enable(struct lynx_cursor * cursor)
|
||||
{
|
||||
u32 reg;
|
||||
reg = FIELD_VALUE(0,HWC_ADDRESS,ADDRESS,cursor->offset)|
|
||||
FIELD_SET(0,HWC_ADDRESS,EXT,LOCAL)|
|
||||
FIELD_SET(0,HWC_ADDRESS,ENABLE,ENABLE);
|
||||
POKE32(HWC_ADDRESS,reg);
|
||||
}
|
||||
void hw_cursor_disable(struct lynx_cursor * cursor)
|
||||
{
|
||||
POKE32(HWC_ADDRESS,0);
|
||||
}
|
||||
|
||||
void hw_cursor_setSize(struct lynx_cursor * cursor,
|
||||
int w,int h)
|
||||
{
|
||||
cursor->w = w;
|
||||
cursor->h = h;
|
||||
}
|
||||
void hw_cursor_setPos(struct lynx_cursor * cursor,
|
||||
int x,int y)
|
||||
{
|
||||
u32 reg;
|
||||
reg = FIELD_VALUE(0,HWC_LOCATION,Y,y)|
|
||||
FIELD_VALUE(0,HWC_LOCATION,X,x);
|
||||
POKE32(HWC_LOCATION,reg);
|
||||
}
|
||||
void hw_cursor_setColor(struct lynx_cursor * cursor,
|
||||
u32 fg,u32 bg)
|
||||
{
|
||||
POKE32(HWC_COLOR_12,(fg<<16)|(bg&0xffff));
|
||||
POKE32(HWC_COLOR_3,0xffe0);
|
||||
}
|
||||
|
||||
void hw_cursor_setData(struct lynx_cursor * cursor,
|
||||
u16 rop,const u8* pcol,const u8* pmsk)
|
||||
{
|
||||
int i,j,count,pitch,offset;
|
||||
u8 color,mask,opr;
|
||||
u16 data;
|
||||
u16 * pbuffer,*pstart;
|
||||
static ulong odd = 0;
|
||||
|
||||
/* in byte*/
|
||||
pitch = cursor->w >> 3;
|
||||
|
||||
/* in byte */
|
||||
count = pitch * cursor->h;
|
||||
|
||||
/* in ushort */
|
||||
offset = cursor->maxW * 2 / 8 / 2;
|
||||
|
||||
data = 0;
|
||||
pstart = (u16 *)cursor->vstart;
|
||||
pbuffer = pstart;
|
||||
|
||||
/*
|
||||
if(odd &1){
|
||||
hw_cursor_setData2(cursor,rop,pcol,pmsk);
|
||||
}
|
||||
odd++;
|
||||
if(odd > 0xfffffff0)
|
||||
odd=0;
|
||||
*/
|
||||
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
color = *pcol++;
|
||||
mask = *pmsk++;
|
||||
data = 0;
|
||||
|
||||
/* either method below works well,
|
||||
* but method 2 shows no lag
|
||||
* and method 1 seems a bit wrong*/
|
||||
#if 0
|
||||
if(rop == ROP_XOR)
|
||||
opr = mask ^ color;
|
||||
else
|
||||
opr = mask & color;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
|
||||
if(opr & (0x80 >> j))
|
||||
{ //use fg color,id = 2
|
||||
data |= 2 << (j*2);
|
||||
}else{
|
||||
//use bg color,id = 1
|
||||
data |= 1 << (j*2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for(j=0;j<8;j++){
|
||||
if(mask & (0x80>>j)){
|
||||
if(rop == ROP_XOR)
|
||||
opr = mask ^ color;
|
||||
else
|
||||
opr = mask & color;
|
||||
|
||||
/* 2 stands for forecolor and 1 for backcolor */
|
||||
data |= ((opr & (0x80>>j))?2:1)<<(j*2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*pbuffer = data;
|
||||
|
||||
/* assume pitch is 1,2,4,8,...*/
|
||||
#if 0
|
||||
if(!((i+1)&(pitch-1))) /* below line equal to is line */
|
||||
#else
|
||||
if((i+1) % pitch == 0)
|
||||
#endif
|
||||
{
|
||||
/* need a return */
|
||||
pstart += offset;
|
||||
pbuffer = pstart;
|
||||
}else{
|
||||
pbuffer++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hw_cursor_setData2(struct lynx_cursor * cursor,
|
||||
u16 rop,const u8* pcol,const u8* pmsk)
|
||||
{
|
||||
int i,j,count,pitch,offset;
|
||||
u8 color,mask,opr;
|
||||
u16 data;
|
||||
u16 * pbuffer,*pstart;
|
||||
|
||||
/* in byte*/
|
||||
pitch = cursor->w >> 3;
|
||||
|
||||
/* in byte */
|
||||
count = pitch * cursor->h;
|
||||
|
||||
/* in ushort */
|
||||
offset = cursor->maxW * 2 / 8 / 2;
|
||||
|
||||
data = 0;
|
||||
pstart = (u16 *)cursor->vstart;
|
||||
pbuffer = pstart;
|
||||
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
color = *pcol++;
|
||||
mask = *pmsk++;
|
||||
data = 0;
|
||||
|
||||
/* either method below works well, but method 2 shows no lag */
|
||||
#if 0
|
||||
if(rop == ROP_XOR)
|
||||
opr = mask ^ color;
|
||||
else
|
||||
opr = mask & color;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
|
||||
if(opr & (0x80 >> j))
|
||||
{ //use fg color,id = 2
|
||||
data |= 2 << (j*2);
|
||||
}else{
|
||||
//use bg color,id = 1
|
||||
data |= 1 << (j*2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for(j=0;j<8;j++){
|
||||
if(mask & (1<<j))
|
||||
data |= ((color & (1<<j))?1:2)<<(j*2);
|
||||
}
|
||||
#endif
|
||||
*pbuffer = data;
|
||||
|
||||
/* assume pitch is 1,2,4,8,...*/
|
||||
if(!(i&(pitch-1)))
|
||||
//if((i+1) % pitch == 0)
|
||||
{
|
||||
/* need a return */
|
||||
pstart += offset;
|
||||
pbuffer = pstart;
|
||||
}else{
|
||||
pbuffer++;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
17
drivers/staging/sm750fb/sm750_cursor.h
Normal file
17
drivers/staging/sm750fb/sm750_cursor.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef LYNX_CURSOR_H__
|
||||
#define LYNX_CURSOR_H__
|
||||
|
||||
/* hw_cursor_xxx works for voyager,718 and 750 */
|
||||
void hw_cursor_enable(struct lynx_cursor * cursor);
|
||||
void hw_cursor_disable(struct lynx_cursor * cursor);
|
||||
void hw_cursor_setSize(struct lynx_cursor * cursor,
|
||||
int w,int h);
|
||||
void hw_cursor_setPos(struct lynx_cursor * cursor,
|
||||
int x,int y);
|
||||
void hw_cursor_setColor(struct lynx_cursor * cursor,
|
||||
u32 fg,u32 bg);
|
||||
void hw_cursor_setData(struct lynx_cursor * cursor,
|
||||
u16 rop,const u8* data,const u8* mask);
|
||||
void hw_cursor_setData2(struct lynx_cursor * cursor,
|
||||
u16 rop,const u8* data,const u8* mask);
|
||||
#endif
|
111
drivers/staging/sm750fb/sm750_help.h
Normal file
111
drivers/staging/sm750fb/sm750_help.h
Normal file
@ -0,0 +1,111 @@
|
||||
#ifndef LYNX_HELP_H__
|
||||
#define LYNX_HELP_H__
|
||||
/*****************************************************************************\
|
||||
* FIELD MACROS *
|
||||
\*****************************************************************************/
|
||||
|
||||
#define _LSB(f) (0 ? f)
|
||||
#define _MSB(f) (1 ? f)
|
||||
#define _COUNT(f) (_MSB(f) - _LSB(f) + 1)
|
||||
|
||||
#define RAW_MASK(f) (0xFFFFFFFF >> (32 - _COUNT(f)))
|
||||
#define GET_MASK(f) (RAW_MASK(f) << _LSB(f))
|
||||
#define GET_FIELD(d,f) (((d) >> _LSB(f)) & RAW_MASK(f))
|
||||
#define TEST_FIELD(d,f,v) (GET_FIELD(d,f) == f ## _ ## v)
|
||||
#define SET_FIELD(d,f,v) (((d) & ~GET_MASK(f)) | \
|
||||
(((f ## _ ## v) & RAW_MASK(f)) << _LSB(f)))
|
||||
#define SET_FIELDV(d,f,v) (((d) & ~GET_MASK(f)) | \
|
||||
(((v) & RAW_MASK(f)) << _LSB(f)))
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Internal macros //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define _F_START(f) (0 ? f)
|
||||
#define _F_END(f) (1 ? f)
|
||||
#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f))
|
||||
#define _F_MASK(f) (((1 << _F_SIZE(f)) - 1) << _F_START(f))
|
||||
#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f))
|
||||
#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f))
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Global macros //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define FIELD_GET(x, reg, field) \
|
||||
( \
|
||||
_F_NORMALIZE((x), reg ## _ ## field) \
|
||||
)
|
||||
|
||||
#define FIELD_SET(x, reg, field, value) \
|
||||
( \
|
||||
(x & ~_F_MASK(reg ## _ ## field)) \
|
||||
| _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
|
||||
)
|
||||
|
||||
#define FIELD_VALUE(x, reg, field, value) \
|
||||
( \
|
||||
(x & ~_F_MASK(reg ## _ ## field)) \
|
||||
| _F_DENORMALIZE(value, reg ## _ ## field) \
|
||||
)
|
||||
|
||||
#define FIELD_CLEAR(reg, field) \
|
||||
( \
|
||||
~ _F_MASK(reg ## _ ## field) \
|
||||
)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Field Macros //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define FIELD_START(field) (0 ? field)
|
||||
#define FIELD_END(field) (1 ? field)
|
||||
#define FIELD_SIZE(field) (1 + FIELD_END(field) - FIELD_START(field))
|
||||
#define FIELD_MASK(field) (((1 << (FIELD_SIZE(field)-1)) | ((1 << (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field))
|
||||
#define FIELD_NORMALIZE(reg, field) (((reg) & FIELD_MASK(field)) >> FIELD_START(field))
|
||||
#define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & FIELD_MASK(field))
|
||||
|
||||
#define FIELD_INIT(reg, field, value) FIELD_DENORMALIZE(reg ## _ ## field, \
|
||||
reg ## _ ## field ## _ ## value)
|
||||
#define FIELD_INIT_VAL(reg, field, value) \
|
||||
(FIELD_DENORMALIZE(reg ## _ ## field, value))
|
||||
#define FIELD_VAL_SET(x, r, f, v) x = x & ~FIELD_MASK(r ## _ ## f) \
|
||||
| FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v)
|
||||
|
||||
#define RGB(r, g, b) \
|
||||
( \
|
||||
(unsigned long) (((r) << 16) | ((g) << 8) | (b)) \
|
||||
)
|
||||
|
||||
#define RGB16(r, g, b) \
|
||||
( \
|
||||
(unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3)) \
|
||||
)
|
||||
|
||||
static inline unsigned int absDiff(unsigned int a,unsigned int b)
|
||||
{
|
||||
if(a<b)
|
||||
return b-a;
|
||||
else
|
||||
return a-b;
|
||||
}
|
||||
|
||||
/* n / d + 1 / 2 = (2n + d) / 2d */
|
||||
#define roundedDiv(num,denom) ((2 * (num) + (denom)) / (2 * (denom)))
|
||||
#define MB(x) ((x)<<20)
|
||||
#define KB(x) ((x)<<10)
|
||||
#define MHz(x) ((x) * 1000000)
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
640
drivers/staging/sm750fb/sm750_hw.c
Normal file
640
drivers/staging/sm750fb/sm750_hw.c
Normal file
@ -0,0 +1,640 @@
|
||||
#include <linux/version.h>
|
||||
#include<linux/module.h>
|
||||
#include<linux/kernel.h>
|
||||
#include<linux/errno.h>
|
||||
#include<linux/string.h>
|
||||
#include<linux/mm.h>
|
||||
#include<linux/slab.h>
|
||||
#include<linux/delay.h>
|
||||
#include<linux/fb.h>
|
||||
#include<linux/ioport.h>
|
||||
#include<linux/init.h>
|
||||
#include<linux/pci.h>
|
||||
#include<linux/vmalloc.h>
|
||||
#include<linux/pagemap.h>
|
||||
#include <linux/console.h>
|
||||
#ifdef CONFIG_MTRR
|
||||
#include <asm/mtrr.h>
|
||||
#endif
|
||||
#include<linux/platform_device.h>
|
||||
#include<linux/screen_info.h>
|
||||
|
||||
#include "sm750.h"
|
||||
#include "sm750_hw.h"
|
||||
#include "ddk750.h"
|
||||
#include "sm750_accel.h"
|
||||
|
||||
int hw_sm750_map(struct lynx_share* share,struct pci_dev* pdev)
|
||||
{
|
||||
int ret;
|
||||
struct sm750_share * spec_share;
|
||||
|
||||
|
||||
spec_share = container_of(share,struct sm750_share,share);
|
||||
ret = 0;
|
||||
|
||||
share->vidreg_start = pci_resource_start(pdev,1);
|
||||
share->vidreg_size = MB(2);
|
||||
|
||||
pr_info("mmio phyAddr = %x\n",share->vidreg_start);
|
||||
|
||||
/* reserve the vidreg space of smi adaptor
|
||||
* if you do this, u need to add release region code
|
||||
* in lynxfb_remove, or memory will not be mapped again
|
||||
* successfully
|
||||
* */
|
||||
|
||||
if((ret = pci_request_region(pdev,1,"sm750fb")))
|
||||
{
|
||||
pr_err("Can not request PCI regions.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* now map mmio and vidmem*/
|
||||
share->pvReg = ioremap_nocache(share->vidreg_start,share->vidreg_size);
|
||||
if(!share->pvReg){
|
||||
pr_err("mmio failed\n");
|
||||
ret = -EFAULT;
|
||||
goto exit;
|
||||
}else{
|
||||
pr_info("mmio virtual addr = %p\n",share->pvReg);
|
||||
}
|
||||
|
||||
|
||||
share->accel.dprBase = share->pvReg + DE_BASE_ADDR_TYPE1;
|
||||
share->accel.dpPortBase = share->pvReg + DE_PORT_ADDR_TYPE1;
|
||||
|
||||
ddk750_set_mmio(share->pvReg,share->devid,share->revid);
|
||||
|
||||
share->vidmem_start = pci_resource_start(pdev,0);
|
||||
/* don't use pdev_resource[x].end - resource[x].start to
|
||||
* calculate the resource size,its only the maximum available
|
||||
* size but not the actual size,use
|
||||
* @hw_sm750_getVMSize function can be safe.
|
||||
* */
|
||||
share->vidmem_size = hw_sm750_getVMSize(share);
|
||||
pr_info("video memory phyAddr = %x, size = %d bytes\n",
|
||||
share->vidmem_start,share->vidmem_size);
|
||||
|
||||
/* reserve the vidmem space of smi adaptor */
|
||||
#if 0
|
||||
if((ret = pci_request_region(pdev,0,_moduleName_)))
|
||||
{
|
||||
pr_err("Can not request PCI regions.\n");
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
share->pvMem = ioremap(share->vidmem_start,
|
||||
share->vidmem_size);
|
||||
|
||||
if(!share->pvMem){
|
||||
pr_err("Map video memory failed\n");
|
||||
ret = -EFAULT;
|
||||
goto exit;
|
||||
}else{
|
||||
pr_info("video memory vaddr = %p\n",share->pvMem);
|
||||
}
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int hw_sm750_inithw(struct lynx_share* share,struct pci_dev * pdev)
|
||||
{
|
||||
struct sm750_share * spec_share;
|
||||
struct init_status * parm;
|
||||
|
||||
spec_share = container_of(share,struct sm750_share,share);
|
||||
parm = &spec_share->state.initParm;
|
||||
if(parm->chip_clk == 0)
|
||||
parm->chip_clk = (getChipType() == SM750LE)?
|
||||
DEFAULT_SM750LE_CHIP_CLOCK :
|
||||
DEFAULT_SM750_CHIP_CLOCK;
|
||||
|
||||
if(parm->mem_clk == 0)
|
||||
parm->mem_clk = parm->chip_clk;
|
||||
if(parm->master_clk == 0)
|
||||
parm->master_clk = parm->chip_clk/3;
|
||||
|
||||
ddk750_initHw((initchip_param_t *)&spec_share->state.initParm);
|
||||
/* for sm718,open pci burst */
|
||||
if(share->devid == 0x718){
|
||||
POKE32(SYSTEM_CTRL,
|
||||
FIELD_SET(PEEK32(SYSTEM_CTRL),SYSTEM_CTRL,PCI_BURST,ON));
|
||||
}
|
||||
|
||||
/* sm750 use sii164, it can be setup with default value
|
||||
* by on power, so initDVIDisp can be skipped */
|
||||
#if 0
|
||||
ddk750_initDVIDisp();
|
||||
#endif
|
||||
|
||||
if(getChipType() != SM750LE)
|
||||
{
|
||||
/* does user need CRT ?*/
|
||||
if(spec_share->state.nocrt){
|
||||
POKE32(MISC_CTRL,
|
||||
FIELD_SET(PEEK32(MISC_CTRL),
|
||||
MISC_CTRL,
|
||||
DAC_POWER,OFF));
|
||||
/* shut off dpms */
|
||||
POKE32(SYSTEM_CTRL,
|
||||
FIELD_SET(PEEK32(SYSTEM_CTRL),
|
||||
SYSTEM_CTRL,
|
||||
DPMS,VNHN));
|
||||
}else{
|
||||
POKE32(MISC_CTRL,
|
||||
FIELD_SET(PEEK32(MISC_CTRL),
|
||||
MISC_CTRL,
|
||||
DAC_POWER,ON));
|
||||
/* turn on dpms */
|
||||
POKE32(SYSTEM_CTRL,
|
||||
FIELD_SET(PEEK32(SYSTEM_CTRL),
|
||||
SYSTEM_CTRL,
|
||||
DPMS,VPHP));
|
||||
}
|
||||
|
||||
switch (spec_share->state.pnltype){
|
||||
case sm750_doubleTFT:
|
||||
case sm750_24TFT:
|
||||
case sm750_dualTFT:
|
||||
POKE32(PANEL_DISPLAY_CTRL,
|
||||
FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL),
|
||||
PANEL_DISPLAY_CTRL,
|
||||
TFT_DISP,
|
||||
spec_share->state.pnltype));
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
/* for 750LE ,no DVI chip initilization makes Monitor no signal */
|
||||
/* Set up GPIO for software I2C to program DVI chip in the
|
||||
Xilinx SP605 board, in order to have video signal.
|
||||
*/
|
||||
swI2CInit(0,1);
|
||||
|
||||
|
||||
/* Customer may NOT use CH7301 DVI chip, which has to be
|
||||
initialized differently.
|
||||
*/
|
||||
if (swI2CReadReg(0xec, 0x4a) == 0x95)
|
||||
{
|
||||
/* The following register values for CH7301 are from
|
||||
Chrontel app note and our experiment.
|
||||
*/
|
||||
pr_info("yes,CH7301 DVI chip found\n");
|
||||
swI2CWriteReg(0xec, 0x1d, 0x16);
|
||||
swI2CWriteReg(0xec, 0x21, 0x9);
|
||||
swI2CWriteReg(0xec, 0x49, 0xC0);
|
||||
pr_info("okay,CH7301 DVI chip setup done\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* init 2d engine */
|
||||
if(!share->accel_off){
|
||||
hw_sm750_initAccel(share);
|
||||
// share->accel.de_wait = hw_sm750_deWait;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
resource_size_t hw_sm750_getVMSize(struct lynx_share * share)
|
||||
{
|
||||
resource_size_t ret;
|
||||
|
||||
ret = ddk750_getVMSize();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int hw_sm750_output_checkMode(struct lynxfb_output* output,struct fb_var_screeninfo* var)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hw_sm750_output_setMode(struct lynxfb_output* output,
|
||||
struct fb_var_screeninfo* var,struct fb_fix_screeninfo* fix)
|
||||
{
|
||||
int ret;
|
||||
disp_output_t dispSet;
|
||||
int channel;
|
||||
|
||||
ret = 0;
|
||||
dispSet = 0;
|
||||
channel = *output->channel;
|
||||
|
||||
|
||||
if(getChipType() != SM750LE){
|
||||
if(channel == sm750_primary){
|
||||
pr_info("primary channel\n");
|
||||
if(output->paths & sm750_panel)
|
||||
dispSet |= do_LCD1_PRI;
|
||||
if(output->paths & sm750_crt)
|
||||
dispSet |= do_CRT_PRI;
|
||||
|
||||
}else{
|
||||
pr_info("secondary channel\n");
|
||||
if(output->paths & sm750_panel)
|
||||
dispSet |= do_LCD1_SEC;
|
||||
if(output->paths & sm750_crt)
|
||||
dispSet |= do_CRT_SEC;
|
||||
|
||||
}
|
||||
ddk750_setLogicalDispOut(dispSet);
|
||||
}else{
|
||||
/* just open DISPLAY_CONTROL_750LE register bit 3:0*/
|
||||
u32 reg;
|
||||
reg = PEEK32(DISPLAY_CONTROL_750LE);
|
||||
reg |= 0xf;
|
||||
POKE32(DISPLAY_CONTROL_750LE,reg);
|
||||
}
|
||||
|
||||
pr_info("ddk setlogicdispout done \n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hw_sm750_output_clear(struct lynxfb_output* output)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int hw_sm750_crtc_checkMode(struct lynxfb_crtc* crtc,struct fb_var_screeninfo* var)
|
||||
{
|
||||
struct lynx_share * share;
|
||||
|
||||
|
||||
share = container_of(crtc,struct lynxfb_par,crtc)->share;
|
||||
|
||||
switch (var->bits_per_pixel){
|
||||
case 8:
|
||||
case 16:
|
||||
break;
|
||||
case 32:
|
||||
if(share->revid == (unsigned char)SM750LE_REVISION_ID){
|
||||
pr_debug("750le do not support 32bpp\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
set the controller's mode for @crtc charged with @var and @fix parameters
|
||||
*/
|
||||
int hw_sm750_crtc_setMode(struct lynxfb_crtc* crtc,
|
||||
struct fb_var_screeninfo* var,
|
||||
struct fb_fix_screeninfo* fix)
|
||||
{
|
||||
int ret,fmt;
|
||||
u32 reg;
|
||||
mode_parameter_t modparm;
|
||||
clock_type_t clock;
|
||||
struct lynx_share * share;
|
||||
struct lynxfb_par * par;
|
||||
|
||||
|
||||
ret = 0;
|
||||
par = container_of(crtc,struct lynxfb_par,crtc);
|
||||
share = par->share;
|
||||
#if 1
|
||||
if(!share->accel_off){
|
||||
/* set 2d engine pixel format according to mode bpp */
|
||||
switch(var->bits_per_pixel){
|
||||
case 8:
|
||||
fmt = 0;
|
||||
break;
|
||||
case 16:
|
||||
fmt = 1;
|
||||
break;
|
||||
case 32:
|
||||
default:
|
||||
fmt = 2;
|
||||
break;
|
||||
}
|
||||
hw_set2dformat(&share->accel,fmt);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* set timing */
|
||||
// modparm.pixel_clock = PS_TO_HZ(var->pixclock);
|
||||
modparm.pixel_clock = ps_to_hz(var->pixclock);
|
||||
modparm.vertical_sync_polarity = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS:NEG;
|
||||
modparm.horizontal_sync_polarity = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS:NEG;
|
||||
modparm.clock_phase_polarity = (var->sync& FB_SYNC_COMP_HIGH_ACT) ? POS:NEG;
|
||||
modparm.horizontal_display_end = var->xres;
|
||||
modparm.horizontal_sync_width = var->hsync_len;
|
||||
modparm.horizontal_sync_start = var->xres + var->right_margin;
|
||||
modparm.horizontal_total = var->xres + var->left_margin + var->right_margin + var->hsync_len;
|
||||
modparm.vertical_display_end = var->yres;
|
||||
modparm.vertical_sync_height = var->vsync_len;
|
||||
modparm.vertical_sync_start = var->yres + var->lower_margin;
|
||||
modparm.vertical_total = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
|
||||
|
||||
/* choose pll */
|
||||
if(crtc->channel != sm750_secondary)
|
||||
clock = PRIMARY_PLL;
|
||||
else
|
||||
clock = SECONDARY_PLL;
|
||||
|
||||
pr_debug("Request pixel clock = %lu\n",modparm.pixel_clock);
|
||||
ret = ddk750_setModeTiming(&modparm,clock);
|
||||
if(ret){
|
||||
pr_err("Set mode timing failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(crtc->channel != sm750_secondary){
|
||||
/* set pitch, offset ,width,start address ,etc... */
|
||||
POKE32(PANEL_FB_ADDRESS,
|
||||
FIELD_SET(0,PANEL_FB_ADDRESS,STATUS,CURRENT)|
|
||||
FIELD_SET(0,PANEL_FB_ADDRESS,EXT,LOCAL)|
|
||||
FIELD_VALUE(0,PANEL_FB_ADDRESS,ADDRESS,crtc->oScreen));
|
||||
|
||||
reg = var->xres * (var->bits_per_pixel >> 3);
|
||||
/* crtc->channel is not equal to par->index on numeric,be aware of that */
|
||||
reg = PADDING(crtc->line_pad,reg);
|
||||
|
||||
POKE32(PANEL_FB_WIDTH,
|
||||
FIELD_VALUE(0,PANEL_FB_WIDTH,WIDTH,reg)|
|
||||
FIELD_VALUE(0,PANEL_FB_WIDTH,OFFSET,fix->line_length));
|
||||
|
||||
POKE32(PANEL_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0,PANEL_WINDOW_WIDTH,WIDTH,var->xres -1)|
|
||||
FIELD_VALUE(0,PANEL_WINDOW_WIDTH,X,var->xoffset));
|
||||
|
||||
POKE32(PANEL_WINDOW_HEIGHT,
|
||||
FIELD_VALUE(0,PANEL_WINDOW_HEIGHT,HEIGHT,var->yres_virtual - 1)|
|
||||
FIELD_VALUE(0,PANEL_WINDOW_HEIGHT,Y,var->yoffset));
|
||||
|
||||
POKE32(PANEL_PLANE_TL,0);
|
||||
|
||||
POKE32(PANEL_PLANE_BR,
|
||||
FIELD_VALUE(0,PANEL_PLANE_BR,BOTTOM,var->yres - 1)|
|
||||
FIELD_VALUE(0,PANEL_PLANE_BR,RIGHT,var->xres - 1));
|
||||
|
||||
/* set pixel format */
|
||||
reg = PEEK32(PANEL_DISPLAY_CTRL);
|
||||
POKE32(PANEL_DISPLAY_CTRL,
|
||||
FIELD_VALUE(reg,
|
||||
PANEL_DISPLAY_CTRL,FORMAT,
|
||||
(var->bits_per_pixel >> 4)
|
||||
));
|
||||
}else{
|
||||
/* not implemented now */
|
||||
POKE32(CRT_FB_ADDRESS,crtc->oScreen);
|
||||
reg = var->xres * (var->bits_per_pixel >> 3);
|
||||
/* crtc->channel is not equal to par->index on numeric,be aware of that */
|
||||
reg = PADDING(crtc->line_pad,reg);
|
||||
|
||||
POKE32(CRT_FB_WIDTH,
|
||||
FIELD_VALUE(0,CRT_FB_WIDTH,WIDTH,reg)|
|
||||
FIELD_VALUE(0,CRT_FB_WIDTH,OFFSET,fix->line_length));
|
||||
|
||||
/* SET PIXEL FORMAT */
|
||||
reg = PEEK32(CRT_DISPLAY_CTRL);
|
||||
reg = FIELD_VALUE(reg,CRT_DISPLAY_CTRL,FORMAT,var->bits_per_pixel >> 4);
|
||||
POKE32(CRT_DISPLAY_CTRL,reg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hw_sm750_crtc_clear(struct lynxfb_crtc* crtc)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int hw_sm750_setColReg(struct lynxfb_crtc* crtc,ushort index,
|
||||
ushort red,ushort green,ushort blue)
|
||||
{
|
||||
static unsigned int add[]={PANEL_PALETTE_RAM,CRT_PALETTE_RAM};
|
||||
POKE32(add[crtc->channel] + index*4 ,(red<<16)|(green<<8)|blue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_sm750le_setBLANK(struct lynxfb_output * output,int blank){
|
||||
int dpms,crtdb;
|
||||
|
||||
switch(blank)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_UNBLANK:
|
||||
#else
|
||||
case VESA_NO_BLANKING:
|
||||
#endif
|
||||
dpms = CRT_DISPLAY_CTRL_DPMS_0;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
|
||||
break;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_NORMAL:
|
||||
dpms = CRT_DISPLAY_CTRL_DPMS_0;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_VSYNC_SUSPEND:
|
||||
#else
|
||||
case VESA_VSYNC_SUSPEND:
|
||||
#endif
|
||||
dpms = CRT_DISPLAY_CTRL_DPMS_2;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
#else
|
||||
case VESA_HSYNC_SUSPEND:
|
||||
#endif
|
||||
dpms = CRT_DISPLAY_CTRL_DPMS_1;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_POWERDOWN:
|
||||
#else
|
||||
case VESA_POWERDOWN:
|
||||
#endif
|
||||
dpms = CRT_DISPLAY_CTRL_DPMS_3;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
}
|
||||
|
||||
if(output->paths & sm750_crt){
|
||||
POKE32(CRT_DISPLAY_CTRL,FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL),CRT_DISPLAY_CTRL,DPMS,dpms));
|
||||
POKE32(CRT_DISPLAY_CTRL,FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL),CRT_DISPLAY_CTRL,BLANK,crtdb));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_sm750_setBLANK(struct lynxfb_output* output,int blank)
|
||||
{
|
||||
unsigned int dpms,pps,crtdb;
|
||||
|
||||
dpms = pps = crtdb = 0;
|
||||
|
||||
switch (blank)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_UNBLANK:
|
||||
#else
|
||||
case VESA_NO_BLANKING:
|
||||
#endif
|
||||
pr_info("flag = FB_BLANK_UNBLANK \n");
|
||||
dpms = SYSTEM_CTRL_DPMS_VPHP;
|
||||
pps = PANEL_DISPLAY_CTRL_DATA_ENABLE;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_OFF;
|
||||
break;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_NORMAL:
|
||||
pr_info("flag = FB_BLANK_NORMAL \n");
|
||||
dpms = SYSTEM_CTRL_DPMS_VPHP;
|
||||
pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_VSYNC_SUSPEND:
|
||||
#else
|
||||
case VESA_VSYNC_SUSPEND:
|
||||
#endif
|
||||
dpms = SYSTEM_CTRL_DPMS_VNHP;
|
||||
pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
#else
|
||||
case VESA_HSYNC_SUSPEND:
|
||||
#endif
|
||||
dpms = SYSTEM_CTRL_DPMS_VPHN;
|
||||
pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
||||
case FB_BLANK_POWERDOWN:
|
||||
#else
|
||||
case VESA_POWERDOWN:
|
||||
#endif
|
||||
dpms = SYSTEM_CTRL_DPMS_VNHN;
|
||||
pps = PANEL_DISPLAY_CTRL_DATA_DISABLE;
|
||||
crtdb = CRT_DISPLAY_CTRL_BLANK_ON;
|
||||
break;
|
||||
}
|
||||
|
||||
if(output->paths & sm750_crt){
|
||||
|
||||
POKE32(SYSTEM_CTRL,FIELD_VALUE(PEEK32(SYSTEM_CTRL),SYSTEM_CTRL,DPMS,dpms));
|
||||
POKE32(CRT_DISPLAY_CTRL,FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL),CRT_DISPLAY_CTRL,BLANK,crtdb));
|
||||
}
|
||||
|
||||
if(output->paths & sm750_panel){
|
||||
POKE32(PANEL_DISPLAY_CTRL,FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL),PANEL_DISPLAY_CTRL,DATA,pps));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hw_sm750_initAccel(struct lynx_share * share)
|
||||
{
|
||||
u32 reg;
|
||||
enable2DEngine(1);
|
||||
|
||||
if(getChipType() == SM750LE){
|
||||
reg = PEEK32(DE_STATE1);
|
||||
reg = FIELD_SET(reg,DE_STATE1,DE_ABORT,ON);
|
||||
POKE32(DE_STATE1,reg);
|
||||
|
||||
reg = PEEK32(DE_STATE1);
|
||||
reg = FIELD_SET(reg,DE_STATE1,DE_ABORT,OFF);
|
||||
POKE32(DE_STATE1,reg);
|
||||
|
||||
}else{
|
||||
/* engine reset */
|
||||
reg = PEEK32(SYSTEM_CTRL);
|
||||
reg = FIELD_SET(reg,SYSTEM_CTRL,DE_ABORT,ON);
|
||||
POKE32(SYSTEM_CTRL,reg);
|
||||
|
||||
reg = PEEK32(SYSTEM_CTRL);
|
||||
reg = FIELD_SET(reg,SYSTEM_CTRL,DE_ABORT,OFF);
|
||||
POKE32(SYSTEM_CTRL,reg);
|
||||
}
|
||||
|
||||
/* call 2d init */
|
||||
share->accel.de_init(&share->accel);
|
||||
}
|
||||
|
||||
int hw_sm750le_deWait()
|
||||
{
|
||||
int i=0x10000000;
|
||||
while(i--){
|
||||
unsigned int dwVal = PEEK32(DE_STATE2);
|
||||
if((FIELD_GET(dwVal,DE_STATE2,DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) &&
|
||||
(FIELD_GET(dwVal,DE_STATE2,DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) &&
|
||||
(FIELD_GET(dwVal,DE_STATE2,DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* timeout error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int hw_sm750_deWait()
|
||||
{
|
||||
int i=0x10000000;
|
||||
while(i--){
|
||||
unsigned int dwVal = PEEK32(SYSTEM_CTRL);
|
||||
if((FIELD_GET(dwVal,SYSTEM_CTRL,DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) &&
|
||||
(FIELD_GET(dwVal,SYSTEM_CTRL,DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) &&
|
||||
(FIELD_GET(dwVal,SYSTEM_CTRL,DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* timeout error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
|
||||
const struct fb_var_screeninfo *var,
|
||||
const struct fb_info *info)
|
||||
{
|
||||
uint32_t total;
|
||||
//check params
|
||||
if ((var->xoffset + var->xres > var->xres_virtual) ||
|
||||
(var->yoffset + var->yres > var->yres_virtual)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
total = var->yoffset * info->fix.line_length +
|
||||
((var->xoffset * var->bits_per_pixel) >> 3);
|
||||
total += crtc->oScreen;
|
||||
if (crtc->channel == sm750_primary) {
|
||||
POKE32(PANEL_FB_ADDRESS,
|
||||
FIELD_VALUE(PEEK32(PANEL_FB_ADDRESS),
|
||||
PANEL_FB_ADDRESS, ADDRESS, total));
|
||||
} else {
|
||||
POKE32(CRT_FB_ADDRESS,
|
||||
FIELD_VALUE(PEEK32(CRT_FB_ADDRESS),
|
||||
CRT_FB_ADDRESS, ADDRESS, total));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
104
drivers/staging/sm750fb/sm750_hw.h
Normal file
104
drivers/staging/sm750fb/sm750_hw.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef LYNX_HW750_H__
|
||||
#define LYNX_HW750_H__
|
||||
|
||||
|
||||
#define DEFAULT_SM750_CHIP_CLOCK 290
|
||||
#define DEFAULT_SM750LE_CHIP_CLOCK 333
|
||||
#ifndef SM750LE_REVISION_ID
|
||||
#define SM750LE_REVISION_ID (unsigned char)0xfe
|
||||
#endif
|
||||
|
||||
//#define DEFAULT_MEM_CLOCK (DEFAULT_SM750_CHIP_CLOCK/1)
|
||||
//#define DEFAULT_MASTER_CLOCK (DEFAULT_SM750_CHIP_CLOCK/3)
|
||||
|
||||
|
||||
enum sm750_pnltype{
|
||||
|
||||
sm750_24TFT = 0,/* 24bit tft */
|
||||
|
||||
sm750_dualTFT = 2,/* dual 18 bit tft */
|
||||
|
||||
sm750_doubleTFT = 1,/* 36 bit double pixel tft */
|
||||
};
|
||||
|
||||
/* vga channel is not concerned */
|
||||
enum sm750_dataflow{
|
||||
sm750_simul_pri,/* primary => all head */
|
||||
|
||||
sm750_simul_sec,/* secondary => all head */
|
||||
|
||||
sm750_dual_normal,/* primary => panel head and secondary => crt */
|
||||
|
||||
sm750_dual_swap,/* primary => crt head and secondary => panel */
|
||||
};
|
||||
|
||||
|
||||
enum sm750_channel{
|
||||
sm750_primary = 0,
|
||||
/* enum value equal to the register filed data */
|
||||
sm750_secondary = 1,
|
||||
};
|
||||
|
||||
enum sm750_path{
|
||||
sm750_panel = 1,
|
||||
sm750_crt = 2,
|
||||
sm750_pnc = 3,/* panel and crt */
|
||||
};
|
||||
|
||||
struct init_status{
|
||||
ushort powerMode;
|
||||
/* below three clocks are in unit of MHZ*/
|
||||
ushort chip_clk;
|
||||
ushort mem_clk;
|
||||
ushort master_clk;
|
||||
ushort setAllEngOff;
|
||||
ushort resetMemory;
|
||||
};
|
||||
|
||||
struct sm750_state{
|
||||
struct init_status initParm;
|
||||
enum sm750_pnltype pnltype;
|
||||
enum sm750_dataflow dataflow;
|
||||
int nocrt;
|
||||
int xLCD;
|
||||
int yLCD;
|
||||
};
|
||||
|
||||
/* sm750_share stands for a presentation of two frame buffer
|
||||
that use one sm750 adaptor, it is similiar to the super class of lynx_share
|
||||
in C++
|
||||
*/
|
||||
|
||||
struct sm750_share{
|
||||
/* it's better to put lynx_share struct to the first place of sm750_share */
|
||||
struct lynx_share share;
|
||||
struct sm750_state state;
|
||||
int hwCursor;
|
||||
/* 0: no hardware cursor
|
||||
1: primary crtc hw cursor enabled,
|
||||
2: secondary crtc hw cursor enabled
|
||||
3: both ctrc hw cursor enabled
|
||||
*/
|
||||
};
|
||||
|
||||
int hw_sm750_map(struct lynx_share* share,struct pci_dev* pdev);
|
||||
int hw_sm750_inithw(struct lynx_share*,struct pci_dev *);
|
||||
void hw_sm750_initAccel(struct lynx_share *);
|
||||
int hw_sm750_deWait(void);
|
||||
int hw_sm750le_deWait(void);
|
||||
|
||||
resource_size_t hw_sm750_getVMSize(struct lynx_share *);
|
||||
int hw_sm750_output_checkMode(struct lynxfb_output*,struct fb_var_screeninfo*);
|
||||
int hw_sm750_output_setMode(struct lynxfb_output*,struct fb_var_screeninfo*,struct fb_fix_screeninfo*);
|
||||
int hw_sm750_crtc_checkMode(struct lynxfb_crtc*,struct fb_var_screeninfo*);
|
||||
int hw_sm750_crtc_setMode(struct lynxfb_crtc*,struct fb_var_screeninfo*,struct fb_fix_screeninfo*);
|
||||
int hw_sm750_setColReg(struct lynxfb_crtc*,ushort,ushort,ushort,ushort);
|
||||
int hw_sm750_setBLANK(struct lynxfb_output*,int);
|
||||
int hw_sm750le_setBLANK(struct lynxfb_output*,int);
|
||||
void hw_sm750_crtc_clear(struct lynxfb_crtc*);
|
||||
void hw_sm750_output_clear(struct lynxfb_output*);
|
||||
int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
|
||||
const struct fb_var_screeninfo *var,
|
||||
const struct fb_info *info);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user