Commit 37a99d0e authored by 吴智聪(John Wu)'s avatar 吴智聪(John Wu)

Merge branch 'neuros' of...

Merge branch 'neuros' of ssh://git@git.neuros.com.cn/git/git-pub/osd20/linux-davinci-2.6 into neuros
parents 62922b66 5f49f747
......@@ -508,8 +508,9 @@ source "arch/arm/common/Kconfig"
config FORCE_MAX_ZONEORDER
int
depends on SA1111
default "9"
depends on SA1111 || ARCH_DAVINCI
default "9" if SA1111
default "13" if ARCH_DAVINCI
menu "Bus support"
......
......@@ -161,7 +161,8 @@ static struct platform_device ntosd_644xa_nandflash_device = {
};
#endif
#if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE)
#if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE) || \
defined(CONFIG_FB_DM) || defined(CONFIG_FB_DM_MODULE)
static u64 davinci_fb_dma_mask = DMA_32BIT_MASK;
......@@ -240,7 +241,8 @@ static struct platform_device *ntosd_644xa_devices[] __initdata = {
#if defined(CONFIG_MTD_NAND_DAVINCI) || defined(CONFIG_MTD_NAND_DAVINCI_MODULE)
&ntosd_644xa_nandflash_device,
#endif
#if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE)
#if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE) || \
defined(CONFIG_FB_DM) || defined(CONFIG_FB_DM_MODULE)
&davinci_fb_device,
#endif
#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
......
......@@ -22,7 +22,8 @@
* Silicon Image SIL9034 HDMI driver.
*
* REVISION:
* 1) Initial creation. --------------------------------- 2007-11-13 JChen
* 1) Initial creation. --------------------------------- 2008-06-13 JChen
* 2) I2c control interface. ---------------------------- 2008-06-23 JChen
*
*/
......@@ -38,6 +39,7 @@
#include <linux/jiffies.h>
#include <linux/poll.h>
#include <linux/workqueue.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
......@@ -58,6 +60,7 @@
#define I2C_RETRY_COUNT 3
#define MOD_DESC "Sil9034 HDMI Driver (c) 2007"
#define SIL9034_HDMI_NAME "sil9034hdmi"
/* Si9034 use 2 i2c to control the chip 0x39 & 0x3A */
#define SLAVE_SIZE 2
#define TIMER_JIFFIES (1 * HZ)
......@@ -66,10 +69,16 @@
#define SIL9034_TIMER 1
#define SIL9034_SCHED 1
/* YCBCR MODE */
#define YCBCR_480I 0
#define YCBCR_480P 0
#define YCBCR_720P 1
/* Silicon Image provide 2 slave address to control. */
static int slave_num = 0 ;
static int sil9034_attach_adapter(struct i2c_adapter * adapter);
static int sil9034_detach_client(struct i2c_client * client);
static struct input_dev *sil9034_hdmi_dev;
static unsigned short normal_i2c[] = {
/* Jchen: should probe this address if real physical device is mount */
......@@ -81,6 +90,54 @@ static unsigned short normal_i2c[] = {
/* Macro need by addr_data */
I2C_CLIENT_INSMOD;
/* bus mapping struct */
typedef struct bus_mapping_sil9034
{
u8 bus_reg ;
u16 value ;
} bus_mapping_sil9034 ;
/* bus mapping for 480p YCbCr 4:2:2 Separate Sync Input*/
bus_mapping_sil9034 sil9034_480p_setting[] =
{
{DE_CTRL_ADDR,0x41},
{DE_DELAY_ADDR,0x04},
{DE_TOP_ADDR,0x19},
{DE_CNTH_ADDR,0x5},
{DE_CNTL_ADDR,0x00},
{DEL_H_ADDR,0x2},
{DEL_L_ADDR,0xD0},
{TX_VID_CTRL_ADDR,0x20},
{TX_VID_MODE_ADDR,0x00}
};
/* bus mapping for 720p YCbCr 4:2:2 Separate Sync Input*/
bus_mapping_sil9034 sil9034_720p_setting[] =
{
{DE_CTRL_ADDR,0x41},
{DE_DELAY_ADDR,0x04},
{DE_TOP_ADDR,0x19},
{DE_CNTH_ADDR,0x5},
{DE_CNTL_ADDR,0x00},
{DEL_H_ADDR,0x2},
{DEL_L_ADDR,0xD0},
{TX_VID_CTRL_ADDR,0x20},
{TX_VID_MODE_ADDR,0x00}
};
/* bus mapping for 1080i YCbCr 4:2:2 Separate Sync Input*/
bus_mapping_sil9034 sil9034_1080i_setting[] =
{
{DE_CTRL_ADDR,0x41},
{DE_DELAY_ADDR,0x04},
{DE_TOP_ADDR,0x19},
{DE_CNTH_ADDR,0x5},
{DE_CNTL_ADDR,0x00},
{DEL_H_ADDR,0x2},
{DEL_L_ADDR,0xD0},
{TX_VID_CTRL_ADDR,0x20},
{TX_VID_MODE_ADDR,0x00}
};
/* i2c private data */
typedef struct davinci6446_sil9034
{
......@@ -92,7 +149,11 @@ typedef struct davinci6446_sil9034
struct timer_list timer ;
#endif
spinlock_t lock;
/* pointer to different setting according to system */
bus_mapping_sil9034 *sil9034_setting ;
unsigned char sil9034_setting_num ;
} davinci6446_sil9034 ;
static davinci6446_sil9034 ds ;
static struct i2c_driver sil9034_driver = {
......@@ -105,9 +166,42 @@ static struct i2c_driver sil9034_driver = {
.attach_adapter = &sil9034_attach_adapter,
.detach_client = &sil9034_detach_client,
};
static const char * pname = "SIL9034 HDMI Driver" ;
static int sil9034_fops_open(struct inode * inode, struct file * file)
{
return 0 ;
}
static ssize_t sil9034_fops_read(struct file *filp, char __user *buff, size_t count, loff_t *ppos)
{
return 0 ;
}
static int sil9034_fops_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
default:
return -EINVAL;
}
return 0 ;
}
static struct file_operations sil9034_fops = {
.open = sil9034_fops_open,
.ioctl = sil9034_fops_ioctl,
.read = sil9034_fops_read,
};
static struct miscdevice hdmi_dev = {
MISC_DYNAMIC_MINOR,
SIL9034_HDMI_NAME,
&sil9034_fops
};
static int sil9034_detect_client(struct i2c_adapter * adapter, int address, int kind)
{
int ret = 0;
......@@ -208,8 +302,8 @@ static int sil9034_write(davinci6446_sil9034 *priv,u8 slave,u8 reg, u16 value)
}
/* JChen: this should be call by others driver or
* create new char dev to ioctl the control.
*/
EXPORT_SYMBOL(sil9034_write);
*/
static int sil9034_read(davinci6446_sil9034 *priv,u8 slave,u8 reg)
{
......@@ -230,7 +324,7 @@ static int sil9034_read(davinci6446_sil9034 *priv,u8 slave,u8 reg)
else
return 0xff;
}
EXPORT_SYMBOL(sil9034_read);
//EXPORT_SYMBOL(sil9034_read);
//-------------------------- INIT / EXIT ---------------------------------------------------------
static int sil9034_chipInfo(davinci6446_sil9034 *priv)
......@@ -329,26 +423,6 @@ static int sil9034_cea861InfoFrameControl2(davinci6446_sil9034 *priv,u8 enable)
return 0 ;
}
static int sil9034_switchClock2M48X1(davinci6446_sil9034 *priv,u8 enable)
{
sil9034_dbg("----------%s----------\n",__FUNCTION__) ;
#if 0
outw((inw(IO_CLK_MOD2) & (~(0x1000))), IO_CLK_MOD2); /* disable I2C clock first */
outw((inw(IO_CLK_DIV4) | 0x01F | 0x0C00), IO_CLK_DIV4);
outw((inw(IO_CLK_MOD2) | 0x1000), IO_CLK_MOD2); /* re-enable I2C clock */
if(enable)
{
/* use M48X1 */
outw((inw(IO_CLK_SEL0) | 0x0000), IO_CLK_SEL0); /* select M48X1 */
}
else
{
/* Use PLLB, MSP430 need this */
outw((inw(IO_CLK_SEL0) | 0x0C00), IO_CLK_SEL0); /* select PLLB */
}
#endif
return 0 ;
}
static int sil9034_cea861InfoFrameSetting(davinci6446_sil9034 *priv)
{
......@@ -537,84 +611,13 @@ static int sil9034_hdmiHdcpConfig(davinci6446_sil9034 *priv,u8 enable)
return 0 ;
}
static int sil9034_videoInputConfig(davinci6446_sil9034 *priv)
static int sil9034_480i_VideoInputConfig(davinci6446_sil9034 *priv)
{
/* Input Mode YCbCr 4:2:2 Mux YC Separate Syncs */
/* Output Mode YcbCr 4:2:2 */
u8 reg_value ;
u8 reg_value = 0 ;
sil9034_dbg("----------%s----------\n",__FUNCTION__) ;
#if 0
/* 480i Muxed YcbCr 4:2:2 Embedded Sync Input */
/* Video DE control register : DE_DLY 3:0=0
* HS_POL 4 = 1
* VS_POL 5 = 1
* DE_GEN 6 = 0
*/
reg_value = sil9034_read(priv,SLAVE0,DE_CTRL_ADDR) ;
sil9034_write(priv,SLAVE0,DE_CTRL_ADDR,(reg_value|0x30)) ;
//sil9034_write(priv,SLAVE0,DE_CTRL_ADDR,(reg_value|0x40)) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CTRL_ADDR) ;
sil9034_dbg("Video DE control register 0x%x = 0x%x\n",DE_CTRL_ADDR,reg_value) ;
/* Create Hsync 1 pulse */
sil9034_write(priv,SLAVE0,HBIT_2HSYNC1,0x13) ;
reg_value = sil9034_read(priv,SLAVE0,HBIT_2HSYNC1) ;
sil9034_dbg("Video hbit 2 sync 1 register 0x%x = 0x%x\n",HBIT_2HSYNC1,reg_value) ;
/* Create Hsync 2 pulse */
reg_value = sil9034_read(priv,SLAVE0,HBIT_2HSYNC2) ;
sil9034_write(priv,SLAVE0,HBIT_2HSYNC2,reg_value & ~(0x3)) ;
reg_value = sil9034_read(priv,SLAVE0,HBIT_2HSYNC2) ;
sil9034_dbg("Video hbit 2 sync 2 register 0x%x = 0x%x\n",HBIT_2HSYNC2,reg_value) ;
/* Determines VSYNC pixel offset low register */
reg_value = sil9034_read(priv,SLAVE0,FIELD2_HSYNC_OFFSETL_ADDR) ;
sil9034_write(priv,SLAVE0,FIELD2_HSYNC_OFFSETL_ADDR,(reg_value|0xAD)) ;
reg_value = sil9034_read(priv,SLAVE0,FIELD2_HSYNC_OFFSETL_ADDR) ;
sil9034_dbg("Video sync pixel offset low register 0x%x = 0x%x\n",FIELD2_HSYNC_OFFSETL_ADDR,reg_value) ;
/* Determines VSYNC pixel offset high register */
reg_value = sil9034_read(priv,SLAVE0,FIELD2_HSYNC_OFFSETH_ADDR) ;
sil9034_write(priv,SLAVE0,FIELD2_HSYNC_OFFSETH_ADDR,(reg_value|0x1)) ;
reg_value = sil9034_read(priv,SLAVE0,FIELD2_HSYNC_OFFSETH_ADDR) ;
sil9034_dbg("Video sync pixel offset low register 0x%x = 0x%x\n",FIELD2_HSYNC_OFFSETH_ADDR,reg_value) ;
/* Video Hsync 1 Length register */
reg_value = sil9034_read(priv,SLAVE0,HLENGTH1_ADDR) ;
sil9034_write(priv,SLAVE0,HLENGTH1_ADDR,(reg_value|0x3E)) ;
reg_value = sil9034_read(priv,SLAVE0,HLENGTH1_ADDR) ;
sil9034_dbg("Video hsync length 1 register 0x%x = 0x%x\n",HLENGTH1_ADDR,reg_value) ;
/* Video Hsync 2 Length register */
reg_value = sil9034_read(priv,SLAVE0,HLENGTH2_ADDR) ;
sil9034_write(priv,SLAVE0,HLENGTH2_ADDR,(reg_value & ~(0x7))) ;
reg_value = sil9034_read(priv,SLAVE0,HLENGTH2_ADDR) ;
sil9034_dbg("Video hsync length 2 register 0x%x = 0x%x\n",HLENGTH2_ADDR,reg_value) ;
/* Video Vbit to VSYNC register */
reg_value = sil9034_read(priv,SLAVE0,VBIT_TO_VSYNC_ADDR) ;
sil9034_write(priv,SLAVE0,VBIT_TO_VSYNC_ADDR,(reg_value | 0x04)) ;
reg_value = sil9034_read(priv,SLAVE0,VBIT_TO_VSYNC_ADDR) ;
sil9034_dbg("Video Vbit to VSYNC register 0x%x = 0x%x\n",VBIT_TO_VSYNC_ADDR,reg_value) ;
/* Video VSYNC length register */
reg_value = sil9034_read(priv,SLAVE0,VLENGTH_ADDR) ;
sil9034_write(priv,SLAVE0,VLENGTH_ADDR,(reg_value | 0x03)) ;
reg_value = sil9034_read(priv,SLAVE0,VLENGTH_ADDR) ;
sil9034_dbg("Video VSYNC length register 0x%x = 0x%x\n",VLENGTH_ADDR,reg_value) ;
/* Video control register , ICLK = 00 EXTN = 1*/
reg_value = sil9034_read(priv,SLAVE0,TX_VID_CTRL_ADDR) ;
sil9034_write(priv,SLAVE0,TX_VID_CTRL_ADDR,(reg_value | 0x20)) ;
reg_value = sil9034_read(priv,SLAVE0,TX_VID_CTRL_ADDR) ;
sil9034_dbg("Video control register 0x%x = 0x%x\n",TX_VID_CTRL_ADDR,reg_value) ;
/* Video mode register , SYNCEXT=1 DEMUX=1 UPSMP=0 CSC=0 DITHER = 0*/
sil9034_write(priv,SLAVE0,TX_VID_MODE_ADDR,0x2) ;
reg_value = sil9034_read(priv,SLAVE0,TX_VID_MODE_ADDR) ;
sil9034_dbg("Video mode register 0x%x = 0x%x\n",TX_VID_MODE_ADDR,reg_value) ;
#else
/* 480i YCbCr 4:2:2 Mux YC Separate Sync Input */
/* Video DE control register : DE_DLY 3:0=0x0
* HS_POL 4 = 1
......@@ -672,7 +675,138 @@ static int sil9034_videoInputConfig(davinci6446_sil9034 *priv)
sil9034_write(priv,SLAVE0,TX_VID_MODE_ADDR,0x2) ;
reg_value = sil9034_read(priv,SLAVE0,TX_VID_MODE_ADDR) ;
sil9034_dbg("Video mode register 0x%x = 0x%x\n",TX_VID_MODE_ADDR,reg_value) ;
#endif
return 0 ;
}
static int sil9034_720p_VideoInputConfig(davinci6446_sil9034 *priv)
{
/* Output Mode YcbCr 4:2:2 */
u8 reg_value = 0 ;
sil9034_dbg("----------%s----------\n",__FUNCTION__) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CTRL_ADDR) ;
sil9034_write(priv,SLAVE0,DE_CTRL_ADDR,(reg_value|0x41)) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CTRL_ADDR) ;
sil9034_dbg("Video DE control register 0x%x = 0x%x\n",DE_CTRL_ADDR,reg_value) ;
/* Video DE delay register */
sil9034_write(priv,SLAVE0,DE_DELAY_ADDR,0x04) ;
reg_value = sil9034_read(priv,SLAVE0,DE_DELAY_ADDR) ;
sil9034_dbg("Video DE delay register 0x%x = 0x%x\n",DE_DELAY_ADDR,reg_value) ;
/* Video DE top register */
reg_value = sil9034_read(priv,SLAVE0,DE_TOP_ADDR) ;
sil9034_write(priv,SLAVE0,DE_TOP_ADDR,reg_value|0x19) ;
reg_value = sil9034_read(priv,SLAVE0,DE_TOP_ADDR) ;
sil9034_dbg("Video DE top register 0x%x = 0x%x\n",DE_TOP_ADDR,reg_value) ;
/* Video DE cnt high byte register */
reg_value = sil9034_read(priv,SLAVE0,DE_CNTH_ADDR) ;
sil9034_write(priv,SLAVE0,DE_CNTH_ADDR,(reg_value | 0x5)) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CNTH_ADDR) ;
sil9034_dbg("Video DE cnt high register 0x%x = 0x%x\n",DE_CNTH_ADDR,reg_value) ;
/* Video DE cnt low byte register */
sil9034_write(priv,SLAVE0,DE_CNTL_ADDR,0x00) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CNTL_ADDR) ;
sil9034_dbg("Video DE cnt low register 0x%x = 0x%x\n",DE_CNTL_ADDR,reg_value) ;
/* Video DE line high byte register */
sil9034_write(priv,SLAVE0,DEL_H_ADDR,0x2) ;
reg_value = sil9034_read(priv,SLAVE0,DEL_H_ADDR) ;
sil9034_dbg("Video DE line high register 0x%x = 0x%x\n",DEL_H_ADDR,reg_value) ;
/* Video DE line low byte register */
sil9034_write(priv,SLAVE0,DEL_L_ADDR,0xD0) ;
reg_value = sil9034_read(priv,SLAVE0,DEL_L_ADDR) ;
sil9034_dbg("Video DE line high register 0x%x = 0x%x\n",DEL_L_ADDR,reg_value) ;
/* Video control register , ICLK = 00 EXTN = 1*/
reg_value = sil9034_read(priv,SLAVE0,TX_VID_CTRL_ADDR) ;
sil9034_write(priv,SLAVE0,TX_VID_CTRL_ADDR,(reg_value|0x20)) ;
reg_value = sil9034_read(priv,SLAVE0,TX_VID_CTRL_ADDR) ;
sil9034_dbg("Video control register 0x%x = 0x%x\n",TX_VID_CTRL_ADDR,reg_value) ;
/* Video mode register , SYNCEXT=0 DEMUX=0 UPSMP=0 CSC=0 DITHER = 0*/
sil9034_write(priv,SLAVE0,TX_VID_MODE_ADDR,0x0) ;
reg_value = sil9034_read(priv,SLAVE0,TX_VID_MODE_ADDR) ;
sil9034_dbg("Video mode register 0x%x = 0x%x\n",TX_VID_MODE_ADDR,reg_value) ;
return 0 ;
}
static int sil9034_Auto_VideoInputConfig(davinci6446_sil9034 *priv)
{
u8 reg_value = 0 ;
u8 count = 0 ;
/* Auto setting by the bus_mapping_sil9034 struct */
for(count=0 ;count<(priv->sil9034_setting_num) ;count++)
{
reg_value = sil9034_read(priv,SLAVE0,\
priv->sil9034_setting[count].bus_reg) ;
sil9034_write(priv,SLAVE0,priv->sil9034_setting[count].bus_reg,\
(reg_value|priv->sil9034_setting[count].value)) ;
reg_value = sil9034_read(priv,SLAVE0,\
priv->sil9034_setting[count].bus_reg) ;
sil9034_dbg("bus mapping regster 0x%x = 0x%x\n",\
priv->sil9034_setting[count].bus_reg,reg_value) ;
}
return 0 ;
}
static int sil9034_480p_VideoInputConfig(davinci6446_sil9034 *priv)
{
/* Output Mode YcbCr 4:2:2 */
u8 reg_value = 0 ;
sil9034_write(priv,SLAVE0,DE_CTRL_ADDR,0x70) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CTRL_ADDR) ;
sil9034_dbg("Video DE control register 0x%x = 0x%x\n",DE_CTRL_ADDR,reg_value) ;
/* Video DE delay register */
sil9034_write(priv,SLAVE0,DE_DELAY_ADDR,0x7A) ;
reg_value = sil9034_read(priv,SLAVE0,DE_DELAY_ADDR) ;
sil9034_dbg("Video DE delay register 0x%x = 0x%x\n",DE_DELAY_ADDR,reg_value) ;
/* Video DE top register */
sil9034_write(priv,SLAVE0,DE_TOP_ADDR,0x24) ;
reg_value = sil9034_read(priv,SLAVE0,DE_TOP_ADDR) ;
sil9034_dbg("Video DE top register 0x%x = 0x%x\n",DE_TOP_ADDR,reg_value) ;
/* Video DE cnt high byte register */
reg_value = sil9034_read(priv,SLAVE0,DE_CNTH_ADDR) ;
sil9034_write(priv,SLAVE0,DE_CNTH_ADDR,(reg_value|0x2)) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CNTH_ADDR) ;
sil9034_dbg("Video DE cnt high register 0x%x = 0x%x\n",DE_CNTH_ADDR,reg_value) ;
/* Video DE cnt low byte register */
sil9034_write(priv,SLAVE0,DE_CNTL_ADDR,0xD0) ;
reg_value = sil9034_read(priv,SLAVE0,DE_CNTL_ADDR) ;
sil9034_dbg("Video DE cnt low register 0x%x = 0x%x\n",DE_CNTL_ADDR,reg_value) ;
/* Video DE line high byte register */
reg_value = sil9034_read(priv,SLAVE0,DEL_H_ADDR) ;
sil9034_write(priv,SLAVE0,DEL_H_ADDR,(reg_value|0x1)) ;
reg_value = sil9034_read(priv,SLAVE0,DEL_H_ADDR) ;
sil9034_dbg("Video DE line high register 0x%x = 0x%x\n",DEL_H_ADDR,reg_value) ;
/* Video DE line low byte register */
sil9034_write(priv,SLAVE0,DEL_L_ADDR,0xE0) ;
reg_value = sil9034_read(priv,SLAVE0,DEL_L_ADDR) ;
sil9034_dbg("Video DE line high register 0x%x = 0x%x\n",DEL_L_ADDR,reg_value) ;
/* Video control register , ICLK = 00 EXTN = 1*/
sil9034_write(priv,SLAVE0,TX_VID_CTRL_ADDR,0x20) ;
reg_value = sil9034_read(priv,SLAVE0,TX_VID_CTRL_ADDR) ;
sil9034_dbg("Video control register 0x%x = 0x%x\n",TX_VID_CTRL_ADDR,reg_value) ;
/* Video mode register , SYNCEXT=0 DEMUX=0 UPSMP=0 CSC=0 DITHER = 0*/
sil9034_write(priv,SLAVE0,TX_VID_MODE_ADDR,0x0) ;
reg_value = sil9034_read(priv,SLAVE0,TX_VID_MODE_ADDR) ;
sil9034_dbg("Video mode register 0x%x = 0x%x\n",TX_VID_MODE_ADDR,reg_value) ;
return 0 ;
}
......@@ -822,7 +956,9 @@ int sil9034_dumpInterruptStateStatus(davinci6446_sil9034 *priv)
/* HDCP key exchange for hdmi */
static void sil9034_timer(unsigned long data)
{
#if SIL9034_SCHED
int status;
#endif
davinci6446_sil9034 *priv = (void *)data ;
if(priv)
......@@ -848,7 +984,7 @@ static void sil9034_sched(void *data)
//sil9034_dumpSystemStatus(priv) ;
//sil9034_dumpDataCtrlStatus(priv) ;
//sil9034_dumpInterruptStateStatus(priv) ;
//sil9034_dumpVideoConfigureStatus(priv) ;
sil9034_dumpVideoConfigureStatus(priv) ;
#if SIL9034_TIMER
mod_timer(&ds.timer, jiffies + TIMER_JIFFIES);
#endif
......@@ -868,50 +1004,56 @@ static int __init sil9034_init(void)
printk(KERN_INFO "%s Couldn't register SIL9034 I2C driver.\n", pname);
goto out;
}
/* Init the priv data
ds.sil9034_setting = &sil9034_720p_setting ;
ds.sil9034_setting_num = \
sizeof(sil9034_720p_setting)/sizeof(bus_mapping_sil9034) ;
*/
/* read chip id & revision */
sil9034_chipInfo(&ds) ;
/* power down occilator */
sil9034_powerDown(&ds,ENABLE) ;
#if 0
/* Tune the video input table according to DM320 hardware spec */
sil9034_videoInputConfig() ;
sil9034_720p_VideoInputConfig(&ds) ;
/* Tune the audio input table according to DM320 hardware spec */
sil9034_audioInputConfig() ;
sil9034_audioInputConfig(&ds) ;
/* software reset */
sil9034_swReset() ;
sil9034_swReset(&ds) ;
/* power up occilator */
sil9034_powerDown(DISABLE) ;
sil9034_powerDown(&ds,DISABLE) ;
/* unmask the interrupt status */
sil9034_unmaskInterruptStatus() ;
sil9034_unmaskInterruptStatus(&ds) ;
/* Hdmi output setting */
sil9034_hdmiOutputConfig() ;
sil9034_hdmiOutputConfig(&ds) ;
/* TMDS control register */
sil9034_hdmiTmdsConfig() ;
sil9034_hdmiTmdsConfig(&ds) ;
/* ddc master config */
sil9034_ddcSetting() ;
sil9034_ddcSetting(&ds) ;
/* HDCP control handshaking */
sil9034_hdmiHdcpConfig(DISABLE) ;
sil9034_hdmiHdcpConfig(&ds,DISABLE) ;
/* enable the avi repeat transmission */
sil9034_cea861InfoFrameControl1(ENABLE) ;
//sil9034_cea861InfoFrameControl2(ENABLE) ;
sil9034_cea861InfoFrameControl1(&ds,ENABLE) ;
//sil9034_cea861InfoFrameControl2(&ds,ENABLE) ;
/* CEA-861 Info Frame control setting */
sil9034_cea861InfoFrameSetting() ;
sil9034_cea861InfoFrameSetting(&ds) ;
/* Audio Info Frame control setting */
sil9034_audioInfoFrameSetting() ;
#endif
sil9034_audioInfoFrameSetting(&ds) ;
#if SIL9034_SCHED
INIT_WORK(&ds.work, sil9034_sched);
#endif
......@@ -924,6 +1066,13 @@ static int __init sil9034_init(void)
add_timer(&ds.timer);
#endif
/* register a device node for user to setting the HDMI param */
status = misc_register(&hdmi_dev);
if (status)
{
printk(KERN_ERR "%s-Couldn't register device\n",pname);
goto out ;
}
out:
return status;
}
......@@ -932,6 +1081,7 @@ static void __exit sil9034_exit(void)
{
sil9034_dbg("----------%s----------\n",__FUNCTION__) ;
i2c_del_driver(&sil9034_driver);
misc_deregister(&hdmi_dev);
}
MODULE_AUTHOR("Neuros");
......
......@@ -1857,6 +1857,10 @@ if ARCH_OMAP
source "drivers/video/omap/Kconfig"
endif
if ARCH_DAVINCI
source "drivers/video/dm/Kconfig"
endif
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
......
......@@ -121,6 +121,7 @@ obj-$(CONFIG_FB_IMAC) += imacfb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_OMAP) += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_DM) += dm/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_DAVINCI) += davincifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
# the test framebuffer is last
......
config FB_DM
tristate "DM frame buffer support (EXPERIMENTAL)"
depends on FB
help
Frame buffer driver for DM644X based boards.
obj-$(CONFIG_FB_DM) += dmfb.o
dmfb-y := dm_main.o
/*
* drivers/video/davincifb.c
*
* Framebuffer driver for Texas Instruments DaVinci display controller.
*
* Copyright (C) 2006 Texas Instruments, Inc.
* Rishi Bhattacharya <support@ti.com>
*
* Leveraged from the framebuffer driver for OMAP24xx
* written by Andy Lowe (source@mvista.com)
* Copyright (C) 2004 MontaVista Software, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
/*
* TODO:
*
* + Make the module load/unload *DONE*
* + Add support to change resolution at runtime *DONE*
* + Add support for different bpp per plane *DONE*
* + Remove all the dobule/triple buffering thing, make it variable based on
* + Add support to change video output at runtime *DONE*
* + Add support to list avilable modes
* the virtual size, support only multiple of real res (2x, 3x, 4x, etc)
* + Changing the resolution on vid0 should change the output size too
* + x and y aren't reserved[0] or reserved[1], fix all referecnes to it
* + The hardware has several bugs, use defines to handle that, current chips
* i own are revision 1.3
* + Rename all window functions to be on the same form
* + Split the check_var we might need to add more unsupported cases and that
* function is getting big
* + Remove dparams completely and redo the parser of the parameters, also
* add module parameters
*
* Notes:
* + Every framebuffer but the vid0 can have a size different to the output size
* + Chaing thr size on vid0 will change the output clocks
* + The memory is already allocated
* + To change the output port (composite, component, whatever) just do a
* echo X > /sys/class/video_output/venc where X can be a number from the enum
* at davincifb.h Note that for some output modes, some ports might not be
* available, like 720p over composite
*/
#define DEBUG
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/video_output.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/arch/hardware.h>
#include <video/davincifb.h>
#include <asm/system.h>
#ifdef CONFIG_THS8200
#include <asm/arch/davinci-ths8200.h>
#endif /* CONFIG_THS8200 */
#define MODULE_NAME "davincifb"
#if 0
/* Output Format Selection */
#define MULTIPLE_BUFFERING 1
#ifdef MULTIPLE_BUFFERING
#define DOUBLE_BUF 2
#define TRIPLE_BUF 3
#else
#define DOUBLE_BUF 1
#define TRIPLE_BUF 1
#endif
#endif
/* needed prototypes */
static int davincifb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);
static int davincifb_set_par(struct fb_info *info);
static struct fb_ops davincifb_ops;
/*============================================================================*
* Display controller register I/O routines *
*============================================================================*/
/*
* Read a register
*/
static __inline__ u32 dispc_reg_in(u32 offset)
{
return inl(offset);
}
/*
* Write a register
*/
static __inline__ u32 dispc_reg_out(u32 offset, u32 val)
{
outl(val, offset);
return val;
}
/*
* Write a register and merge it with the current value
*/
static __inline__ u32 dispc_reg_merge(u32 offset, u32 val, u32 mask)
{
u32 addr = offset;
u32 new_val = (inl(addr) & ~mask) | (val & mask);
outl(new_val, addr);
return new_val;
}
struct dm_win_info {
struct fb_info info;
/* X and Y position */
unsigned int x, y;
/* framebuffer area */
dma_addr_t fb_base_phys;
unsigned long fb_base;
unsigned long fb_size;
u32 pseudo_palette[17];
/* flag to identify if framebuffer area is fixed already or not */
unsigned long sdram_address;
struct dm_info *dm;
unsigned int win;
};
struct dm_info {
/* to map the registers */
dma_addr_t mmio_base_phys;
unsigned long mmio_base;
unsigned long mmio_size;
wait_queue_head_t vsync_wait;
unsigned long vsync_cnt;
int timeout;
/* this is the function that configures the output device (NTSC/PAL/LCD)
* for the required output format (composite/s-video/component/rgb)
*/
void (*output_device_config) (int on); /* FIXME, remove this */
struct device *dev;
struct dm_win_info *windows[DAVINCIFB_WINDOWS];
unsigned int windows_mask;
struct output_device *output;
unsigned int output_sel;
};
/* Random value chosen for now. Should be within the panel's supported range */
#define LCD_PANEL_CLOCK 180000
/* All window widths have to be rounded up to a multiple of 32 bytes */
/* The DAVINCIFB_WIN_OSD0 window has to be always within DAVINCIFB_WIN_VID0. Plus, since it is in RGB565
* mode, it _cannot_ overlap with DAVINCIFB_WIN_VID1.
* For defaults, we are setting the DAVINCIFB_WIN_OSD0 window to be displayed in the top
* left quadrant of the screen, and the DAVINCIFB_WIN_VID1 in the bottom right quadrant.
* So the default 'xres' and 'yres' are set to half of the screen width and
* height respectively. Note however that the framebuffer size is allocated
* for the full screen size so the user can change the 'xres' and 'yres' by
* using the FBIOPUT_VSCREENINFO ioctl within the limits of the screen size.
*/
#define round_32(width) ((((width) + 31) / 32) * 32 )
/* get FB window buffer size */
static inline int fb_window_size(int width, int height, int bufnum)
{
return round_32(width * 16 / 8) * height * bufnum;
}
static char *dm_win_names[DAVINCIFB_WINDOWS] = {
[DAVINCIFB_WIN_OSD0] = "dm_osd0_fb",
[DAVINCIFB_WIN_OSD1] = "dm_osd1_fb",
[DAVINCIFB_WIN_VID0] = "dm_vid0_fb",
[DAVINCIFB_WIN_VID1] = "dm_vid1_fb"
};
static struct fb_var_screeninfo dm_default_var[DAVINCIFB_WINDOWS] = {
/* the max mode allowed on osd0 should be 720p x 2 buffers
* which is 1843200 pixels at 16bpp (1280*720*2)
*/
[DAVINCIFB_WIN_OSD0] = {
.xres = 720,
.yres = 480,
.xres_virtual = 720,
.yres_virtual = 2560,
.bits_per_pixel = 16,
.activate = FB_ACTIVATE_NOW,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.vmode = FB_VMODE_INTERLACED,
},
[DAVINCIFB_WIN_OSD1] = {
.xres = 320,
.yres = 240,
.xres_virtual = 320,
.yres_virtual = 240,
.bits_per_pixel = 4,
.activate = FB_ACTIVATE_NOW,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.vmode = FB_VMODE_INTERLACED,
},
/* the max mode allowed on vid0 should be 1080i x 3 buffers
* which is 6220800 pixels at 16 bpp (1920*1080*3)
*/
[DAVINCIFB_WIN_VID0] = {
.xres = 720,
.yres = 480,
.xres_virtual = 720,
.yres_virtual = 8640,
.bits_per_pixel = 16,
.activate = FB_ACTIVATE_NOW,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.vmode = FB_VMODE_INTERLACED,
},
[DAVINCIFB_WIN_VID1] = {
.xres = 720,
.yres = 480,
.xres_virtual = 720,
.yres_virtual = 480,
.bits_per_pixel = 16,
.activate = FB_ACTIVATE_NOW,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.vmode = FB_VMODE_INTERLACED,
}
};
static inline int is_win(const struct dm_win_info *w, unsigned int win)
{
if (w->win == win)
return 1;
else
return 0;
}
#define x_pos(w) ((w)->x)
#define y_pos(w) ((w)->y)
/* TODO remove this static default vars */
#define BASEX 0x80
#define BASEY 0x12
#define DISP_XRES 720
#define DISP_YRES 480
#define DISP_MEMY 576
#define BASEX480P 0x50
#define BASEY480P 0x5
#define DISP_XRES480P 720
#define DISP_YRES480P 480
#define BASEX720P 0x50
#define BASEY720P 0x5
#define DISP_XRES720P 1280
#define DISP_YRES720P 720
#define DISP_MEMY720P 720
#define BASEX1080I 0x58
#define BASEY1080I 0x5
#define DISP_XRES1080I 1920
#define DISP_YRES1080I 1080
#define DISP_MEMY1080I 1080
#if 0
#define OSD0_XRES round_32((DISP_XRES)*16/8) * 8/16 /* pixels */
#define OSD0_YRES DISP_YRES
#define OSD0_FB_PHY 0
#define OSD0_FB_SIZE (round_32((DISP_XRES)*16/8) * DISP_MEMY * DOUBLE_BUF)
/* 16 bpp, Double buffered */
static struct fb_var_screeninfo osd0_default_var = {
.xres = OSD0_XRES,
.yres = OSD0_YRES,
.xres_virtual = OSD0_XRES,
.yres_virtual = OSD0_YRES * DOUBLE_BUF,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = 16,
.grayscale = 0,
.red = {11, 5, 0},
.green = {5, 6, 0},
.blue = {0, 5, 0},
.transp = {0, 0, 0},
.nonstd = 0,
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.accel_flags = 0,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.left_margin = 40, /* pixclocks */
.right_margin = 4, /* pixclocks */
.upper_margin = 8, /* line clocks */
.lower_margin = 2, /* line clocks */
.hsync_len = 4, /* pixclocks */
.vsync_len = 2, /* line clocks */
.sync = 0,
.vmode = FB_VMODE_INTERLACED,
};
/* Using the full screen for DAVINCIFB_WIN_OSD1 by default */
#define OSD1_XRES round_32(DISP_XRES*4/8) * 8/4 /* pixels */
#define OSD1_YRES DISP_YRES
#define OSD1_FB_PHY 0
#define OSD1_FB_SIZE (round_32(DISP_XRES*4/8) * DISP_MEMY * DOUBLE_BUF)
static struct fb_var_screeninfo osd1_default_var = {
.xres = DISP_XRES,
.yres = OSD1_YRES,
.xres_virtual = OSD1_XRES,
.yres_virtual = OSD1_YRES * DOUBLE_BUF,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = 4,
.activate = FB_ACTIVATE_NOW,
.accel_flags = 0,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.vmode = FB_VMODE_INTERLACED,
};
/* Using the full screen for DAVINCIFB_WIN_OSD0 by default */
#define VID0_XRES round_32(DISP_XRES*16/8) * 8/16 /* pixels */
#define VID0_YRES DISP_YRES
#define VID0_FB_PHY 0
#define VID0_FB_SIZE (round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF)
static struct fb_var_screeninfo vid0_default_var = {
.xres = VID0_XRES,
.yres = VID0_YRES,
.xres_virtual = VID0_XRES,
.yres_virtual = VID0_YRES * TRIPLE_BUF,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = 16,
.activate = FB_ACTIVATE_NOW,
.accel_flags = 0,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.vmode = FB_VMODE_INTERLACED,
};
/* Using the bottom right quadrant of the screen screen for DAVINCIFB_WIN_VID1 by default,
* but keeping the framebuffer allocated for the full screen, so the user can
* change the 'xres' and 'yres' later using the FBIOPUT_VSCREENINFO ioctl.
*/
#define VID1_BPP 16 /* Video1 can be in YUV or RGB888 format */
#define VID1_XRES round_32(DISP_XRES*16/8) * 8/16 /* pixels */
#define VID1_YRES DISP_YRES
#define VID1_FB_PHY 0
#define VID1_FB_SIZE (round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF)
static struct fb_var_screeninfo vid1_default_var = {
.xres = VID1_XRES,
.yres = VID1_YRES,
.xres_virtual = VID1_XRES,
.yres_virtual = VID1_YRES * TRIPLE_BUF,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = VID1_BPP,
.activate = FB_ACTIVATE_NOW,
.accel_flags = 0,
.pixclock = LCD_PANEL_CLOCK, /* picoseconds */
.vmode = FB_VMODE_INTERLACED,
};
#endif
static struct dmparams_t {
u8 output;
u8 format;
u8 windows; /* bitmap flag based on DAVINCIFB_WIN_VID0, DAVINCIFB_WIN_VID1, DAVINCIFB_WIN_OSD0, DAVINCIFB_WIN_OSD1
* definitions in header file */
u32 vid0_xres;
u32 vid0_yres;
u32 vid0_xpos;
u32 vid0_ypos;
u32 vid1_xres;
u32 vid1_yres;
u32 vid1_xpos;
u32 vid1_ypos;
u32 osd0_xres;
u32 osd0_yres;
u32 osd0_xpos;
u32 osd0_ypos;
u32 osd1_xres;
u32 osd1_yres;
u32 osd1_xpos;
u32 osd1_ypos;
u32 vid0_phys;
u32 vid1_phys;
u32 osd0_phys;
u32 osd1_phys;
} dmparams = {
NTSC, /* output */
COMPOSITE, /* format */
(1 << DAVINCIFB_WIN_VID0) | (1 << DAVINCIFB_WIN_VID1) | (1 << DAVINCIFB_WIN_OSD0) | (1 << DAVINCIFB_WIN_OSD1),
/* windows registered */
720, 480, 0, 0, /* vid0 size and position */
720, 480, 0, 0, /* vid1 size and position */
720, 480, 0, 0, /* osd0 size and position */
720, 480, 0, 0, /* osd1 size and position */
#if 0
VID0_FB_PHY,
VID1_FB_PHY,
OSD0_FB_PHY,
OSD1_FB_PHY,
#endif
};
static const struct fb_videomode dm_modedb[] = {
/* name, refresh, xres, yres, pixclock, left_margin, right_margin
* upper_margin, lower_margin, hsync_len, vsync_len, sync,
* vmode, flag
*/
/* 576i*/
{ "576i", 50, 720, 576, 0, 0, 0, 0, 0, 0, FB_SYNC_BROADCAST,
FB_VMODE_INTERLACED},
};
/*============================================================================*
* VENC interface *
*============================================================================*/
/* VOUT code */
#if 0
struct dm_vout_ops {
};
static int dm_vout_register(struct dm_vout_ops *ops)
{
/* append to the list of ops */
}
/* VENC */
struct dm_vout_ops dm_vout_venc {
};
#endif
static void enable_digital_output(bool on)
{
if (on) {
/* Set PINMUX0 reg to enable LCD
(all other settings are kept per u-boot) */
dispc_reg_merge(PINMUX0, PINMUX0_LOEEN, PINMUX0_LOEEN);
/* Set PCR register for FULL clock */
dispc_reg_out(VPBE_PCR, 0);
/* Enable video clock output and inverse clock polarity */
dispc_reg_out(VENC_VIDCTL,
(VENC_VIDCTL_VLCKE | VENC_VIDCTL_VLCKP));
/* Setting DRGB Matrix registers back to default values */
dispc_reg_out(VENC_DRGBX0, 0x00000400);
dispc_reg_out(VENC_DRGBX1, 0x00000576);
dispc_reg_out(VENC_DRGBX2, 0x00000159);
dispc_reg_out(VENC_DRGBX3, 0x000002cb);
dispc_reg_out(VENC_DRGBX4, 0x000006ee);
/* Enable DCLOCK */
dispc_reg_out(VENC_DCLKCTL, VENC_DCKCTL_DCKEC);
/* Set DCLOCK pattern */
dispc_reg_out(VENC_DCLKPTN0, 1);
dispc_reg_out(VENC_DCLKPTN1, 0);
dispc_reg_out(VENC_DCLKPTN2, 0);
dispc_reg_out(VENC_DCLKPTN3, 0);
dispc_reg_out(VENC_DCLKPTN0A, 2);
dispc_reg_out(VENC_DCLKPTN1A, 0);
dispc_reg_out(VENC_DCLKPTN2A, 0);
dispc_reg_out(VENC_DCLKPTN3A, 0);
dispc_reg_out(VENC_DCLKHS, 0);
dispc_reg_out(VENC_DCLKHSA, 1);
dispc_reg_out(VENC_DCLKHR, 0);
dispc_reg_out(VENC_DCLKVS, 0);
dispc_reg_out(VENC_DCLKVR, 0);
/* Enable LCD output control (accepting default polarity) */
dispc_reg_out(VENC_LCDOUT, 0x1);
/* Set brightness start position and pulse width to zero */
dispc_reg_out(VENC_BRTS, 0);
dispc_reg_out(VENC_BRTW, 0);
/* Set LCD AC toggle interval and horizontal position to zero */
dispc_reg_out(VENC_ACCTL, 0);
/* Set PWM period and width to zero */
dispc_reg_out(VENC_PWMP, 0);
dispc_reg_out(VENC_PWMW, 0);
/* Clear component and composite mode
registers (applicable to Analog DACS) */
dispc_reg_out(VENC_CVBS, 0);
dispc_reg_out(VENC_CMPNT, 0);
/* turning on horizontal and vertical syncs */
dispc_reg_out(VENC_SYNCCTL,
(VENC_SYNCCTL_SYEV|VENC_SYNCCTL_SYEH));
/* Set OSD clock and OSD Sync Adavance registers */
dispc_reg_out(VENC_OSDCLK0, 0);
dispc_reg_out(VENC_OSDCLK1, 1);
dispc_reg_out(VENC_OSDHAD, 0);
/* Enable Video Window 0 / disable video window 1 */
dispc_reg_out(OSD_VIDWINMD, OSD_VIDWINMD_ACT0);
/* Clear OSD Field Inversion for DAVINCIFB_WIN_VID0 Use */
dispc_reg_out(OSD_MODE, 0);
/* Disable DAVINCIFB_WIN_OSD0 Window */
dispc_reg_out(OSD_OSDWIN0MD, 0x00002000);
/* Disable DAVINCIFB_WIN_OSD1 Window */
dispc_reg_out(OSD_OSDWIN1MD, 0x00008000);
/* set VPSS clock */
dispc_reg_out(VPSS_CLKCTL, 0x0a);
} else {
/* Initialize the VPSS Clock Control register */
dispc_reg_out(VPSS_CLKCTL, 0x18);
/* Set PINMUX0 reg to enable LCD
(all other settings are kept per u-boot) */
dispc_reg_merge(PINMUX0, 0, PINMUX0_LOEEN);
dispc_reg_merge(PINMUX0, 0, PINMUX0_LFLDEN);
/* disable VCLK output pin enable */
dispc_reg_out(VENC_VIDCTL, 0x1101);
/* Disable output sync pins */
dispc_reg_out(VENC_SYNCCTL, 0);
/* Disable DCLOCK */
dispc_reg_out(VENC_DCLKCTL, 0);
dispc_reg_out(VENC_DRGBX1, 0x0000057C);
/* Disable LCD output control
(accepting default polarity) */
dispc_reg_out(VENC_LCDOUT, 0);
dispc_reg_out(VENC_CMPNT, 0x100);
/* Enable Video Window 1 / disable video window 0 */
dispc_reg_out(OSD_VIDWINMD, 0x302);
/* Enable OSD Field Inversion for DAVINCIFB_WIN_VID1 Use */
dispc_reg_out(OSD_MODE, 0x200);
/* Disable DAVINCIFB_WIN_OSD0 Window */
dispc_reg_out(OSD_OSDWIN0MD, 0x00002003);
/* Disable DAVINCIFB_WIN_OSD1 Window */
dispc_reg_out(OSD_OSDWIN1MD, 0x00008002);
/* Set DAVINCIFB_WIN_VID0 window origin and size */
dispc_reg_out(OSD_VIDWIN0XP, 0);
dispc_reg_out(OSD_VIDWIN0YP, 0);
dispc_reg_out(OSD_VIDWIN0XL, 0x2d0);
dispc_reg_out(OSD_VIDWIN0YL, 0xf0);
/* Set DAVINCIFB_WIN_VID1 window origin and size */
dispc_reg_out(OSD_VIDWIN1XP, 0);
dispc_reg_out(OSD_VIDWIN1YP, 0);
dispc_reg_out(OSD_VIDWIN1XL, 0x2d0);
dispc_reg_out(OSD_VIDWIN1YL, 0xf0);
/* Set DAVINCIFB_WIN_OSD0 window origin and size */
dispc_reg_out(OSD_OSDWIN0XP, 0);
dispc_reg_out(OSD_OSDWIN0YP, 0);
dispc_reg_out(OSD_OSDWIN0XL, 0x2d0);
dispc_reg_out(OSD_OSDWIN0YL, 0xf0);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_OSDWIN1XP, 0);
dispc_reg_out(OSD_OSDWIN1YP, 0);
dispc_reg_out(OSD_OSDWIN1XL, 0x2d0);
dispc_reg_out(OSD_OSDWIN1YL, 0xf0);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_CURXP, 0);
dispc_reg_out(OSD_CURYP, 0);
dispc_reg_out(OSD_CURXL, 0x2d0);
dispc_reg_out(OSD_CURYL, 0xf0);
dispc_reg_out(VENC_HSPLS, 0);
dispc_reg_out(VENC_VSPLS, 0);
dispc_reg_out(VENC_HINT, 0);
dispc_reg_out(VENC_HSTART, 0);
dispc_reg_out(VENC_HVALID, 0);
dispc_reg_out(VENC_VINT, 0);
dispc_reg_out(VENC_VSTART, 0);
dispc_reg_out(VENC_VVALID, 0);
dispc_reg_out(VENC_HSDLY, 0);
dispc_reg_out(VENC_VSDLY, 0);
dispc_reg_out(VENC_YCCCTL, 0);
dispc_reg_out(VENC_VSTARTA, 0);
/* Set OSD clock and OSD Sync Adavance registers */
dispc_reg_out(VENC_OSDCLK0, 1);
dispc_reg_out(VENC_OSDCLK1, 2);
}
}
/* slow down the VCLK to 27MHZ from
* 74MHZ */
static inline void slow_down_vclk(void)
{
/* set DCLKPTN works as the clock enable for ENC
* clock. */
outl(VENC_DCKCTL_DCKEC, VENC_DCLKCTL);
/* DCLK pattern. The specified bit pattern is output in
* resolution of ENC clock units.*/
outl(0x01, VENC_DCLKPTN0);
/* select MXI mode. Use 27 MHz (from MXI27)
* (DAC clock = 27 MHz).VPBE/Video encoder clock
* is enabled*/
outl(VPSS_CLKCTL_ENABLE_VPBE_CLK,
VPSS_CLKCTL);
}
static void davincifb_480p_component_config(int on)
{
if (on) {
#ifdef CONFIG_THS8200
/* Enable THS8200 DAC output mode as 480P */
ths8200_set_480p_mode();
#endif/* CONFIG_THS8200 */
dispc_reg_out(VENC_VMOD, 0);
/* Set new baseX and baseY */
dispc_reg_out(OSD_BASEPX, BASEX480P);
dispc_reg_out(OSD_BASEPY, BASEY480P);
/* Enable the digtal output */
enable_digital_output(true);
/* slow down the vclk as 27MHZ */
slow_down_vclk();
dispc_reg_merge(PINMUX0, 0, PINMUX0_LFLDEN);
/* Enable DAVINCIFB_WIN_OSD0 Window */
dispc_reg_out(OSD_OSDWIN0MD, 0x00002001);
/* Enable DAVINCIFB_WIN_OSD1 Window */
dispc_reg_out(OSD_OSDWIN1MD, 0x00008000);
/* Set Timing parameters for 480P frame
(must match what THS8200 expects) */
dispc_reg_out(VENC_HSPLS, BASEX480P);
dispc_reg_out(VENC_VSPLS, BASEY480P);
dispc_reg_out(VENC_HINT, 858 - 1);
dispc_reg_out(VENC_HSTART, 122);
dispc_reg_out(VENC_HVALID, DISP_XRES480P);
dispc_reg_out(VENC_VINT, 525 - 1);
dispc_reg_out(VENC_VSTART, 36);
dispc_reg_out(VENC_VVALID, DISP_YRES480P);
dispc_reg_out(VENC_HSDLY, 0);
dispc_reg_out(VENC_VSDLY, 0);
dispc_reg_out(VENC_YCCCTL, 0);
dispc_reg_out(VENC_VSTARTA, 0);
/* Set DAVINCIFB_WIN_VID0 window origin and size */
dispc_reg_out(OSD_VIDWIN0XP, 20);
dispc_reg_out(OSD_VIDWIN0YP, 25);
dispc_reg_out(OSD_VIDWIN0XL, DISP_XRES480P);
dispc_reg_out(OSD_VIDWIN0YL, DISP_YRES480P);
/* Set DAVINCIFB_WIN_VID1 window origin and size */
dispc_reg_out(OSD_VIDWIN1XP, 20);
dispc_reg_out(OSD_VIDWIN1YP, 25);
dispc_reg_out(OSD_VIDWIN1XL, DISP_XRES480P);
dispc_reg_out(OSD_VIDWIN1YL, DISP_YRES480P);
/* Set DAVINCIFB_WIN_OSD0 window origin and size */
dispc_reg_out(OSD_OSDWIN0XP, 20);
dispc_reg_out(OSD_OSDWIN0YP, 25);
dispc_reg_out(OSD_OSDWIN0XL, DISP_XRES480P);
dispc_reg_out(OSD_OSDWIN0YL, DISP_YRES480P);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_OSDWIN1XP, 20);
dispc_reg_out(OSD_OSDWIN1YP, 25);
dispc_reg_out(OSD_OSDWIN1XL, DISP_XRES480P);
dispc_reg_out(OSD_OSDWIN1YL, DISP_YRES480P);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_CURXP, 20);
dispc_reg_out(OSD_CURYP, 25);
dispc_reg_out(OSD_CURXL, DISP_XRES480P);
dispc_reg_out(OSD_CURYL, DISP_YRES480P);
/* Enable all VENC, non-standard timing mode,
master timing, HD, progressive */
dispc_reg_out(VENC_VMOD,
(VENC_VMOD_VENC | VENC_VMOD_VMD | VENC_VMOD_HDMD));
printk(KERN_INFO "Davinci set video mode as 480p\n");
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_1080i_component_config(int on)
{
if (on) {
#ifdef CONFIG_THS8200
/* Enable THS8200 DAC output mode as 1080I */
ths8200_set_1080i_mode();
#endif/* CONFIG_THS8200 */
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Set new baseX and baseY */
dispc_reg_out(OSD_BASEPX, BASEX1080I);
dispc_reg_out(OSD_BASEPY, BASEY1080I);
enable_digital_output(true);
dispc_reg_merge(PINMUX0, PINMUX0_LFLDEN, PINMUX0_LFLDEN);
/* Enable DAVINCIFB_WIN_OSD0 Window */
dispc_reg_out(OSD_OSDWIN0MD, 0x00002003);
/* Enable DAVINCIFB_WIN_OSD1 Window */
dispc_reg_out(OSD_OSDWIN1MD, 0x00008002);
/* Set Timing parameters for 720P frame (must match what THS8200 expects) */
dispc_reg_out(VENC_HSPLS, BASEX1080I);
dispc_reg_out(VENC_VSPLS, BASEY1080I);
dispc_reg_out(VENC_HINT, 2200-1);
dispc_reg_out(VENC_HSTART, 200);
dispc_reg_out(VENC_HVALID, DISP_XRES1080I);
dispc_reg_out(VENC_VINT, 1125-1);
dispc_reg_out(VENC_VSTART, 13);
dispc_reg_out(VENC_VVALID, DISP_YRES1080I/2);
dispc_reg_out(VENC_HSDLY, 0);
dispc_reg_out(VENC_VSDLY, 0);
dispc_reg_out(VENC_YCCCTL, 0);
dispc_reg_out(VENC_VSTARTA, 13);
dispc_reg_out(OSD_VIDWINMD, 0x203);
/* Set DAVINCIFB_WIN_VID0 window origin and size */
dispc_reg_out(OSD_VIDWIN0XP, 200 - BASEX1080I);
dispc_reg_out(OSD_VIDWIN0YP, 13);
dispc_reg_out(OSD_VIDWIN0XL, DISP_XRES1080I);
dispc_reg_out(OSD_VIDWIN0YL, DISP_YRES1080I/2);
/* Set DAVINCIFB_WIN_VID1 window origin and size */
dispc_reg_out(OSD_VIDWIN1XP, 200 - BASEX1080I);
dispc_reg_out(OSD_VIDWIN1YP, 13);
dispc_reg_out(OSD_VIDWIN1XL, DISP_XRES1080I);
dispc_reg_out(OSD_VIDWIN1YL, DISP_YRES1080I/2);
/* Set DAVINCIFB_WIN_OSD0 window origin and size */
dispc_reg_out(OSD_OSDWIN0XP, 200 - BASEX1080I);
dispc_reg_out(OSD_OSDWIN0YP, 13);
dispc_reg_out(OSD_OSDWIN0XL, DISP_XRES1080I);
dispc_reg_out(OSD_OSDWIN0YL, DISP_YRES1080I/2);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_OSDWIN1XP, 200 - BASEX1080I);
dispc_reg_out(OSD_OSDWIN1YP, 13);
dispc_reg_out(OSD_OSDWIN1XL, DISP_XRES1080I);
dispc_reg_out(OSD_OSDWIN1YL, DISP_YRES1080I/2);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_CURXP, 200 - BASEX1080I);
dispc_reg_out(OSD_CURYP, 13);
dispc_reg_out(OSD_CURXL, DISP_XRES1080I);
dispc_reg_out(OSD_CURYL, DISP_YRES1080I/2);
/* Enable all VENC, non-standard timing mode, master timing, HD, interlaced */
dispc_reg_out(VENC_VMOD,
(VENC_VMOD_VENC | VENC_VMOD_VMD |
VENC_VMOD_HDMD | VENC_VMOD_NSIT));
printk(KERN_INFO "Davinci set video mode as 1080i\n");
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_720p_component_config(int on)
{
if (on) {
#ifdef CONFIG_THS8200
/* Enable the Ths8200 Video DAC to support 720p */
ths8200_set_720p_mode();
#endif
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Set new baseX and baseY */
dispc_reg_out(OSD_BASEPX, BASEX720P);
dispc_reg_out(OSD_BASEPY, BASEY720P);
/* Enable the digtal output */
enable_digital_output(true);
dispc_reg_merge(PINMUX0, 0, PINMUX0_LFLDEN);
/* Enable DAVINCIFB_WIN_OSD0 Window */
dispc_reg_out(OSD_OSDWIN0MD, 0x00002001);
/* Enable DAVINCIFB_WIN_OSD1 Window */
dispc_reg_out(OSD_OSDWIN1MD, 0x00008000);
/* Set Timing parameters for 720P frame
(must match what THS8200 expects) */
dispc_reg_out(VENC_HSPLS, BASEX720P);
dispc_reg_out(VENC_VSPLS, BASEY720P);
dispc_reg_out(VENC_HINT, 1649);
dispc_reg_out(VENC_HSTART, 300);
dispc_reg_out(VENC_HVALID, DISP_XRES720P);
dispc_reg_out(VENC_VINT, 749);
dispc_reg_out(VENC_VSTART, 26);
dispc_reg_out(VENC_VVALID, DISP_YRES720P);
dispc_reg_out(VENC_HSDLY, 0);
dispc_reg_out(VENC_VSDLY, 0);
dispc_reg_out(VENC_YCCCTL, 0);
dispc_reg_out(VENC_VSTARTA, 0);
/* Set DAVINCIFB_WIN_VID0 window origin and size */
dispc_reg_out(OSD_VIDWIN0XP, 220);
dispc_reg_out(OSD_VIDWIN0YP, 25);
dispc_reg_out(OSD_VIDWIN0XL, DISP_XRES720P);
dispc_reg_out(OSD_VIDWIN0YL, DISP_YRES720P);
/* Set DAVINCIFB_WIN_VID1 window origin and size */
dispc_reg_out(OSD_VIDWIN1XP, 220);
dispc_reg_out(OSD_VIDWIN1YP, 25);
dispc_reg_out(OSD_VIDWIN1XL, DISP_XRES720P);
dispc_reg_out(OSD_VIDWIN1YL, DISP_YRES720P);
/* Set DAVINCIFB_WIN_OSD0 window origin and size */
dispc_reg_out(OSD_OSDWIN0XP, 220);
dispc_reg_out(OSD_OSDWIN0YP, 25);
dispc_reg_out(OSD_OSDWIN0XL, DISP_XRES720P);
dispc_reg_out(OSD_OSDWIN0YL, DISP_YRES720P);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_OSDWIN1XP, 220);
dispc_reg_out(OSD_OSDWIN1YP, 25);
dispc_reg_out(OSD_OSDWIN1XL, DISP_XRES720P);
dispc_reg_out(OSD_OSDWIN1YL, DISP_YRES720P);
/* Set DAVINCIFB_WIN_OSD1 window origin and size */
dispc_reg_out(OSD_CURXP, 220);
dispc_reg_out(OSD_CURYP, 25);
dispc_reg_out(OSD_CURXL, DISP_XRES720P);
dispc_reg_out(OSD_CURYL, DISP_YRES720P);
/* Enable all VENC, non-standard timing mode,
master timing, HD, progressive */
dispc_reg_out(VENC_VMOD,
(VENC_VMOD_VENC | VENC_VMOD_VMD | VENC_VMOD_HDMD));
printk(KERN_INFO "Davinci set video mode as 720p\n");
} else{
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_ntsc_composite_config(int on)
{
if (on) {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Enable Composite output and start video encoder */
dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
/* Set REC656 Mode */
dispc_reg_out(VENC_YCCCTL, 0x1);
/* Enable output mode and NTSC */
dispc_reg_out(VENC_VMOD, 0x1003);
/* Enable all DACs */
dispc_reg_out(VENC_DACTST, 0);
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_ntsc_svideo_config(int on)
{
if (on) {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Enable Composite output and start video encoder */
dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
/* Set REC656 Mode */
dispc_reg_out(VENC_YCCCTL, 0x1);
/* Enable output mode and NTSC */
dispc_reg_out(VENC_VMOD, 0x1003);
/* Enable S-Video Output; DAC B: S-Video Y, DAC C: S-Video C */
dispc_reg_out(VENC_DACSEL, 0x210);
/* Enable all DACs */
dispc_reg_out(VENC_DACTST, 0);
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_ntsc_component_config(int on)
{
if (on) {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Enable Composite output and start video encoder */
dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
/* Set REC656 Mode */
dispc_reg_out(VENC_YCCCTL, 0x1);
/* Enable output mode and NTSC */
dispc_reg_out(VENC_VMOD, 0x1003);
/* Enable Component output; DAC A: Y, DAC B: Pb, DAC C: Pr */
dispc_reg_out(VENC_DACSEL, 0x543);
/* Enable all DACs */
dispc_reg_out(VENC_DACTST, 0);
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_pal_composite_config(int on)
{
if (on) {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Enable Composite output and start video encoder */
dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
/* Set REC656 Mode */
dispc_reg_out(VENC_YCCCTL, 0x1);
/* Enable output mode and PAL */
dispc_reg_out(VENC_VMOD, 0x1043);
/* Enable all DACs */
dispc_reg_out(VENC_DACTST, 0);
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_pal_svideo_config(int on)
{
if (on) {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Enable Composite output and start video encoder */
dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
/* Set REC656 Mode */
dispc_reg_out(VENC_YCCCTL, 0x1);
/* Enable output mode and PAL */
dispc_reg_out(VENC_VMOD, 0x1043);
/* Enable S-Video Output; DAC B: S-Video Y, DAC C: S-Video C */
dispc_reg_out(VENC_DACSEL, 0x210);
/* Enable all DACs */
dispc_reg_out(VENC_DACTST, 0);
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
static void davincifb_pal_component_config(int on)
{
if (on) {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Enable Composite output and start video encoder */
dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
/* Set REC656 Mode */
dispc_reg_out(VENC_YCCCTL, 0x1);
/* Enable output mode and PAL */
dispc_reg_out(VENC_VMOD, 0x1043);
/* Enable Component output; DAC A: Y, DAC B: Pb, DAC C: Pr */
dispc_reg_out(VENC_DACSEL, 0x543);
/* Enable all DACs */
dispc_reg_out(VENC_DACTST, 0);
} else {
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
}
}
/* video_output interface */
int output_set_state(struct output_device *od)
{
struct dm_info *dm =
(struct dm_info *)class_get_devdata(&od->class_dev);
unsigned long state = od->request_state;
/* TODO check that the output is available */
switch (state)
{
case DAVINCIFB_OUT_COMPOSITE:
dispc_reg_out(VENC_DACSEL, 0x0);
break;
case DAVINCIFB_OUT_COMPONENT:
/* Enable Component output; DAC A: Y, DAC B: Pb, DAC C: Pr */
dispc_reg_out(VENC_DACSEL, 0x543);
break;
case DAVINCIFB_OUT_SVIDEO:
/* Enable S-Video Output; DAC B: S-Video Y, DAC C: S-Video C */
dispc_reg_out(VENC_DACSEL, 0x210);
break;
case DAVINCIFB_OUT_RGB:
/* TODO handle rgb */
printk("rgb!\n");
break;
default:
return -EINVAL;
}
dm->output_sel = state;
#if 0
/* off dac */
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
#endif
return 0;
}
int output_get_status(struct output_device *od)
{
struct dm_info *dm =
(struct dm_info *)class_get_devdata(&od->class_dev);
return dm->output_sel;
}
struct output_properties output_props = {
.set_state = &output_set_state,
.get_status = &output_get_status,
};
#if 0
static int dm_vout_probe(void)
{
int ret;
ret = dm_vout_register(&dm_vout_venc);
return ret;
}
#endif
/* Must do checks against the limits of the output device */
static int davincifb_venc_check_mode(const struct dm_win_info *w,
const struct fb_var_screeninfo *var)
{
/* ntsc / pal */
if (var->xres == 720) {
if ((var->yres == 576) || (var->yres == 480))
return 0;
}
/* TODO check specific output beside the venc */
return -EINVAL;
}
/*============================================================================*
* OSD windows interface *
*============================================================================*/
static void set_sdram_params(const struct dm_win_info *w, u32 addr, u32 line_length);
/* Wait for a vsync interrupt. This routine sleeps so it can only be called
* from process context.
*/
static int davincifb_wait_for_vsync(struct dm_win_info *w)
{
struct dm_info *dm = w->dm;
wait_queue_t wq;
unsigned long cnt;
int ret;
init_waitqueue_entry(&wq, current);
cnt = dm->vsync_cnt;
ret = wait_event_interruptible_timeout(dm->vsync_wait,
cnt != dm->vsync_cnt,
dm->timeout);
if (ret < 0)
return ret;
if (ret == 0)
return -ETIMEDOUT;
return 0;
}
/* Sets a uniform attribute value over a rectangular area on the attribute
* window. The attribute value (0 to 7) is passed through the fb_fillrect's
* color parameter.
*/
static int davincifb_set_attr_blend(struct dm_win_info *w,
struct fb_fillrect *r)
{
struct fb_info *info = &w->info;
struct fb_var_screeninfo *var = &info->var;
unsigned long start = 0;
u8 blend;
u32 width_bytes;
if (r->dx + r->width > var->xres_virtual)
return -EINVAL;
if (r->dy + r->height > var->yres_virtual)
return -EINVAL;
if (r->color < 0 || r->color > 7)
return -EINVAL;
/* since bits_per_pixel = 4, this will truncate the width if it is
* not even. Similarly r->dx will be rounded down to an even pixel.
* ... Do we want to return an error otherwise?
*/
width_bytes = r->width * var->bits_per_pixel / 8;
start = w->fb_base + r->dy * info->fix.line_length
+ r->dx * var->bits_per_pixel / 8;
blend = (((u8) r->color & 0xf) << 4) | ((u8) r->color);
while (r->height--) {
start += info->fix.line_length;
memset((void *)start, blend, width_bytes);
}
return 0;
}
/*============================================================================*
* OSD windows interface *
*============================================================================*/
/* Interlaced = Frame mode, Non-interlaced = Field mode */
static void set_interlaced(struct dm_win_info *w, unsigned int on)
{
/* TODO remove DAVINCIFB_WIN_VID0, DAVINCIFB_WIN_OSD0, etc */
on = (on == 0) ? 0 : ~0;
if (is_win(w, DAVINCIFB_WIN_VID0))
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF0);
else if (is_win(w, DAVINCIFB_WIN_VID1))
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF1);
else if (is_win(w, DAVINCIFB_WIN_OSD0))
dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OFF0);
else if (is_win(w, DAVINCIFB_WIN_OSD1))
dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OFF1);
}
/* For zooming, we just have to set the start of framebuffer, the zoom factors
* and the display size. The hardware will then read only
* (display size / zoom factor) area of the framebuffer and zoom and
* display it. In the following function, we assume that the start of
* framebuffer and the display size parameters are set already.
*/
static void set_zoom(struct dm_win_info *w, int h_factor, int v_factor)
{
/* TODO remove DAVINCIFB_WIN_VID0, DAVINCIFB_WIN_OSD0, etc */
switch (w->win) {
case DAVINCIFB_WIN_VID0:
dispc_reg_merge(OSD_VIDWINMD,
h_factor << OSD_VIDWINMD_VHZ0_SHIFT,
OSD_VIDWINMD_VHZ0);
dispc_reg_merge(OSD_VIDWINMD,
v_factor << OSD_VIDWINMD_VVZ0_SHIFT,
OSD_VIDWINMD_VVZ0);
break;
case DAVINCIFB_WIN_VID1:
dispc_reg_merge(OSD_VIDWINMD,
h_factor << OSD_VIDWINMD_VHZ1_SHIFT,
OSD_VIDWINMD_VHZ1);
dispc_reg_merge(OSD_VIDWINMD,
v_factor << OSD_VIDWINMD_VVZ1_SHIFT,
OSD_VIDWINMD_VVZ1);
break;
case DAVINCIFB_WIN_OSD0:
dispc_reg_merge(OSD_OSDWIN0MD,
h_factor << OSD_OSDWIN0MD_OHZ0_SHIFT,
OSD_OSDWIN0MD_OHZ0);
dispc_reg_merge(OSD_OSDWIN0MD,
v_factor << OSD_OSDWIN0MD_OVZ0_SHIFT,
OSD_OSDWIN0MD_OVZ0);
break;
case DAVINCIFB_WIN_OSD1:
dispc_reg_merge(OSD_OSDWIN1MD,
h_factor << OSD_OSDWIN1MD_OHZ1_SHIFT,
OSD_OSDWIN1MD_OHZ1);
dispc_reg_merge(OSD_OSDWIN1MD,
v_factor << OSD_OSDWIN1MD_OVZ1_SHIFT,
OSD_OSDWIN1MD_OVZ1);
break;
}
}
/* Chooses the ROM CLUT for now. Can be extended later. */
static void set_bg_color(u8 clut, u8 color_offset)
{
clut = 0; /* 0 = ROM, 1 = RAM */
dispc_reg_merge(OSD_MODE, OSD_MODE_BCLUT & clut, OSD_MODE_BCLUT);
dispc_reg_merge(OSD_MODE, color_offset << OSD_MODE_CABG_SHIFT,
OSD_MODE_CABG);
}
static void set_sdram_params(const struct dm_win_info *w, u32 addr, u32 line_length)
{
/* The parameters to be written to the registers should be in
* multiple of 32 bytes
*/
addr = addr; /* div by 32 */
line_length = line_length / 32;
if (is_win(w, DAVINCIFB_WIN_VID0)) {
dispc_reg_out(OSD_VIDWIN0ADR, addr);
dispc_reg_out(OSD_VIDWIN0OFST, line_length);
} else if (is_win(w, DAVINCIFB_WIN_VID1)) {
dispc_reg_out(OSD_VIDWIN1ADR, addr);
dispc_reg_out(OSD_VIDWIN1OFST, line_length);
} else if (is_win(w, DAVINCIFB_WIN_OSD0)) {
dispc_reg_out(OSD_OSDWIN0ADR, addr);
dispc_reg_out(OSD_OSDWIN0OFST, line_length);
} else if (is_win(w, DAVINCIFB_WIN_OSD1)) {
dispc_reg_out(OSD_OSDWIN1ADR, addr);
dispc_reg_out(OSD_OSDWIN1OFST, line_length);
}
}
static void set_win_enable(const struct dm_win_info *w, unsigned int on)
{
on = (on == 0) ? 0 : ~0;
if (is_win(w, DAVINCIFB_WIN_VID0))
/* Turning off DAVINCIFB_WIN_VID0 use due to field inversion issue */
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_ACT0);
else if (is_win(w, DAVINCIFB_WIN_VID1))
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_ACT1);
else if (is_win(w, DAVINCIFB_WIN_OSD0))
dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OACT0);
else if (is_win(w, DAVINCIFB_WIN_OSD1)) {
/* The OACT1 bit is applicable only if DAVINCIFB_WIN_OSD1 is not used as
* the attribute window
*/
if (!(dispc_reg_in(OSD_OSDWIN1MD) & OSD_OSDWIN1MD_OASW))
dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OACT1);
}
}
/* TODO fix this, isnt flexible enough */
static void set_win_mode(const struct dm_win_info *w)
{
if (is_win(w, DAVINCIFB_WIN_VID0)) ;
else if (is_win(w, DAVINCIFB_WIN_VID1)) {
if (w->info.var.bits_per_pixel == 32)
dispc_reg_merge(OSD_MISCCT, ~0,
OSD_MISCCT_RGBWIN | OSD_MISCCT_RGBEN);
} else if (is_win(w, DAVINCIFB_WIN_OSD0))
/* Set RGB565 mode */
dispc_reg_merge(OSD_OSDWIN0MD, OSD_OSDWIN0MD_RGB0E,
OSD_OSDWIN0MD_RGB0E);
else if (is_win(w, DAVINCIFB_WIN_OSD1)) {
/* Set as attribute window */
dispc_reg_merge(OSD_OSDWIN1MD, OSD_OSDWIN1MD_OASW,
OSD_OSDWIN1MD_OASW);
}
}
/* These position parameters are given through fb_var_screeninfo.
* xp = var.reserved[0], yp = var.reserved[1],
* xl = var.xres, yl = var.yres
*/
static void set_win_position(const struct dm_win_info *w, u32 xp, u32 yp, u32 xl,
u32 yl)
{
int i = 0;
struct device *dev = w->dm->dev;
dev_dbg(dev, "Setting window position %u %u %u %u\n", xp, yp, xl, yl);
if (is_win(w, DAVINCIFB_WIN_VID0)) {
i = 0;
} else if (is_win(w, DAVINCIFB_WIN_VID1)) {
i = 1;
} else if (is_win(w, DAVINCIFB_WIN_OSD0)) {
i = 2;
} else if (is_win(w, DAVINCIFB_WIN_OSD1)) {
i = 3;
}
dispc_reg_out(OSD_WINXP(i), xp);
dispc_reg_out(OSD_WINYP(i), yp);
dispc_reg_out(OSD_WINXL(i), xl);
dispc_reg_out(OSD_WINYL(i), yl);
}
static inline void get_win_position(const struct dm_win_info *w,
u32 * xp, u32 * yp, u32 * xl, u32 * yl)
{
struct fb_var_screeninfo *v = &w->info.var;
*xp = x_pos(w);
*yp = y_pos(w);
*xl = v->xres;
*yl = v->yres;
}
/* Returns 1 if the windows overlap, 0 otherwise */
static int window_overlap(struct dm_win_info *w, u32 xp, u32 yp, u32 xl, u32 yl)
{
u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0;
#define OVERLAP(x1, y1, x2, y2, x3, y3, x4, y4) \
(!( ((x1)<(x3) && (x2)<(x3)) || ((x1)>(x4) && (x2)>(x4)) || \
((y1)<(y3) && (y2)<(y3)) || ((y1)>(y4) && (y2)>(y4)) ) \
)
if (!w)
return 0;
get_win_position(w, &_xp, &_yp, &_xl, &_yl);
return OVERLAP(xp, yp, xp + xl, yp + yl,
_xp, _yp, _xp + _xl, _yp + _yl);
#undef OVERLAP
}
/* Returns 1 if the window parameters are within DAVINCIFB_WIN_VID0, 0 otherwise */
static int within_vid0_limits(struct dm_win_info *vid0, u32 xp, u32 yp, u32 xl,
u32 yl)
{
u32 vid0_xp = 0, vid0_yp = 0, vid0_xl = 0, vid0_yl = 0;
if (!vid0)
return 1;
get_win_position(vid0, &vid0_xp, &vid0_yp, &vid0_xl, &vid0_yl);
if ((xp >= vid0_xp) && (yp >= vid0_yp) &&
(xp + xl <= vid0_xp + vid0_xl) && (yp + yl <= vid0_yp + vid0_yl))
return 1;
return 0;
}
/* DAVINCIFB_WIN_VID0 must be large enough to hold all other windows */
static int check_new_vid0_size(struct dm_win_info *vid0, u32 xp0, u32 yp0,
u32 xl0, u32 yl0)
{
struct dm_win_info *owin;
u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0;
#define WITHIN_LIMITS \
((_xp >= xp0) && (_yp >= yp0) && \
(_xp + _xl <= xp0 + xl0) && (_yp + _yl <= yp0 + yl0))
owin = vid0->dm->windows[DAVINCIFB_WIN_OSD0];
if (owin) {
get_win_position(owin, &_xp, &_yp, &_xl, &_yl);
if (!WITHIN_LIMITS)
return -EINVAL;
}
owin = vid0->dm->windows[DAVINCIFB_WIN_OSD1];
if (owin) {
get_win_position(owin, &_xp, &_yp, &_xl, &_yl);
if (!WITHIN_LIMITS)
return -EINVAL;
}
owin = vid0->dm->windows[DAVINCIFB_WIN_VID1];
if (owin) {
get_win_position(owin, &_xp, &_yp, &_xl, &_yl);
if (!WITHIN_LIMITS)
return -EINVAL;
}
return 0;
#undef WITHIN_LIMITS
}
/* Initialize the fb_info structure with common values and values that wont
* change if var changes
*/
static void dm_win_common_info_set(struct dm_win_info *w)
{
struct fb_info *info = &w->info;
info->flags = FBINFO_DEFAULT;
info->fbops = &davincifb_ops;
info->screen_base = (char *)(w->fb_base);
info->pseudo_palette = w->pseudo_palette;
info->par = w;
strlcpy(info->fix.id, dm_win_names[w->win], sizeof(info->fix.id));
info->fix.mmio_start = w->dm->mmio_base_phys;
info->fix.mmio_len = w->dm->mmio_size;
info->fix.accel = FB_ACCEL_NONE;
w->sdram_address = 0;
}
/* Initialize fixed screeninfo.
* The fixed screeninfo cannot be directly specified by the user, but
* it may change to reflect changes to the var info.
*/
static void dm_win_fix_set(struct dm_win_info *w)
{
struct fb_info *info = &w->info;
info->fix.smem_start = w->fb_base_phys;
info->fix.line_length =
(info->var.xres_virtual * info->var.bits_per_pixel) / 8;
info->fix.smem_len = w->fb_size;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = (info->var.bits_per_pixel <= 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
/* some values might change based on check_var, set_par and pan */
info->fix.xpanstep = 0;
info->fix.ypanstep = 1;
info->fix.ywrapstep = 0;
info->fix.type_aux = 0;
}
static int dm_win_mem_free(struct dm_win_info *w)
{
#if 0
iounmap((void *)w->fb_base);
release_mem_region(w->fb_base_phys, w->fb_size);
#endif
#if 0
dma_free_coherent(NULL, w->fb_size, (void *)w->fb_base,
w->fb_base_phys);
#endif
free_pages_exact((void *)w->fb_base, w->fb_size);
}
static int dm_win_mem_alloc(struct dm_win_info *w)
{
struct fb_var_screeninfo *vinfo = &w->info.var;
struct device *dev = w->dm->dev;
w->fb_size = vinfo->xres_virtual * vinfo->yres_virtual *
vinfo->bits_per_pixel / 8;
dev_dbg(dev, "Trying to allocate %lu bytes of buffer\n", w->fb_size);
#if 0
w->fb_base = (unsigned long)dma_alloc_coherent(dev, w->fb_size,
&w->fb_base_phys, GFP_DMA);
#endif
w->fb_base = (unsigned long)alloc_pages_exact(w->fb_size, GFP_DMA);
w->fb_base_phys = virt_to_phys((void *)w->fb_base);
if (!w->fb_base)
return -ENOMEM;
dev_dbg(dev, "Framebuffer allocated at 0x%x "
"mapped to 0x%x, size %dk\n",
(unsigned)w->fb_base_phys, (unsigned)w->fb_base,
(unsigned)w->fb_size / 1024);
return 0;
}
static int dm_win_probe(struct dm_win_info *w)
{
int bg_color = 0x00;
struct fb_info *info = &w->info;
struct device *dev = w->dm->dev;
struct fb_var_screeninfo *vinfo = &info->var;
/* TODO redo this logic, first map the maximum size and then
* check the mode
*/
dev_dbg(dev, "Probing device %s\n", dm_win_names[w->win]);
/* check the requested var */
if (davincifb_check_var(&dm_default_var[w->win], info)) {
dev_err(dev, "%s: Invalid default video mode\n",
dm_win_names[w->win]);
return -EINVAL;
}
/* copy the modified default var into the fb_info struct */
memcpy(vinfo, &dm_default_var[w->win],
sizeof(struct fb_var_screeninfo));
/* request memory */
if (dm_win_mem_alloc(w) < 0) {
dev_err(dev, "%s: Cannot allocate framebuffer of size %lu\n",
dm_win_names[w->win], w->fb_size);
return -EINVAL;
}
/* setup common values */
dm_win_common_info_set(w);
dm_win_fix_set(w);
/* create the fb device */
if (register_framebuffer(info) < 0) {
dev_err(dev, "Unable to register %s framebuffer\n",
dm_win_names[w->win]);
return -EINVAL;
}
davincifb_set_par(info);
/* clear the memory */
switch (info->var.bits_per_pixel) {
case 16:
/* yuv422 */
if (is_win(w, DAVINCIFB_WIN_VID0) ||
is_win(w, DAVINCIFB_WIN_VID1))
bg_color = 0x88;
break;
/* attribute */
case 4:
if (is_win(w, DAVINCIFB_WIN_OSD1))
bg_color = 0xff;
break;
}
memset((void *)w->fb_base, bg_color, w->fb_size);
return 0;
}
static int dm_wins_probe(struct dm_info *info)
{
int windows;
int i = 0;
/* Setup DAVINCIFB_WIN_VID0 framebuffer */
if (!(info->windows_mask & (1 << DAVINCIFB_WIN_VID0))) {
printk(KERN_WARNING "No video/osd windows will be enabled "
"because Video0 is disabled\n");
return 0; /* background will still be shown */
}
/* Probe all requested windows */
windows = info->windows_mask;
info->windows_mask = 0;
while (windows)
{
if (windows & 1) {
struct dm_win_info *w;
w = kzalloc(sizeof(struct dm_win_info), GFP_KERNEL);
if (!w) {
dev_err(info->dev, "%s: could not allocate\
memory\n", dm_win_names[i]);
goto stop;
}
/* necessary information for checkvar */
w->win = i;
w->dm = info;
w->info.par = w;
if (dm_win_probe(w)) {
kfree(w);
}
else {
info->windows[i] = w;
info->windows_mask |= (1 << i);
}
}
windows >>= 1;
i++;
}
/* TODO return EINVAL in case none of the requested wins were ok */
stop:
return 0;
}
static int dm_win_remove(struct dm_win_info *w)
{
unregister_framebuffer(&w->info);
dm_win_mem_free(w);
/* TODO disable the plane */
}
static int dm_wins_remove(struct dm_info *info)
{
int windows;
int i = 0;
windows = info->windows_mask;
while (windows)
{
if (windows & 1)
{
dm_win_remove(info->windows[i]);
kfree(info->windows[i]);
info->windows[i] = NULL;
}
windows >>= 1;
i++;
}
}
static int parse_win_params(char *wp,
int *xres, int *yres, int *xpos, int *ypos)
{
char *s;
if ((s = strsep(&wp, "x")) == NULL)
return -EINVAL;
*xres = simple_strtoul(s, NULL, 0);
if ((s = strsep(&wp, "@")) == NULL)
return -EINVAL;
*yres = simple_strtoul(s, NULL, 0);
if ((s = strsep(&wp, ",")) == NULL)
return -EINVAL;
*xpos = simple_strtoul(s, NULL, 0);
if ((s = strsep(&wp, ":")) == NULL)
return -EINVAL;
*ypos = simple_strtoul(s, NULL, 0);
return 0;
}
/*============================================================================*
* Framebuffer API *
*============================================================================*/
/**
* davincifb_check_var - Validates a var passed in.
* @var: frame buffer variable screen structure
* @info: frame buffer structure that represents a single frame buffer
*
* Checks to see if the hardware supports the state requested by
* var passed in. This function does not alter the hardware state!!!
* This means the data stored in struct fb_info and struct xxx_par do
* not change. This includes the var inside of struct fb_info.
* Do NOT change these. This function can be called on its own if we
* intent to only test a mode and not actually set it.
* If the var passed in is slightly off by what the hardware can support
* then we alter the var PASSED in to what we can do.
*
* Returns negative errno on error, or zero on success.
*/
static int davincifb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
const struct dm_win_info *w = (const struct dm_win_info *)info->par;
struct fb_var_screeninfo v;
struct device *dev = w->dm->dev;
/* Rules:
* 1) Vid1, DAVINCIFB_WIN_OSD0, DAVINCIFB_WIN_OSD1 and Cursor must be fully contained inside of Vid0.
* 2) Vid0 and Vid1 are both set to accept YUV 4:2:2 (for now).
* 3) OSD window data is always packed into 32-bit words and left justified.
* 4) Each horizontal line of window data must be a multiple of 32 bytes.
* 32 bytes = 32 bytes / 2 bytes per pixel = 16 pixels.
* This implies that 'xres' must be a multiple of 32 bytes.
* 5) The offset registers hold the distance between the start of one line and
* the start of the next. This offset value must be a multiple of 32 bytes.
* This implies that 'xres_virtual' is also a multiple of 32 bytes. Note
* that 'xoffset' needn't be a multiple of 32 bytes.
* 6) DAVINCIFB_WIN_OSD0 is set to accept RGB565.
* dispc_reg_merge(OSD_OSDWIN0ND, OSD_OSDWIN0ND_RGB0E, OSD_OSDWIN0ND_RGB0E)
* 7) DAVINCIFB_WIN_OSD1 is set to be the attribute window.
* 8) Vid1 startX = Vid0 startX + N * 16 pixels (32 bytes)
* 9) Vid1 width = (16*N - 8) pixels
* 10) When one of the OSD windows is in RGB565, it cannot overlap with Vid1.
* 11) Vid1 start X position must be offset a multiple of 16 pixels from the
* left edge of Vid0.
*/
memcpy(&v, var, sizeof(v));
/* virtual size < display size */
if (v.xres_virtual < v.xres || v.yres_virtual < v.yres) {
dev_dbg(dev, "Virtual size > displayed size\n");
return -EINVAL;
}
/* virtual offset > virtual size */
if (v.xoffset > v.xres_virtual - v.xres) {
dev_dbg(dev, "Virtual x offset > vitual size\n");
return -EINVAL;
}
if (v.yoffset > v.yres_virtual - v.yres) {
dev_dbg(dev, "Virtual y offset > vitual size\n");
return -EINVAL;
}
/* TODO handle the vid0 output thing */
if (is_win(w, DAVINCIFB_WIN_VID0)) {
/* do board-specific checks on the var */
if (davincifb_venc_check_mode(w, &v))
return -EINVAL;
}
/* FIXME Rules 4 and 5 aren't good. The line_length should be multiple
* of 32 bytes but not the xres
*/
/* Rules 4, 5 */
if ((v.xres * v.bits_per_pixel / 8) % 32 || (v.xres_virtual * v.bits_per_pixel / 8) % 32) {
dev_dbg(dev, "%s Offset isnt 32 byte aligned xres = %d \
xres_virtual = %d bpp = %d\n", dm_win_names[w->win],
v.xres, v.xres_virtual, v.bits_per_pixel);
return -EINVAL;
}
if ((w->fb_size) && (v.xres_virtual * v.yres_virtual * v.bits_per_pixel
/ 8 > w->fb_size)) {
dev_dbg(dev, "Requested resolution too big\n");
return -EINVAL;
}
if (!is_win(w, DAVINCIFB_WIN_VID0)) {
/* Rule 1 */
if (!within_vid0_limits(w->dm->windows[DAVINCIFB_WIN_VID0],
x_pos(w), y_pos(w), v.xres, v.yres)) {
dev_dbg(dev, "Window %s isnt fully contained on vid0\n",
dm_win_names[w->win]);
//return -EINVAL;
}
}
if (is_win(w, DAVINCIFB_WIN_OSD0)) {
/* Rule 10 */
/*if (window_overlap(w->dm->windows[DAVINCIFB_WIN_VID1],
x_pos(w), y_pos(w), v.xres, v.yres)) {
dev_dbg(dev, "osd0 window overlaps with vid1\n");
return -EINVAL;
}*/
/* Rule 5 */
v.bits_per_pixel = 16;
v.red.offset = 11;
v.green.offset = 5;
v.blue.offset = 0;
v.red.length = 5;
v.green.length = 6;
v.blue.length = 5;
v.transp.offset = v.transp.length = 0;
v.red.msb_right = v.green.msb_right = v.blue.msb_right
= v.transp.msb_right = 0;
v.nonstd = 0;
v.accel_flags = 0;
} else if (is_win(w, DAVINCIFB_WIN_OSD1)) {
v.bits_per_pixel = 4;
} else if (is_win(w, DAVINCIFB_WIN_VID0)) {
if (check_new_vid0_size((struct dm_info *)w, x_pos(w), y_pos(w),
v.xres, v.yres)) {
dev_dbg(dev, "vid0 isn't large enough to handle all\
windows\n");
//return -EINVAL;
}
v.bits_per_pixel = 16;
} else if (is_win(w, DAVINCIFB_WIN_VID1)) {
/* Rule 11 */
if (w->dm->windows[DAVINCIFB_WIN_VID0] &&
((x_pos(w->dm->windows[DAVINCIFB_WIN_VID0]) - x_pos(w))
% 16)) {
dev_dbg(dev, "vid1 x should be multiple of 16 from\
vid0\n");
return -EINVAL;
}
/* Video1 may be in YUV or RGB888 format */
if ((v.bits_per_pixel != 16) && (v.bits_per_pixel != 32))
return -EINVAL;
} else
return -EINVAL;
memcpy(var, &v, sizeof(v));
return 0;
}
/**
* davincifb_set_par - Optional function. Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*
* Using the fb_var_screeninfo in fb_info we set the resolution of the
* this particular framebuffer. This function alters the par AND the
* fb_fix_screeninfo stored in fb_info. It doesn't not alter var in
* fb_info since we are using that data. This means we depend on the
* data in var inside fb_info to be supported by the hardware.
* davincifb_check_var is always called before dmfb_set_par to ensure this.
* Again if you can't can't the resolution you don't need this function.
*
*/
static int davincifb_set_par(struct fb_info *info)
{
struct dm_win_info *w = (struct dm_win_info *)info->par;
struct fb_var_screeninfo *v = &info->var;
u32 start = 0, offset = 0;
info->fix.line_length = v->xres_virtual * v->bits_per_pixel / 8;
offset = v->yoffset * info->fix.line_length +
v->xoffset * v->bits_per_pixel / 8;
start = (u32) w->fb_base_phys + offset;
set_sdram_params(w, start, info->fix.line_length);
set_interlaced(w, 1);
set_win_position(w,
x_pos(w), y_pos(w), v->xres, v->yres / 2);
set_win_mode(w);
set_win_enable(w, 1);
/* TODO handle the vid0 output thing */
if (is_win(w, DAVINCIFB_WIN_VID0)) {
/* TODO set video output to that resolution */
/* turn off current output */
//w->dm->output_device_config(0);
/* NTSC / PAL */
if (v->xres == 720)
{
/* Reset video encoder module */
dispc_reg_out(VENC_VMOD, 0);
/* Enable Composite output and start video encoder */
dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
/* Set REC656 Mode */
dispc_reg_out(VENC_YCCCTL, 0x1);
if (v->yres == 480) {
/* Enable output mode and NTSC */
dispc_reg_out(VENC_VMOD, 0x1003);
}
else {
/* Enable output mode and PAL */
dispc_reg_out(VENC_VMOD, 0x1043);
}
/* Enable all DACs */
dispc_reg_out(VENC_DACTST, 0);
}
/* turn on new mode */
//w->dm->output_device_config(1);
}
return 0;
}
/**
* davincifb_ioctl - handler for private ioctls.
*/
static int davincifb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
struct dm_win_info *w = (struct dm_win_info *)info->par;
void __user *argp = (void __user *)arg;
struct fb_fillrect rect;
struct zoom_params zoom;
long std = 0;
unsigned int enable = 0;
unsigned int pos = 0;
switch (cmd) {
case FBIO_WAITFORVSYNC:
/* This ioctl accepts an integer argument to specify a
* display. We only support one display, so we will
* simply ignore the argument.
*/
return (davincifb_wait_for_vsync(w));
break;
case FBIO_SETATTRIBUTE:
if (copy_from_user(&rect, argp, sizeof(rect)))
return -EFAULT;
if (!is_win(w, DAVINCIFB_WIN_OSD1))
return -EINVAL;
return (davincifb_set_attr_blend(w, &rect));
break;
/* FIXME this is wrong, we can't use the info.var as parameter
* to check var, it will be overwritten
*/
case FBIO_SETPOSX:
if (copy_from_user(&pos, argp, sizeof(u_int32_t)))
return -EFAULT;
if (pos >= 0 && pos <= DISP_XRES) {
struct fb_var_screeninfo v;
memcpy(&v, &w->info.var, sizeof(v));
if (davincifb_check_var(&v, &w->info) < 0)
return -EINVAL;
memcpy(&w->info.var, &v, sizeof(v));
davincifb_set_par(&w->info);
w->x = pos;
return 0;
} else
return -EINVAL;
break;
case FBIO_SETPOSY:
if (copy_from_user(&pos, argp, sizeof(u_int32_t)))
return -EFAULT;
if (pos >= 0 && pos <= DISP_YRES) {
struct fb_var_screeninfo v;
memcpy(&v, &w->info.var, sizeof(v));
if (davincifb_check_var(&v, &w->info) < 0)
return -EINVAL;
memcpy(&w->info.var, &v, sizeof(v));
davincifb_set_par(&w->info);
w->y = pos;
return 0;
} else
return -EINVAL;
break;
case FBIO_SETZOOM:
if (copy_from_user(&zoom, argp, sizeof(zoom)))
return -EFAULT;
if ((zoom.zoom_h == 2) || (zoom.zoom_h == 0)
|| (zoom.zoom_h == 1) || (zoom.zoom_v == 2)
|| (zoom.zoom_v == 0) || (zoom.zoom_v == 1)) {
if (!is_win(w, zoom.window_id))
return -EINVAL;
set_zoom(w, zoom.zoom_h, zoom.zoom_v);
return 0;
} else {
return -EINVAL;
}
break;
case FBIO_GETSTD:
std = ((dmparams.output << 16) | (dmparams.format)); //(NTSC <<16) | (COPOSITE);
if (copy_to_user(argp, &std, sizeof(u_int32_t)))
return -EFAULT;
return 0;
break;
case FBIO_ENABLE:
if (copy_from_user(&enable, argp, sizeof(u_int32_t)))
return -EFAULT;
set_win_enable(w, enable);
return 0;
break;
}
return -EINVAL;
}
/**
* davincifb_setcolreg - Optional function. Sets a color register.
* @regno: Which register in the CLUT we are programming
* @red: The red value which can be up to 16 bits wide
* @green: The green value which can be up to 16 bits wide
* @blue: The blue value which can be up to 16 bits wide.
* @transp: If supported the alpha value which can be up to 16 bits wide.
* @info: frame buffer info structure
*
* Set a single color register. The values supplied have a 16 bit
* magnitude which needs to be scaled in this function for the hardware.
* Things to take into consideration are how many color registers, if
* any, are supported with the current color visual. With truecolor mode
* no color palettes are supported. Here a psuedo palette is created
* which we store the value in pseudo_palette in struct fb_info. For
* pseudocolor mode we have a limited color palette. To deal with this
* we can program what color is displayed for a particular pixel value.
* DirectColor is similar in that we can program each color field. If
* we have a static colormap we don't need to implement this function.
*
* Returns negative errno on error, or zero on success.
*/
static int davincifb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
/* only pseudo-palette (16 bpp) allowed */
if (regno >= 16) /* maximum number of palette entries */
return 1;
if (info->var.grayscale) {
/* grayscale = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
}
/* Truecolor has hardware-independent 16-entry pseudo-palette */
if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
u32 v;
if (regno >= 16)
return 1;
red >>= (16 - info->var.red.length);
green >>= (16 - info->var.green.length);
blue >>= (16 - info->var.blue.length);
v = (red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
switch (info->var.bits_per_pixel) {
case 16:
((u16 *) (info->pseudo_palette))[regno] = v;
break;
default:
return 1;
}
return 0;
}
return 0;
}
/**
* davincifb_pan_display - NOT a required function. Pans the display.
* @var: frame buffer variable screen structure
* @info: frame buffer structure that represents a single frame buffer
*
* Pan (or wrap, depending on the `vmode' field) the display using the
* `xoffset' and `yoffset' fields of the `var' structure.
* If the values don't fit, return -EINVAL.
*
* Returns negative errno on error, or zero on success.
*/
static int davincifb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct dm_win_info *w = (struct dm_win_info *)info->par;
u32 start = 0, offset = 0;
if (var->xoffset > var->xres_virtual - var->xres)
return -EINVAL;
if (var->yoffset > var->yres_virtual - var->yres)
return -EINVAL;
if ((var->xres_virtual * var->bits_per_pixel / 8) % 32)
return -EINVAL;
offset = var->yoffset * info->fix.line_length +
var->xoffset * var->bits_per_pixel / 8;
start = (u32) w->fb_base_phys + offset;
if ((dispc_reg_in(VENC_VSTAT) & 0x00000010)==0x10)
set_sdram_params(w, start, info->fix.line_length);
else
w->sdram_address = start;
return 0;
}
/**
* davincifb_blank - NOT a required function. Blanks the display.
* @blank_mode: the blank mode we want.
* @info: frame buffer structure that represents a single frame buffer
*
* Blank the screen if blank_mode != 0, else unblank. Return 0 if
* blanking succeeded, != 0 if un-/blanking failed due to e.g. a
* video mode which doesn't support it. Implements VESA suspend
* and powerdown modes on hardware that supports disabling hsync/vsync:
* blank_mode == 2: suspend vsync
* blank_mode == 3: suspend hsync
* blank_mode == 4: powerdown
*
* Returns negative errno on error, or zero on success.
*
*/
static int davincifb_blank(int blank_mode, struct fb_info *info)
{
return 0;
}
#if 0
static int mem_alloc(struct dm_win_info *w, dma_addr_t fb_base_phys,
unsigned long fb_size, char *fbname)
{
struct device *dev = w->dm->dev;
w->fb_base_phys = fb_base_phys;
w->fb_size = fb_size;
/* A null base address indicates that the framebuffer memory should be
* dynamically allocated.
*/
if (!w->fb_base_phys)
{
printk("using dma alloc coherent\n");
w->alloc_fb_mem = 1;
}
if (!w->alloc_fb_mem) {
if (!request_mem_region(w->fb_base_phys, w->fb_size, fbname)) {
dev_err(dev, "%s: cannot reserve FB region\n", fbname);
goto free_par;
}
w->fb_base =
(unsigned long)ioremap(w->fb_base_phys, w->fb_size);
if (!w->fb_base) {
dev_err(dev, "%s: cannot map framebuffer\n", fbname);
goto release_fb;
}
} else {
/* allocate coherent memory for the framebuffer */
w->fb_base = (unsigned long)dma_alloc_coherent(dev,
w->fb_size,
&w->fb_base_phys,
GFP_KERNEL |
GFP_DMA);
if (!w->fb_base) {
dev_err(dev, "%s: cannot allocate framebuffer\n",
fbname);
goto free_par;
}
}
dev_dbg(dev, "Framebuffer allocated at 0x%x "
"mapped to 0x%x, size %dk\n",
(unsigned)w->fb_base_phys, (unsigned)w->fb_base,
(unsigned)w->fb_size / 1024);
return 0;
release_fb:
if (!w->alloc_fb_mem)
release_mem_region(w->fb_base_phys, w->fb_size);
free_par:
return -ENOMEM;
}
static struct fb_info *init_fb_info(struct dm_win_info *w,
struct fb_var_screeninfo *var, char *id)
{
struct fb_info *info = &(w->info);
struct dm_info *dm = w->dm;
/* initialize the fb_info structure */
info->flags = FBINFO_DEFAULT;
info->fbops = &davincifb_ops;
info->screen_base = (char *)(w->fb_base);
info->pseudo_palette = w->pseudo_palette;
info->par = w;
/* Initialize variable screeninfo.
* The variable screeninfo can be directly specified by the user
* via an ioctl.
*/
memcpy(&info->var, var, sizeof(info->var));
info->var.activate = FB_ACTIVATE_NOW;
/* Initialize fixed screeninfo.
* The fixed screeninfo cannot be directly specified by the user, but
* it may change to reflect changes to the var info.
*/
strlcpy(info->fix.id, id, sizeof(info->fix.id));
info->fix.smem_start = w->fb_base_phys;
info->fix.line_length =
(info->var.xres_virtual * info->var.bits_per_pixel) / 8;
info->fix.smem_len = w->fb_size;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = (info->var.bits_per_pixel <= 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
info->fix.xpanstep = 0;
info->fix.ypanstep = 1;
info->fix.ywrapstep = 0;
info->fix.type_aux = 0;
info->fix.mmio_start = dm->mmio_base_phys;
info->fix.mmio_len = dm->mmio_size;
info->fix.accel = FB_ACCEL_NONE;
w->sdram_address = 0;
return info;
}
#endif
static inline void fix_default_var(struct dm_win_info *w,
u32 xres, u32 yres, u32 xpos, u32 ypos,
int n_buf)
{
struct fb_var_screeninfo *v = &w->info.var;
v->xres = xres;
v->yres = yres;
v->xres_virtual = v->xres;
v->yres_virtual = v->yres * n_buf;
x_pos(w) = xpos;
y_pos(w) = ypos;
}
/*
* Frame buffer operations
*/
static struct fb_ops davincifb_ops = {
.owner = THIS_MODULE,
.fb_check_var = davincifb_check_var,
.fb_set_par = davincifb_set_par,
.fb_setcolreg = davincifb_setcolreg,
.fb_blank = davincifb_blank,
.fb_pan_display = davincifb_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_rotate = NULL,
.fb_sync = NULL,
.fb_ioctl = davincifb_ioctl,
};
/*============================================================================*
* Platform device *
*============================================================================*/
/**
*
*/
static irqreturn_t davincifb_isr(int irq, void *arg)
{
struct dm_info *dm = (struct dm_info *)arg;
int win;
if ((dispc_reg_in(VENC_VSTAT) & 0x00000010) == 0x10) {
for (win = 0; win < DAVINCIFB_WINDOWS; win++)
{
struct dm_win_info *w;
unsigned long addr = 0;
w = dm->windows[win];
if (!w)
continue;
xchg(&addr, w->sdram_address);
if (addr) {
set_sdram_params(w, w->sdram_address,
w->info.fix.line_length);
w->sdram_address = 0;
}
}
return IRQ_HANDLED;
} else {
++dm->vsync_cnt;
wake_up_interruptible(&dm->vsync_wait);
return IRQ_HANDLED;
}
return IRQ_HANDLED;
}
/*
* Cleanup
*/
static int davincifb_remove(struct platform_device *pdev)
{
struct dm_info *dm;
dm = platform_get_drvdata(pdev);
free_irq(IRQ_VENCINT, dm);
/* Cleanup all framebuffers */
dm_wins_remove(dm);
/* Turn OFF the output device */
dm->output_device_config(0);
video_output_unregister(dm->output);
if (dm->mmio_base)
iounmap((void *)dm->mmio_base);
release_mem_region(dm->mmio_base_phys, dm->mmio_size);
kfree(dm);
return 0;
}
/*
* Initialization
*/
static int davincifb_probe(struct platform_device *pdev)
{
struct dm_info *dm;
struct fb_info *info;
if (dmparams.windows == 0)
return 0; /* user disabled all windows through bootargs */
dm = kzalloc(sizeof(struct dm_info), GFP_KERNEL);
dm->dev = &pdev->dev;
dm->mmio_base_phys = OSD_REG_BASE;
dm->mmio_size = OSD_REG_SIZE;
if (!request_mem_region
(dm->mmio_base_phys, dm->mmio_size, MODULE_NAME)) {
dev_err(dm->dev, ": cannot reserve MMIO region\n");
goto free_dm;
}
/* map the regions */
dm->mmio_base =
(unsigned long)ioremap(dm->mmio_base_phys, dm->mmio_size);
if (!dm->mmio_base) {
dev_err(dm->dev, ": cannot map MMIO\n");
goto release_mmio;
}
/* initialize the vsync wait queue */
init_waitqueue_head(&dm->vsync_wait);
dm->timeout = HZ / 5;
{
#if 0
void *virt;
virt = alloc_pages_exact(5 * 1024 * 1024, GFP_DMA | __GFP_ZERO);
printk("virtual = %p\n", virt);
if (virt)
free_pages_exact(virt, 5 * 1024 * 1024);
#endif
}
if ((dmparams.output == NTSC) && (dmparams.format == COMPOSITE))
dm->output_device_config = davincifb_ntsc_composite_config;
else if ((dmparams.output == NTSC) && (dmparams.format == SVIDEO))
dm->output_device_config = davincifb_ntsc_svideo_config;
else if ((dmparams.output == NTSC) && (dmparams.format == COMPONENT))
dm->output_device_config = davincifb_ntsc_component_config;
else if ((dmparams.output == PAL) && (dmparams.format == COMPOSITE))
dm->output_device_config = davincifb_pal_composite_config;
else if ((dmparams.output == PAL) && (dmparams.format == SVIDEO))
dm->output_device_config = davincifb_pal_svideo_config;
else if ((dmparams.output == PAL) && (dmparams.format == COMPONENT))
dm->output_device_config = davincifb_pal_component_config;
else if ((dmparams.output == HD720P) && (dmparams.format == COMPONENT))
dm->output_device_config = davincifb_720p_component_config;
else if ((dmparams.output == HD1080I) && (dmparams.format == COMPONENT))
dm->output_device_config = davincifb_1080i_component_config;
else if ((dmparams.output == HD480P) && (dmparams.format == COMPONENT))
dm->output_device_config = davincifb_480p_component_config;
/* Add support for other displays here */
else {
printk(KERN_WARNING "Unsupported output device!\n");
dm->output_device_config = NULL;
}
printk("Setting Up Clocks for DM420 OSD rev = %x\n", dispc_reg_in(VPBE_PID));
/* Initialize the VPSS Clock Control register */
dispc_reg_out(VPSS_CLKCTL, 0x18);
/* Set Base Pixel X and Base Pixel Y */
dispc_reg_out(OSD_BASEPX, BASEX);
dispc_reg_out(OSD_BASEPY, BASEY);
/* Reset OSD registers to default. */
dispc_reg_out(OSD_MODE, 0);
dispc_reg_out(OSD_OSDWIN0MD, 0);
/* Set blue background color */
set_bg_color(0, 162);
/* Field Inversion Workaround */
dispc_reg_out(OSD_MODE, 0x200);
dm->windows_mask = (1 << DAVINCIFB_WIN_OSD0) |
(1 << DAVINCIFB_WIN_OSD1) |
(1 << DAVINCIFB_WIN_VID0) |
(1 << DAVINCIFB_WIN_VID1);
dm_wins_probe(dm);
/* install our interrupt service routine */
if (request_irq(IRQ_VENCINT, davincifb_isr, IRQF_SHARED, MODULE_NAME,
dm)) {
dev_err(dm->dev, MODULE_NAME
": could not install interrupt service routine\n");
goto exit;
}
/* TODO remove this */
/* Turn ON the output device */
dm->output_device_config(1);
dm->output =
video_output_register("venc", dm->dev, dm, &output_props);
platform_set_drvdata(pdev, dm);
return 0;
exit:
davincifb_remove(pdev);
iounmap((void *)dm->mmio_base);
release_mmio:
release_mem_region(dm->mmio_base_phys, dm->mmio_size);
free_dm:
kfree(dm);
return -ENODEV;
}
static struct platform_driver davincifb_driver = {
.probe = davincifb_probe,
.remove = davincifb_remove,
.driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
},
};
/*
* Pass boot-time options by adding the following string to the boot params:
* video=davincifb:[option[:option]]
* Valid options:
* output=[lcd|ntsc|pal]
* format=[composite|s-video|component|rgb]
* vid0=[off|MxN@X,Y]
* vid1=[off|MxN@X,Y]
* osd0=[off|MxN@X,Y]
* osd1=[off|MxN@X,Y]
* MxN specify the window resolution (displayed size)
* X,Y specify the window position
* M, N, X, Y are integers
* M, X should be multiples of 16
*/
#ifndef MODULE
int __init davincifb_setup(char *options)
{
char *this_opt;
u32 xres, yres, xpos, ypos;
int format_xres = 720;
int format_yres = 480;
pr_debug("davincifb: Options \"%s\"\n", options);
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ":")) != NULL) {
if (!*this_opt)
continue;
if (!strncmp(this_opt, "output=", 7)) {
if (!strncmp(this_opt + 7, "lcd", 3)) {
dmparams.output = LCD;
dmparams.format = 0;
} else if (!strncmp(this_opt + 7, "ntsc", 4))
dmparams.output = NTSC;
else if (!strncmp(this_opt + 7, "pal", 3))
dmparams.output = PAL;
else if (!strncmp(this_opt + 7, "720p", 4)) {
dmparams.output = HD720P;
dmparams.format = COMPONENT;
} else if (!strncmp(this_opt + 7, "1080i", 5)) {
dmparams.output = HD1080I;
dmparams.format = COMPONENT;
} else if (!strncmp(this_opt + 7, "480p", 4)) {
dmparams.output = HD480P;
dmparams.format = COMPONENT;
}
} else if (!strncmp(this_opt, "format=", 7)) {
if (dmparams.output == LCD ||
dmparams.output == HD720P ||
dmparams.output == HD1080I ||
dmparams.output == HD480P)
continue;
if (!strncmp(this_opt + 7, "composite", 9))
dmparams.format = COMPOSITE;
else if (!strncmp(this_opt + 7, "s-video", 7))
dmparams.format = SVIDEO;
else if (!strncmp(this_opt + 7, "component", 9))
dmparams.format = COMPONENT;
else if (!strncmp(this_opt + 7, "rgb", 3))
dmparams.format = RGB;
} else if (!strncmp(this_opt, "vid0=", 5)) {
if (!strncmp(this_opt + 5, "off", 3))
dmparams.windows &= ~(1 << DAVINCIFB_WIN_VID0);
else if (!parse_win_params(this_opt + 5,
&xres, &yres, &xpos,
&ypos)) {
dmparams.vid0_xres = xres;
dmparams.vid0_yres = yres;
dmparams.vid0_xpos = xpos;
dmparams.vid0_ypos = ypos;
}
} else if (!strncmp(this_opt, "vid1=", 5)) {
if (!strncmp(this_opt + 5, "off", 3))
dmparams.windows &= ~(1 << DAVINCIFB_WIN_VID1);
else if (!parse_win_params(this_opt + 5,
&xres, &yres, &xpos,
&ypos)) {
dmparams.vid1_xres = xres;
dmparams.vid1_yres = yres;
dmparams.vid1_xpos = xpos;
dmparams.vid1_ypos = ypos;
}
} else if (!strncmp(this_opt, "osd0=", 5)) {
if (!strncmp(this_opt + 5, "off", 3))
dmparams.windows &= ~(1 << DAVINCIFB_WIN_OSD0);
else if (!parse_win_params(this_opt + 5,
&xres, &yres, &xpos,
&ypos)) {
dmparams.osd0_xres = xres;
dmparams.osd0_yres = yres;
dmparams.osd0_xpos = xpos;
dmparams.osd0_ypos = ypos;
}
} else if (!strncmp(this_opt, "osd1=", 5)) {
if (!strncmp(this_opt + 5, "off", 3))
dmparams.windows &= ~(1 << DAVINCIFB_WIN_OSD1);
else if (!parse_win_params(this_opt + 5,
&xres, &yres, &xpos,
&ypos)) {
dmparams.osd1_xres = xres;
dmparams.osd1_yres = yres;
dmparams.osd1_xpos = xpos;
dmparams.osd1_ypos = ypos;
}
}
}
printk(KERN_INFO "DaVinci: "
"Output on %s%s, Enabled windows: %s %s %s %s\n",
(dmparams.output == LCD) ? "LCD" :
(dmparams.output == HD720P) ? "HD720P":
(dmparams.output == HD1080I) ? "HD1080I":
(dmparams.output == HD480P) ? "HD480P":
(dmparams.output == NTSC) ? "NTSC" :
(dmparams.output == PAL) ? "PAL" : "unknown device!",
(dmparams.format == 0) ? "" :
(dmparams.format == COMPOSITE) ? " in COMPOSITE format" :
(dmparams.format == SVIDEO) ? " in SVIDEO format" :
(dmparams.format == COMPONENT) ? " in COMPONENT format" :
(dmparams.format == RGB) ? " in RGB format" : "",
(dmparams.windows & (1 << DAVINCIFB_WIN_VID0)) ? "Video0" : "",
(dmparams.windows & (1 << DAVINCIFB_WIN_VID1)) ? "Video1" : "",
(dmparams.windows & (1 << DAVINCIFB_WIN_OSD0)) ? "DAVINCIFB_WIN_OSD0" : "",
(dmparams.windows & (1 << DAVINCIFB_WIN_OSD1)) ? "DAVINCIFB_WIN_OSD1" : "");
if (dmparams.output == NTSC) {
format_yres = 480;
} else if (dmparams.output == PAL) {
format_yres = 576;
} else if (dmparams.output == HD720P) {
format_xres = DISP_XRES720P;
format_yres = DISP_YRES720P;
} else if (dmparams.output == HD1080I) {
format_xres = DISP_XRES1080I;
format_yres = DISP_YRES1080I;
} else if (dmparams.output == HD480P) {
format_xres = DISP_XRES480P;
format_yres = DISP_YRES480P;
} else {
printk(KERN_INFO
"DaVinci:invalid format..defaulting width to 480\n");
}
dmparams.osd0_xres = osd0_default_var.xres = format_xres;
dmparams.osd1_xres = osd1_default_var.xres = format_xres;
dmparams.vid0_xres = vid0_default_var.xres = format_xres;
dmparams.vid1_xres = vid1_default_var.xres = format_xres;
dmparams.osd0_yres = osd0_default_var.yres = format_yres;
dmparams.osd1_yres = osd1_default_var.yres = format_yres;
dmparams.vid0_yres = vid0_default_var.yres = format_yres;
dmparams.vid1_yres = vid1_default_var.yres = format_yres;
osd0_default_var.xres_virtual = round_32((format_xres)*16/8) * 8/16;
osd1_default_var.xres_virtual = round_32((format_xres)*16/8) * 8/16;
vid0_default_var.xres_virtual = round_32((format_xres)*16/8) * 8/16;
vid1_default_var.xres_virtual = round_32((format_xres)*16/8) * 8/16;
osd0_default_var.yres_virtual = format_yres * DOUBLE_BUF;
osd1_default_var.yres_virtual = format_yres * DOUBLE_BUF;
vid0_default_var.yres_virtual = format_yres * TRIPLE_BUF;
vid1_default_var.yres_virtual = format_yres * TRIPLE_BUF;
dmparams.osd0_phys = DAVINCI_FB_RESERVE_MEM_BASE;
dmparams.osd1_phys = dmparams.osd0_phys +
fb_window_size(format_xres, format_yres, DOUBLE_BUF);
dmparams.vid0_phys = dmparams.osd1_phys +
fb_window_size(format_xres, format_yres, DOUBLE_BUF);
dmparams.vid1_phys = dmparams.vid0_phys +
fb_window_size(format_xres, format_yres, TRIPLE_BUF);
if (dmparams.windows & (1 << DAVINCIFB_WIN_VID0))
printk(KERN_INFO "Setting Video0 size %dx%d, "
"position (%d,%d)\n",
dmparams.vid0_xres, dmparams.vid0_yres,
dmparams.vid0_xpos, dmparams.vid0_ypos);
if (dmparams.windows & (1 << DAVINCIFB_WIN_VID1))
printk(KERN_INFO "Setting Video1 size %dx%d, "
"position (%d,%d)\n",
dmparams.vid1_xres, dmparams.vid1_yres,
dmparams.vid1_xpos, dmparams.vid1_ypos);
if (dmparams.windows & (1 << DAVINCIFB_WIN_OSD0))
printk(KERN_INFO "Setting DAVINCIFB_WIN_OSD0 size %dx%d, "
"position (%d,%d)\n",
dmparams.osd0_xres, dmparams.osd0_yres,
dmparams.osd0_xpos, dmparams.osd0_ypos);
if (dmparams.windows & (1 << DAVINCIFB_WIN_OSD1))
printk(KERN_INFO "Setting DAVINCIFB_WIN_OSD1 size %dx%d, "
"position (%d,%d)\n",
dmparams.osd1_xres, dmparams.osd1_yres,
dmparams.osd1_xpos, dmparams.osd1_ypos);
return 0;
}
#endif
/*============================================================================*
* Module Interface *
*============================================================================*/
/* Register both the driver and the device */
int __init davincifb_init(void)
{
#ifndef MODULE
/* boot-line options */
/* handle options for "dm64xxfb" for backwards compatability */
char *option;
char *names[] = { "davincifb", "dm64xxfb" };
int i, num_names = 2, done = 0;
for (i = 0; i < num_names && !done; i++) {
if (fb_get_options(names[i], &option)) {
printk(MODULE_NAME
": Disabled on command-line.\n");
return -ENODEV;
} else if (option) {
davincifb_setup(option);
done = 1;
}
}
#endif
/* Register the driver with LDM */
if (platform_driver_register(&davincifb_driver)) {
pr_debug("failed to register davincifb driver\n");
return -ENODEV;
}
return 0;
}
static void __exit davincifb_cleanup(void)
{
platform_driver_unregister(&davincifb_driver);
}
module_init(davincifb_init);
module_exit(davincifb_cleanup);
MODULE_DESCRIPTION("Framebuffer driver for TI DaVinci");
MODULE_AUTHOR("Texas Instruments");
MODULE_LICENSE("GPL");
......@@ -178,6 +178,9 @@ extern struct page *alloc_page_vma(gfp_t gfp_mask,
extern unsigned long FASTCALL(__get_free_pages(gfp_t gfp_mask, unsigned int order));
extern unsigned long FASTCALL(get_zeroed_page(gfp_t gfp_mask));
void *alloc_pages_exact(size_t size, gfp_t gfp_mask);
void free_pages_exact(void *virt, size_t size);
#define __get_free_page(gfp_mask) \
__get_free_pages((gfp_mask),0)
......
......@@ -23,7 +23,8 @@
*
* REVISION:
*
* 1) Initial creation. ----------------------------------- 2007-11-13 JChen
* 1) Initial creation. ----------------------------------- 2008-06-10 JChen
* 2) Add support for HDMI user interface . --------------- 2008-06-23 JChen
*
*/
......@@ -235,5 +236,7 @@
#define AUDIO_IFOFRAMES_EN_RPT (0x30)
/*******************************HDMI Interface *********************/
#endif /* NEUROS_SIL9034__H */
unifdef-y += sisfb.h
unifdef-y += sisfb.h davincifb.h
......@@ -432,6 +432,25 @@
#define OSD_TRANSPVA_RGBTRANS_SHIFT 0
enum
{
DAVINCIFB_WIN_VID0,
DAVINCIFB_WIN_VID1,
DAVINCIFB_WIN_OSD0,
DAVINCIFB_WIN_OSD1,
DAVINCIFB_WINDOWS
};
enum
{
DAVINCIFB_OUT_COMPOSITE,
DAVINCIFB_OUT_COMPONENT,
DAVINCIFB_OUT_SVIDEO,
DAVINCIFB_OUT_RGB,
DAVINCIFB_OUTPUTS
};
#define LCD 0
#define NTSC 1
#define PAL 2
......@@ -457,4 +476,5 @@ struct zoom_params
};
#define FBIO_SETZOOM _IOW('F', 0x24, struct zoom_params)
#define FBIO_GETSTD _IOR('F', 0x25, u_int32_t)
#define FBIO_ENABLE _IOW('F', 0x26, u_int32_t)
#endif /* _DAVINCIFB_H_ */
......@@ -1467,6 +1467,59 @@ fastcall void free_pages(unsigned long addr, unsigned int order)
EXPORT_SYMBOL(free_pages);
/**
* alloc_pages_exact - allocate an exact number physically-contiguous pages.
* @size: the number of bytes to allocate
* @gfp_mask: GFP flags for the allocation
*
* This function is similar to alloc_pages(), except that it allocates the
* minimum number of pages to satisfy the request. alloc_pages() can only
* allocate memory in power-of-two pages.
*
* This function is also limited by MAX_ORDER.
*
* Memory allocated by this function must be released by free_pages_exact().
*/
void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
{
unsigned int order = get_order(size);
unsigned long addr;
addr = __get_free_pages(gfp_mask, order);
if (addr) {
unsigned long alloc_end = addr + (PAGE_SIZE << order);
unsigned long used = addr + PAGE_ALIGN(size);
split_page(virt_to_page(addr), order);
while (used < alloc_end) {
free_page(used);
used += PAGE_SIZE;
}
}
return (void *)addr;
}
EXPORT_SYMBOL(alloc_pages_exact);
/**
* free_pages_exact - release memory allocated via alloc_pages_exact()
* @virt: the value returned by alloc_pages_exact.
* @size: size of allocation, same value as passed to alloc_pages_exact().
*
* Release the memory allocated by a previous call to alloc_pages_exact.
*/
void free_pages_exact(void *virt, size_t size)
{
unsigned long addr = (unsigned long)virt;
unsigned long end = addr + PAGE_ALIGN(size);
while (addr < end) {
free_page(addr);
addr += PAGE_SIZE;
}
}
EXPORT_SYMBOL(free_pages_exact);
static unsigned int nr_free_zone_pages(int offset)
{
/* Just pick one node, since fallback list is circular */
......
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