Commit 81dee67e authored by Sudip Mukherjee's avatar Sudip Mukherjee Committed by Greg Kroah-Hartman

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: default avatarSudip Mukherjee <sudip@vectorindia.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c3d6047d
......@@ -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/
......
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>.
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
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>
#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
This diff is collapsed.
#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
#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;
}
#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
#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
#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
//#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");
}
#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
#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, &registerIndex) == 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
#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
#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;
}
#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
#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);
}
#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
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
#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
This diff is collapsed.
/*******************************************************************
*
* 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_ */
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);
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.
This diff is collapsed.
#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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#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
#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
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment