diff options
author | Pawit Pornkitprasan <p.pawit@gmail.com> | 2011-12-24 09:34:37 +0700 |
---|---|---|
committer | Pawit Pornkitprasan <p.pawit@gmail.com> | 2011-12-24 09:35:11 +0700 |
commit | fdc19983538bec90010fa7f344a7417ff4731ba8 (patch) | |
tree | 8a84a1edd1c026b71fec4756caf27cbbb9e827d5 /drivers/media | |
parent | b55e9ac4df4d240b39eda4cd9c0198453dd59061 (diff) | |
download | kernel_samsung_aries-fdc19983538bec90010fa7f344a7417ff4731ba8.zip kernel_samsung_aries-fdc19983538bec90010fa7f344a7417ff4731ba8.tar.gz kernel_samsung_aries-fdc19983538bec90010fa7f344a7417ff4731ba8.tar.bz2 |
Added support for aries
Reverts "S5PC11X : FIMC apply v4l2 standard for asynchronous dequeue/queue"
5f4b037e6ebb18d65a3ac896032eb559d7fe2baf
Diffstat (limited to 'drivers/media')
70 files changed, 43082 insertions, 59 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 52798a1..a7ab498 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -357,6 +357,18 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" +config RADIO_SI4709 + bool "Silicon Labs Si4709 FM Radio Receiver support" + ---help--- + This is a driver for I2C devices with the Silicon Labs SI4709 + chip. + + Say Y here if you want to connect this type of radio to your + computer's I2C port. + + To compile this driver as a module, choose M here: the + module will be called radio-i2c-si470x. + config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index f484a6e..5d0e62f 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ +obj-$(CONFIG_RADIO_SI4709) += si4709/ obj-$(CONFIG_USB_MR800) += radio-mr800.o obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o diff --git a/drivers/media/radio/si4709/Makefile b/drivers/media/radio/si4709/Makefile new file mode 100644 index 0000000..d110423 --- /dev/null +++ b/drivers/media/radio/si4709/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Silicon Labs Si4709 FM Radio Receiver +# + +radio-si4709-i2c-objs := radio-si4709_dev.o radio-si4709_i2c_drv.o radio-si4709_main.o +obj-$(CONFIG_RADIO_SI4709) += radio-si4709-i2c.o diff --git a/drivers/media/radio/si4709/radio-si4709_common.h b/drivers/media/radio/si4709/radio-si4709_common.h new file mode 100755 index 0000000..c81ed92 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_common.h @@ -0,0 +1,41 @@ +#ifndef _COMMON_H +#define _COMMON_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <mach/gpio.h> + +//#define Si4709_DEBUG + +#define error(fmt,arg...) printk(KERN_CRIT fmt "\n",## arg) + +#ifdef Si4709_DEBUG +#define debug(fmt,arg...) printk(KERN_CRIT "--------" fmt "\n",## arg) +#else +#define debug(fmt,arg...) +#endif + +#define FM_RESET GPIO_FM_RST + +/*VNVS:28-OCT'09---- For testing FM tune and seek operation status*/ +#define TEST_FM + +/*VNVS:7-JUNE'10 ---- RDS Interrupt ON Always (Enabling interrupt when RDS is enabled)*/ +#define RDS_INTERRUPT_ON_ALWAYS + +/*VNVS:18-JUN'10---- For testing RDS*/ +/*Enable only for debugging RDS*/ +//#define RDS_TESTING +#ifdef RDS_TESTING +#define debug_rds(fmt,arg...) printk(KERN_CRIT "--------" fmt "\n",## arg) +#define GROUP_TYPE_2A ( 2 * 2 + 0) +#define GROUP_TYPE_2B ( 2 * 2 + 1) +#else +#define debug_rds(fmt,arg...) +#endif + +#define YES 1 +#define NO 0 + +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_dev.c b/drivers/media/radio/si4709/radio-si4709_dev.c new file mode 100644 index 0000000..6a65da9 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_dev.c @@ -0,0 +1,2563 @@ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/time.h> +#include <linux/workqueue.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> +#include <../../../arch/arm/mach-s5pv210/include/mach/gpio-aries.h> + +#include "radio-si4709_regs.h" +#include "radio-si4709_main.h" +#include "radio-si4709_dev.h" +#include "radio-si4709_common.h" + +enum +{ + eTRUE, + eFALSE, +}dev_struct_status_t; + +/*dev_state*/ +/*power_state*/ +#define RADIO_ON 1 +#define RADIO_POWERDOWN 0 +/*seek_state*/ +#define RADIO_SEEK_ON 1 +#define RADIO_SEEK_OFF 0 + +#define FREQ_87500_kHz 8750 +#define FREQ_76000_kHz 7600 + +#define RSSI_seek_th_MAX 0x7F +#define RSSI_seek_th_MIN 0x00 + +#define seek_SNR_th_DISB 0x00 +#define seek_SNR_th_MIN 0x01 /*most stops*/ +#define seek_SNR_th_MAX 0x0F /*fewest stops*/ + +#define seek_FM_ID_th_DISB 0x00 +#define seek_FM_ID_th_MAX 0x01 /*most stops*/ +#define seek_FM_ID_th_MIN 0x0F /*fewest stops*/ + +#define TUNE_RSSI_THRESHOLD 0x00 +#define TUNE_SNR_THRESHOLD 0x01 +#define TUNE_CNT_THRESHOLD 0x00 + +typedef struct +{ + u32 frequency; + u8 rsssi_val; +}channel_into_t; + +typedef struct +{ + u16 band; + u32 bottom_of_band; + u16 channel_spacing; + u32 timeout_RDS; /****For storing the jiffy value****/ + u32 seek_preset[NUM_SEEK_PRESETS]; + u8 curr_snr; + u8 curr_rssi_th; +}dev_settings_t; + +typedef struct +{ + /*Any function which + - views/modifies the fields of this structure + - does i2c communication + should lock the mutex before doing so. + Recursive locking should not be done. + In this file all the exported functions will take care + of this. The static functions will not deal with the + mutex*/ + struct mutex lock; + + struct i2c_client const *client; + + dev_state_t state; + + dev_settings_t settings; + + channel_into_t rssi_freq[50]; + + u16 registers[NUM_OF_REGISTERS]; + + /* This field will be checked by all the functions + exported by this file (except the init function), + to validate the the fields of this structure. + if eTRUE: the fileds are valid + if eFALSE: do not trust the values of the fields + of this structure*/ + unsigned short valid; + + /*will be true is the client ans state fields are correct*/ + unsigned short valid_client_state; +}Si4709_device_t; + + +/*extern functions*/ +/**********************************************/ +/*All the exported functions which view or modify the device + state/data, do i2c com will have to lock the mutex before + doing so*/ +/**********************************************/ +int Si4709_dev_init(struct i2c_client *); +int Si4709_dev_exit(void); + +void Si4709_dev_mutex_init(void); + +int Si4709_dev_suspend(void); +int Si4709_dev_resume(void); + +int Si4709_dev_powerup(void); +int Si4709_dev_powerdown(void); + +int Si4709_dev_band_set(int); +int Si4709_dev_ch_spacing_set(int); + +int Si4709_dev_chan_select(u32); +int Si4709_dev_chan_get(u32*); + +int Si4709_dev_seek_up(u32*); +int Si4709_dev_seek_down(u32*); +int Si4709_dev_seek_auto(u32*); + +int Si4709_dev_RSSI_seek_th_set(u8); +int Si4709_dev_seek_SNR_th_set(u8); +int Si4709_dev_seek_FM_ID_th_set(u8); +int Si4709_dev_cur_RSSI_get(rssi_snr_t*); +int Si4709_dev_VOLEXT_ENB(void); +int Si4709_dev_VOLEXT_DISB(void); +int Si4709_dev_volume_set(u8); +int Si4709_dev_volume_get(u8 *); +int Si4709_dev_DSMUTE_ON(void); +int Si4709_dev_DSMUTE_OFF(void); +int Si4709_dev_MUTE_ON(void); +int Si4709_dev_MUTE_OFF(void); +int Si4709_dev_MONO_SET(void); +int Si4709_dev_STEREO_SET(void); +int Si4709_dev_RDS_ENABLE(void); +int Si4709_dev_RDS_DISABLE(void); +int Si4709_dev_RDS_timeout_set(u32); +int Si4709_dev_rstate_get(dev_state_t*); +int Si4709_dev_RDS_data_get(radio_data_t*); +int Si4709_dev_device_id(device_id *); +int Si4709_dev_chip_id(chip_id *); +int Si4709_dev_sys_config2(sys_config2 *); +int Si4709_dev_power_config(power_config *); +int Si4709_dev_AFCRL_get(u8*); +int Si4709_dev_DE_set(u8); +/***********************************************/ + +#ifdef RDS_INTERRUPT_ON_ALWAYS +#define RDS_BUFFER_LENGTH 50 +static u16 *RDS_Block_Data_buffer; +static u8 *RDS_Block_Error_buffer; +static u8 RDS_Buffer_Index_read; //index number for last read data +static u8 RDS_Buffer_Index_write; //index number for last written data + +int Si4709_RDS_flag; +int RDS_Data_Available; +int RDS_Data_Lost; +int RDS_Groups_Available_till_now; +struct workqueue_struct *Si4709_wq; +struct work_struct Si4709_work; +#endif + +/*static functions*/ +/**********************************************/ +static void wait(void); + +static void wait_RDS(void ); + +static int powerup(void); +static int powerdown(void); + +static int seek(u32*, int); +static int tune_freq(u32); + +static void get_cur_chan_freq(u32 *, u16); + +static u16 freq_to_channel(u32); +static u32 channel_to_freq(u16); + +static int insert_preset(u32,u8,u8*); + +static int i2c_read(u8); +static int i2c_write(u8); +/**********************************************/ + +/*Si4709 device structure*/ +static Si4709_device_t Si4709_dev = +{ + .client = NULL, + .valid = eFALSE, + .valid_client_state = eFALSE, +}; + +/*Wait flag*/ +/*WAITING or WAIT_OVER or NO_WAIT*/ +int Si4709_dev_wait_flag = NO_WAIT; +#ifdef RDS_INTERRUPT_ON_ALWAYS +int Si4709_RDS_flag = NO_WAIT; +#endif + +int Si4709_dev_init(struct i2c_client *client) +{ + int ret = 0; + + debug("Si4709_dev_init called"); + + mutex_lock(&(Si4709_dev.lock)); + + Si4709_dev.client = client; + + /***reset the device here****/ + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + mdelay(1); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + mdelay(2); + + s3c_gpio_setpull(GPIO_FM_INT, S3C_GPIO_PULL_UP); + s3c_gpio_slp_setpull_updown(GPIO_FM_INT, S3C_GPIO_PULL_UP); + + Si4709_dev.state.power_state = RADIO_POWERDOWN; + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + + if( (ret = i2c_read(BOOTCONFIG) ) < 0 ) + { + debug("i2c_read failed"); + } + else + { + Si4709_dev.valid_client_state = eTRUE; + } + +#ifdef RDS_INTERRUPT_ON_ALWAYS + /*Creating Circular Buffer*/ + /*Single RDS_Block_Data buffer size is 4x16 bits*/ + RDS_Block_Data_buffer = kzalloc(RDS_BUFFER_LENGTH*8,GFP_KERNEL); + if(!RDS_Block_Data_buffer) + { + error("Not sufficient memory for creating RDS_Block_Data_buffer"); + ret = -ENOMEM; + goto EXIT; + } + + /*Single RDS_Block_Error buffer size is 4x8 bits*/ + RDS_Block_Error_buffer = kzalloc(RDS_BUFFER_LENGTH*4,GFP_KERNEL); + if(!RDS_Block_Error_buffer) + { + error("Not sufficient memory for creating RDS_Block_Error_buffer"); + ret = -ENOMEM; + kfree(RDS_Block_Data_buffer); + goto EXIT; + } + + /*Initialising read and write indices*/ + RDS_Buffer_Index_read= 0; + RDS_Buffer_Index_write= 0; + + /*Creating work-queue*/ + Si4709_wq = create_singlethread_workqueue("Si4709_wq"); + if(!Si4709_wq) + { + error("Not sufficient memory for Si4709_wq, work-queue"); + ret = -ENOMEM; + kfree(RDS_Block_Error_buffer); + kfree(RDS_Block_Data_buffer); + goto EXIT; + } + + /*Initialising work_queue*/ + INIT_WORK(&Si4709_work, Si4709_work_func); + + RDS_Data_Available = 0; + RDS_Data_Lost =0; + RDS_Groups_Available_till_now = 0; +EXIT: +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_init call over"); + + return ret; +} + +int Si4709_dev_exit(void) +{ + int ret = 0; + + debug("Si4709_dev_exit called"); + + mutex_lock(&(Si4709_dev.lock)); + + // Temporary blocked by abnormal function call(E-CIM 2657654) - DW Shim. 2010.03.04 + printk(KERN_ERR "Si4709_dev_exit() is called!!"); +// Si4709_dev.client = NULL; + +// Si4709_dev.valid_client_state = eFALSE; +// Si4709_dev.valid = eFALSE; + +#ifdef RDS_INTERRUPT_ON_ALWAYS + if(Si4709_wq) + destroy_workqueue(Si4709_wq); + + if(RDS_Block_Error_buffer) + kfree(RDS_Block_Error_buffer); + + if(RDS_Block_Data_buffer) + kfree(RDS_Block_Data_buffer); +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_exit call over"); + + return ret; +} + +void Si4709_dev_mutex_init(void) +{ + mutex_init(&(Si4709_dev.lock)); +} + +int Si4709_dev_powerup(void) +{ + int ret = 0; + u32 value = 100; + + debug("Si4709_dev_powerup called"); + + mutex_lock(&(Si4709_dev.lock)); + + if(!(RADIO_ON==Si4709_dev.state.power_state)) + { + if( (ret = powerup()) < 0 ) + { + debug("powerup failed"); + } + else if( Si4709_dev.valid_client_state == eFALSE ) + { + debug("Si4709_dev_powerup called when DS (state, client) is invalid"); + ret = -1; + } + else + { + /*initial settings*/ +#if 0 + POWERCFG_BITSET_RDSM_LOW(&Si4709_dev.registers[POWERCFG]); +#else + POWERCFG_BITSET_RDSM_HIGH(&Si4709_dev.registers[POWERCFG]); +#endif + // POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_SKMODE_LOW(&Si4709_dev.registers[POWERCFG]); /*VNVS:18-NOV'09---- wrap at the upper and lower band limit and continue seeking*/ + SYSCONFIG1_BITSET_STCIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RDS_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_DE_50(&Si4709_dev.registers[SYSCONFIG1]); /*VNVS:18-NOV'09--- Setting DE-Time Constant as 50us(Europe,Japan,Australia)*/ + SYSCONFIG1_BITSET_GPIO_STC_RDS_INT(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG1]); + + // SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2],2); + SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2], TUNE_RSSI_THRESHOLD); /*VNVS:18-NOV'09---- modified for detecting more stations of good quality*/ + SYSCONFIG2_BITSET_VOLUME(&Si4709_dev.registers[SYSCONFIG2],0x0F); + SYSCONFIG2_BITSET_BAND_87p5_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_87500_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; + + SYSCONFIG2_BITSET_SPACE_100_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_100_kHz; + + + // SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3],3); + SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3], TUNE_SNR_THRESHOLD);/*VNVS:18-NOV'09---- modified for detecting more stations of good quality*/ + SYSCONFIG3_BITSET_SKCNT(&Si4709_dev.registers[SYSCONFIG3], TUNE_CNT_THRESHOLD); + + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + Si4709_dev.settings.timeout_RDS = msecs_to_jiffies(value); + Si4709_dev.settings.curr_snr = TUNE_SNR_THRESHOLD; + Si4709_dev.settings.curr_rssi_th = TUNE_RSSI_THRESHOLD; + + /*this will write all the above registers*/ + if( (ret = i2c_write(SYSCONFIG3)) < 0 ) + { + debug("Si4709_dev_powerup i2c_write 1 failed"); + } + else + { + Si4709_dev.valid = eTRUE; +#ifdef RDS_INTERRUPT_ON_ALWAYS + /*Initialising read and write indices*/ + RDS_Buffer_Index_read= 0; + RDS_Buffer_Index_write= 0; + + RDS_Data_Available = 0; + RDS_Data_Lost =0; + RDS_Groups_Available_till_now = 0; +#endif + } + + } + } + else + debug("Device already Powered-ON"); + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +int Si4709_dev_powerdown(void) +{ + int ret = 0; + + msleep(500); // For avoiding turned off pop noise + debug("Si4709_dev_powerdown called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_powerdown called when DS is invalid"); + ret = -1; + } + else if ( ( ret = powerdown()) < 0 ) + { + debug("powerdown failed"); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_suspend(void) +{ + int ret = 0; + + debug("Si4709_dev_suspend called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid_client_state== eFALSE ) + { + debug("Si4709_dev_suspend called when DS (state, client) is invalid"); + ret = -1; + } +#if 0 + else if( Si4709_dev.state.power_state == RADIO_ON ) + { + ret = powerdown(); + } +#endif + + mutex_unlock(&(Si4709_dev.lock)); + + debug("Si4709_dev_enable call over"); + + return ret; +} + +int Si4709_dev_resume(void) +{ + int ret = 0; + +// debug("Si4709_dev_resume called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid_client_state == eFALSE ) + { + debug("Si4709_dev_resume called when DS (state, client) is invalid"); + ret = -1; + } +#if 0 + else if( Si4709_dev.state.power_state == RADIO_POWERDOWN ) + { + if( (ret = powerup()) < 0 ) + { + debug("powerup failed"); + } + } +#endif + + mutex_unlock(&(Si4709_dev.lock)); + +// debug("Si4709_dev_disable call over"); + + return ret; +} + +int Si4709_dev_band_set(int band) +{ + int ret = 0; + u16 sysconfig2 =0; + u16 prev_band = 0; + u32 prev_bottom_of_band = 0; + + debug("Si4709_dev_band_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + prev_band = Si4709_dev.settings.band; + prev_bottom_of_band = Si4709_dev.settings.bottom_of_band; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_band_set called when DS is invalid"); + ret = -1; + } + else + { + switch (band) + { + case BAND_87500_108000_kHz: + SYSCONFIG2_BITSET_BAND_87p5_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_87500_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_87500_kHz; + break; + + case BAND_76000_108000_kHz: + SYSCONFIG2_BITSET_BAND_76_108_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_76000_108000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; + break; + + case BAND_76000_90000_kHz: + SYSCONFIG2_BITSET_BAND_76_90_MHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.band = BAND_76000_90000_kHz; + Si4709_dev.settings.bottom_of_band = FREQ_76000_kHz; + break; + + default: + ret = -1; + } + + if(ret == 0) + { + if( (ret = i2c_write(SYSCONFIG2)) < 0 ) + { + debug("Si4709_dev_band_set i2c_write 1 failed"); + Si4709_dev.settings.band = prev_band; + Si4709_dev.settings.bottom_of_band = prev_bottom_of_band; + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_ch_spacing_set(int ch_spacing) +{ + int ret = 0; + u16 sysconfig2 = 0; + u16 prev_ch_spacing = 0; + + debug("Si4709_dev_ch_spacing_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + prev_ch_spacing = Si4709_dev.settings.channel_spacing; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_ch_spacing_set called when DS is invalid"); + ret = -1; + } + else + { + switch (ch_spacing) + { + case CHAN_SPACING_200_kHz: + SYSCONFIG2_BITSET_SPACE_200_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_200_kHz; + break; + + case CHAN_SPACING_100_kHz: + SYSCONFIG2_BITSET_SPACE_100_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_100_kHz; + break; + + case CHAN_SPACING_50_kHz: + SYSCONFIG2_BITSET_SPACE_50_KHz(&Si4709_dev.registers[SYSCONFIG2]); + Si4709_dev.settings.channel_spacing = CHAN_SPACING_50_kHz; + break; + + default: + ret = -1; + } + + if(ret == 0) + { + if( (ret = i2c_write(SYSCONFIG2)) < 0 ) + { + debug("Si4709_dev_ch_spacing_set i2c_write 1 failed"); + Si4709_dev.settings.channel_spacing = prev_ch_spacing; + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chan_select(u32 frequency) +{ + int ret = 0; + + debug("Si4709_dev_chan_select called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chan_select called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = tune_freq(frequency); + debug("Si4709_dev_chan_select called1"); + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chan_get(u32 *frequency) +{ + int ret = 0; + + + debug("Si4709_dev_chan_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chan_get called when DS is invalid"); + ret = -1; + } + else if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("Si4709_dev_chan_get i2c_read failed"); + } + else + { + get_cur_chan_freq(frequency, Si4709_dev.registers[READCHAN]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_up(u32 *frequency) +{ + int ret = 0; + + debug("Si4709_dev_seek_up called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_up called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = seek(frequency, 1); + + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_down(u32 *frequency) +{ + int ret = 0; + + debug("Si4709_dev_seek_down called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_down called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.state.seek_state = RADIO_SEEK_ON; + + ret = seek(frequency, 0); + + Si4709_dev.state.seek_state = RADIO_SEEK_OFF; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +#if 0 +int Si4709_dev_seek_auto(u32 *seek_preset_user) +{ + u8 *rssi_seek; + int ret = 0; + int i =0; + int j = 0; + channel_into_t temp; + + debug("Si4709_dev_seek_auto called"); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_auto called when DS is invalid"); + ret = -1; + } + + else if( (rssi_seek = (u8 *)kzalloc(sizeof(u8) * NUM_SEEK_PRESETS, GFP_KERNEL)) == NULL ) + { + debug("Si4709_ioctl: no memory"); + ret = -ENOMEM; + } + + else + { + + if( (ret = tune_freq(FREQ_87500_kHz)) == 0 ) + { + debug("Si4709_dev_seek_auto tune_freq success"); + get_cur_chan_freq(&(Si4709_dev.rssi_freq[0].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[0].rsssi_val)); + + } + else + { + debug("tunning failed, seek auto failed"); + ret =-1; + } + #if 0 + for(i=0;i<50; i++) + { + if( (ret = seek(&(Si4709_dev.settings.seek_preset[i]),1)) == 0 ) + { + get_cur_chan_freq(&(Si4709_dev.rssi_freq[i].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[i].rsssi_val)); + rssi_seek ++; + } + + else + { + debug("seek failed"); + + } + } + #endif + + + + /***new method ****/ + for(i=1;i<30; i++) + { + if( (ret = seek(&(Si4709_dev.settings.seek_preset[i]),1)) == 0 ) + { + get_cur_chan_freq(&(Si4709_dev.rssi_freq[i].frequency), Si4709_dev.registers[READCHAN]); + Si4709_dev_cur_RSSI_get(&(Si4709_dev.rssi_freq[i].rsssi_val)); + } + + else + { + debug("seek failed"); + + } + } + /***Sort the array of structures on the basis of RSSI value****/ + for(i=0;i<29;i++) + { + + for(j=i+1;j<30;j++) + { + + if( Si4709_dev.rssi_freq[j].rsssi_val>Si4709_dev.rssi_freq[i].rsssi_val) + { + temp=Si4709_dev.rssi_freq[i]; + Si4709_dev.rssi_freq[i]=Si4709_dev.rssi_freq[j]; + Si4709_dev.rssi_freq[j]=temp; + } + + } + + } + + /***Store the frequency in Array*****/ + for(i=0;i<19;i++) + { + Si4709_dev.settings.seek_preset[i]=Si4709_dev.rssi_freq[i].frequency; + } + + + + } + memcpy(seek_preset_user, Si4709_dev.settings.seek_preset , sizeof(int)*NUM_SEEK_PRESETS); + kfree(rssi_seek); + return ret; +} +#endif + + + +int Si4709_dev_RSSI_seek_th_set(u8 seek_th) +{ + int ret = 0; + u16 sysconfig2 = 0; + + debug("Si4709_dev_RSSI_seek_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RSSI_seek_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG2_BITSET_SEEKTH(&Si4709_dev.registers[SYSCONFIG2], seek_th); + Si4709_dev.settings.curr_rssi_th=seek_th; + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_RSSI_seek_th_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_SNR_th_set(u8 seek_SNR) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_seek_SNR_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_SNR_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_SKSNR(&Si4709_dev.registers[SYSCONFIG3], seek_SNR); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + Si4709_dev.settings.curr_snr=seek_SNR; + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_seek_SNR_th_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_seek_FM_ID_th_set(u8 seek_FM_ID_th) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_seek_FM_ID_th_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_seek_SNR_th_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_SKCNT(&Si4709_dev.registers[SYSCONFIG3], seek_FM_ID_th); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_seek_FM_ID_th_set i2c_write 1 failed"); + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_cur_RSSI_get(rssi_snr_t *cur_RSSI) +{ + int ret = 0; + + debug("Si4709_dev_cur_RSSI_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_cur_RSSI_get called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("Si4709_dev_cur_RSSI_get i2c_read 1 failed"); + } + else + { + + cur_RSSI->curr_rssi= STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + cur_RSSI->curr_rssi_th=Si4709_dev.settings.curr_rssi_th; + cur_RSSI->curr_snr=Si4709_dev.settings.curr_snr; + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/*VNVS:START 13-OCT'09---- Functions which reads device-id,chip-id,power configuration, system configuration2 registers */ +int Si4709_dev_device_id(device_id *dev_id) +{ + int ret = 0; + + debug("Si4709_dev_device_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_device_id called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(DEVICE_ID)) < 0 ) + { + debug("Si4709_dev_device_id i2c_read failed"); + } + else + { + + dev_id->part_number= DEVICE_ID_PART_NUMBER(Si4709_dev.registers[DEVICE_ID]); + dev_id->manufact_number = DEVICE_ID_MANUFACT_NUMBER(Si4709_dev.registers[DEVICE_ID]); + + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_chip_id(chip_id *chp_id) +{ + int ret = 0; + + debug("Si4709_dev_chip_id called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_chip_id called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(CHIP_ID)) < 0 ) + { + debug("Si4709_dev_chip_id i2c_read failed"); + } + else + { + + chp_id->chip_version= CHIP_ID_CHIP_VERSION(Si4709_dev.registers[CHIP_ID]); + chp_id->device = CHIP_ID_DEVICE(Si4709_dev.registers[CHIP_ID]); + chp_id->firmware_version = CHIP_ID_FIRMWARE_VERSION(Si4709_dev.registers[CHIP_ID]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config2(sys_config2 *sys_conf2) +{ + int ret = 0; + + debug("Si4709_sys_config2 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_sys_config2 called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(SYSCONFIG2)) < 0) + { + debug("Si4709_sys_config2 i2c_read failed"); + } + else + { + sys_conf2->rssi_th =SYS_CONFIG2_RSSI_TH(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_band = SYS_CONFIG2_FM_BAND(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_chan_spac = SYS_CONFIG2_FM_CHAN_SPAC(Si4709_dev.registers[SYSCONFIG2]); + sys_conf2->fm_vol = SYS_CONFIG2_FM_VOL(Si4709_dev.registers[SYSCONFIG2]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config3(sys_config3 *sys_conf3) +{ + int ret = 0; + + debug("Si4709_sys_config3 called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_sys_config3 called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(SYSCONFIG3)) < 0) + { + debug("Si4709_sys_config3 i2c_read failed"); + } + else + { + sys_conf3->smmute = (Si4709_dev.registers[SYSCONFIG3] & 0xC000) >> 14; + sys_conf3->smutea = (Si4709_dev.registers[SYSCONFIG3] & 0x3000) >> 12; + sys_conf3->volext = (Si4709_dev.registers[SYSCONFIG3] & 0x0100) >> 8; + sys_conf3->sksnr = (Si4709_dev.registers[SYSCONFIG3] & 0x00F0) >> 4; + sys_conf3->skcnt = (Si4709_dev.registers[SYSCONFIG3] & 0x000F); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_status_rssi(status_rssi *status) +{ + int ret = 0; + + debug("Si4709_dev_status_rssi called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_status_rssi called when DS is invalid"); + ret = -1; + } + else + { + if((ret = i2c_read(STATUSRSSI)) < 0) + { + debug("Si4709_sys_config3 i2c_read failed"); + } + else + { + status->rdsr = (Si4709_dev.registers[STATUSRSSI] & 0x8000) >> 15; + status->stc = (Si4709_dev.registers[STATUSRSSI] & 0x4000) >> 14; + status->sfbl = (Si4709_dev.registers[STATUSRSSI] & 0x2000) >> 13; + status->afcrl = (Si4709_dev.registers[STATUSRSSI] & 0x1000) >> 12; + status->rdss = (Si4709_dev.registers[STATUSRSSI] & 0x0800) >> 11; + status->blera = (Si4709_dev.registers[STATUSRSSI] & 0x0600) >> 9; + status->st = (Si4709_dev.registers[STATUSRSSI] & 0x0100) >> 8; + status->rssi = (Si4709_dev.registers[STATUSRSSI] & 0x00FF); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config2_set(sys_config2 *sys_conf2) +{ + int ret = 0; + u16 register_bak = 0; + + debug("Si4709_dev_sys_config2_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + register_bak = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_sys_config2_set called when DS is invalid"); + ret = -1; + } + else + { + printk(KERN_ERR "Si4709_dev_sys_config2_set() : Register Value = [0x%X], rssi-th = [%X]\n", Si4709_dev.registers[SYSCONFIG2], sys_conf2->rssi_th); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0x00FF) | ((sys_conf2->rssi_th) << 8); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFF3F) | ((sys_conf2->fm_band) << 6); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFFCF) | ((sys_conf2->fm_chan_spac) << 4); + Si4709_dev.registers[SYSCONFIG2] = (Si4709_dev.registers[SYSCONFIG2] & 0xFFF0) | (sys_conf2->fm_vol); + printk(KERN_ERR "Si4709_dev_sys_config2_set() : After Register Value = [0x%X]\n", Si4709_dev.registers[SYSCONFIG2]); + + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_sys_config2_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG2] = register_bak; + } + else + printk(KERN_ERR "Si4709_dev_sys_config2_set() : Write Sucess!!"); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_sys_config3_set(sys_config3 *sys_conf3) +{ + int ret = 0; + u16 register_bak = 0; + + debug("Si4709_dev_sys_config3_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + register_bak = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_sys_config3_set called when DS is invalid"); + ret = -1; + } + else + { + printk(KERN_ERR "Si4709_dev_sys_config3_set() : Register Value = [0x%X], sksnrth = [%X]\n", Si4709_dev.registers[SYSCONFIG3], sys_conf3->sksnr); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0x3FFF) | ((sys_conf3->smmute) << 14); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xCFFF) | ((sys_conf3->smutea) << 12); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFEFF) | ((sys_conf3->volext) << 8); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFF0F) | ((sys_conf3->sksnr) << 4); + Si4709_dev.registers[SYSCONFIG3] = (Si4709_dev.registers[SYSCONFIG3] & 0xFFF0) | (sys_conf3->skcnt); + printk(KERN_ERR "Si4709_dev_sys_config3_set() : After Register Value = [0x%X]\n", Si4709_dev.registers[SYSCONFIG3]); + + if((ret = i2c_write( SYSCONFIG3)) < 0) + { + debug("Si4709_dev_sys_config3_set i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG3] = register_bak; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_power_config(power_config *pow_conf) +{ + int ret =0; + + debug("Si4709_dev_power_config called"); + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_power_config called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(POWERCFG)) < 0 ) + { + debug("Si4709_dev_power_config i2c_read failed"); + } + else + { + + pow_conf->dsmute =POWER_CONFIG_SOFTMUTE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->dmute =POWER_CONFIG_MUTE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->mono =POWER_CONFIG_MONO_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->rds_mode =POWER_CONFIG_RDS_MODE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->sk_mode =POWER_CONFIG_SKMODE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->seek_up =POWER_CONFIG_SEEKUP_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->seek =POWER_CONFIG_SEEK_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->power_disable =POWER_CONFIG_DISABLE_STATUS(Si4709_dev.registers[POWERCFG]); + pow_conf->power_enable =POWER_CONFIG_ENABLE_STATUS(Si4709_dev.registers[POWERCFG]); + } + } + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ + +/*VNVS:START 18-NOV'09*/ +/*Reading AFCRL Bit*/ +int Si4709_dev_AFCRL_get(u8 *afc) +{ + int ret = 0; + + debug("Si4709_dev_AFCRL_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_AFCRL_get called when DS is invalid"); + ret = -1; + } + else + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("Si4709_dev_AFCRL_get i2c_read failed"); + } + *afc = STATUSRSSI_AFC_RAIL_STATUS(Si4709_dev.registers[STATUSRSSI]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*Setting DE-emphasis time constant 50us(Europe,Japan,Australia) or 75us(USA)*/ +int Si4709_dev_DE_set(u8 de_tc) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_DE_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DE_set called when DS is invalid"); + ret = -1; + } + else + { + switch(de_tc) + { + case DE_TIME_CONSTANT_50: + SYSCONFIG1_BITSET_DE_50(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + break; + case DE_TIME_CONSTANT_75: + SYSCONFIG1_BITSET_DE_75(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + break; + default: + ret = -1; + } + + if(0==ret) + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_DE_set i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/*Resetting the RDS Data Buffer*/ +int Si4709_dev_reset_rds_data() +{ + int ret = 0; + + debug_rds("Si4709_dev_reset_rds_data called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_reset_rds_data called when DS is invalid"); + ret = -1; + } + else + { + RDS_Buffer_Index_write = 0; + RDS_Buffer_Index_read = 0; + RDS_Data_Lost = 0; + RDS_Data_Available = 0; + memset(RDS_Block_Data_buffer,0,RDS_BUFFER_LENGTH*8); + memset(RDS_Block_Error_buffer,0,RDS_BUFFER_LENGTH*4); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ +int Si4709_dev_VOLEXT_ENB(void) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_VOLEXT_ENB called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_VOLEXT_ENB called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_VOLEXT_ENB(&Si4709_dev.registers[SYSCONFIG3]); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_VOLEXT_ENB i2c_write failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_VOLEXT_DISB(void) +{ + int ret = 0; + u16 sysconfig3 = 0; + + debug("Si4709_dev_VOLEXT_DISB called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig3 = Si4709_dev.registers[SYSCONFIG3]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_VOLEXT_DISB called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG3_BITSET_VOLEXT_DISB(&Si4709_dev.registers[SYSCONFIG3]); + SYSCONFIG3_BITSET_RESERVED(&Si4709_dev.registers[SYSCONFIG3]); + + if( (ret = i2c_write( SYSCONFIG3 )) < 0 ) + { + debug("Si4709_dev_VOLEXT_DISB i2c_write failed"); + Si4709_dev.registers[SYSCONFIG3] = sysconfig3; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_volume_set(u8 volume) +{ + int ret = 0; + u16 sysconfig2 = 0; + + debug("Si4709_dev_volume_set called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig2 = Si4709_dev.registers[SYSCONFIG2]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_volume_set called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG2_BITSET_VOLUME(&Si4709_dev.registers[SYSCONFIG2], volume); + + if( (ret = i2c_write( SYSCONFIG2 )) < 0 ) + { + debug("Si4709_dev_volume_set i2c_write failed"); + Si4709_dev.registers[SYSCONFIG2] = sysconfig2; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_volume_get(u8 *volume) +{ + int ret = 0; + + debug("Si4709_dev_volume_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_volume_get called when DS is invalid"); + ret = -1; + } + else + { + *volume = SYSCONFIG2_GET_VOLUME(Si4709_dev.registers[SYSCONFIG2]); + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +/* + VNVS:START 19-AUG'10---- Adding DSMUTE ON/OFF feature.The Soft Mute feature is available to attenuate the audio + outputs and minimize audible noise in very weak signal conditions. + */ +int Si4709_dev_DSMUTE_ON(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_DSMUTE_ON called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DSMUTE_ON called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DSMUTE_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + error("Si4709_dev_DSMUTE_ON i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_DSMUTE_OFF(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_DSMUTE_OFF called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_DSMUTE_OFF called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DSMUTE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + error("Si4709_dev_DSMUTE_OFF i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} +/*VNVS:END*/ + +int Si4709_dev_MUTE_ON(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MUTE_ON called"); + + mutex_lock(&(Si4709_dev.lock)); + powercfg = Si4709_dev.registers[POWERCFG]; + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MUTE_ON called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DMUTE_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MUTE_ON i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_MUTE_OFF(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MUTE_OFF called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MUTE_OFF called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_DMUTE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MUTE_OFF i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_MONO_SET(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_MONO_SET called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_MONO_SET called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_MONO_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_MONO_SET i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_STEREO_SET(void) +{ + int ret = 0; + u16 powercfg = 0; + + debug("Si4709_dev_STEREO_SET called"); + + mutex_lock(&(Si4709_dev.lock)); + + powercfg = Si4709_dev.registers[POWERCFG]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_STEREO_SET called when DS is invalid"); + ret = -1; + } + else + { + POWERCFG_BITSET_MONO_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write( POWERCFG )) < 0 ) + { + debug("Si4709_dev_STEREO_SET i2c_write failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_RDS_ENABLE(void) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_RDS_ENABLE called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_ENABLE called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG1_BITSET_RDS_HIGH(&Si4709_dev.registers[SYSCONFIG1]); +#ifdef RDS_INTERRUPT_ON_ALWAYS + SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); +#endif + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_RDS_ENABLE i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } +#ifdef RDS_INTERRUPT_ON_ALWAYS + else + Si4709_RDS_flag = RDS_WAITING; +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + + +int Si4709_dev_RDS_DISABLE(void) +{ + u16 sysconfig1 = 0; + int ret = 0; + + debug("Si4709_dev_RDS_DISABLE called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_DISABLE called when DS is invalid"); + ret = -1; + } + else + { + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev.registers[SYSCONFIG1]); +#ifdef RDS_INTERRUPT_ON_ALWAYS + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); +#endif + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + if( (ret = i2c_write(SYSCONFIG1)) < 0 ) + { + debug("Si4709_dev_RDS_DISABLE i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } +#ifdef RDS_INTERRUPT_ON_ALWAYS + else + Si4709_RDS_flag = NO_WAIT; +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +int Si4709_dev_rstate_get(dev_state_t *dev_state) +{ + int ret = 0; + + debug("Si4709_dev_rstate_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_rstate_get called when DS is invalid"); + ret = -1; + } + else + { + dev_state->power_state = Si4709_dev.state.power_state; + dev_state->seek_state = Si4709_dev.state.seek_state; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +/*VNVS:START 7-JUNE'10 Function call for work-queue "Si4709_wq"*/ +#ifdef RDS_INTERRUPT_ON_ALWAYS +void Si4709_work_func(struct work_struct *work) +{ + int i,ret = 0; +#ifdef RDS_TESTING + u8 group_type; +#endif + debug_rds("%s",__func__); +// mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + error("Si4709_dev_RDS_data_get called when DS is invalid"); + ret = -1; + } + else + { + + if(RDS_Data_Lost > 1) + debug_rds("No_of_RDS_groups_Lost till now : %d",RDS_Data_Lost); + + + /*RDSR bit and RDS Block data, so reading the RDS registers*/ + if((ret = i2c_read(RDSD)) < 0) + error("Si4709_work_func i2c_read failed"); + else + { + /*Checking whether RDS Ready bit is set or not, if not set return immediately*/ + if(!(STATUSRSSI_RDS_READY_STATUS(Si4709_dev.registers[STATUSRSSI]))) + { + error("RDS Ready Bit Not set"); + return; + } + + debug_rds("RDS Ready bit is set"); + + debug_rds("No_of_RDS_groups_Available : %d",RDS_Data_Available); + + RDS_Data_Available = 0; + + debug_rds("RDS_Buffer_Index_write = %d",RDS_Buffer_Index_write); + + /*Writing into the Circular Buffer*/ + + /*Writing into RDS_Block_Data_buffer*/ + i = 0; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSA]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSB]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSC]; + RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_write] = Si4709_dev.registers[RDSD]; + + /*Writing into RDS_Block_Error_buffer*/ + i = 0; + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = STATUSRSSI_RDS_BLOCK_A_ERRORS(Si4709_dev.registers[STATUSRSSI]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_B_ERRORS(Si4709_dev.registers[READCHAN]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_C_ERRORS(Si4709_dev.registers[READCHAN]); + RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_write] = READCHAN_BLOCK_D_ERRORS(Si4709_dev.registers[READCHAN]); + +#ifdef RDS_TESTING + if(RDS_Block_Error_buffer[0 + 4*RDS_Buffer_Index_write] < 3) + { + debug_rds("PI Code is %d",RDS_Block_Data_buffer[0 + 4*RDS_Buffer_Index_write]); + } + if(RDS_Block_Error_buffer[1 + 4*RDS_Buffer_Index_write] < 2) + { + group_type = RDS_Block_Data_buffer[1 + 4*RDS_Buffer_Index_write] >> 11; + + if (group_type & 0x01) + { + debug_rds("PI Code is %d",RDS_Block_Data_buffer[2 + 4*RDS_Buffer_Index_write]); + } + if(group_type == GROUP_TYPE_2A || group_type == GROUP_TYPE_2B ) + { + if(RDS_Block_Error_buffer[2 + 4*RDS_Buffer_Index_write] < 3) + { + debug_rds("Update RT with RDSC"); + } + else + { + debug_rds("RDS_Block_Error_buffer of Block C is greater than 3"); + } + } + } +#endif + RDS_Buffer_Index_write++; + + if(RDS_Buffer_Index_write >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_write = 0; + + debug_rds("RDS_Buffer_Index_write = %d",RDS_Buffer_Index_write); + } + } + +// mutex_unlock(&(Si4709_dev.lock)); +} +#endif +/*VNVS:END*/ + +int Si4709_dev_RDS_data_get(radio_data_t *data) +{ + int i,ret = 0; + u16 sysconfig1 = 0; + + debug_rds("Si4709_dev_RDS_data_get called"); + + mutex_lock(&(Si4709_dev.lock)); + + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + if( Si4709_dev.valid == eFALSE ) + { + error("Si4709_dev_RDS_data_get called when DS is invalid"); + ret = -1; + } + else + { +#ifdef RDS_INTERRUPT_ON_ALWAYS + + debug_rds("RDS_Buffer_Index_read = %d",RDS_Buffer_Index_read); + + /*If No New RDS Data is available return error*/ + if(RDS_Buffer_Index_read == RDS_Buffer_Index_write) + { + debug_rds("No_New_RDS_Data_is_available"); + if((ret = i2c_read(READCHAN)) < 0) + error("Si4709_dev_RDS_data_get i2c_read 1 failed"); + else + { + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug_rds("curr_channel: %u, curr_rssi:%u",data->curr_channel,(u32)data->curr_rssi); + } + ret = -1; + } + else + { + if((ret = i2c_read(READCHAN)) < 0) + error("Si4709_dev_RDS_data_get i2c_read 2 failed"); + else + { + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug_rds("curr_channel: %u, curr_rssi:%u",data->curr_channel,(u32)data->curr_rssi); + + /*Reading from RDS_Block_Data_buffer*/ + i = 0; + data->rdsa = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsb = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsc = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->rdsd = RDS_Block_Data_buffer[i++ + 4*RDS_Buffer_Index_read]; + + /*Reading from RDS_Block_Error_buffer*/ + i = 0; + data->blera = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerb = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerc = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + data->blerd = RDS_Block_Error_buffer[i++ + 4*RDS_Buffer_Index_read]; + + /*Flushing the read data*/ + memset(&RDS_Block_Data_buffer[0+4*RDS_Buffer_Index_read],0,8); + memset(&RDS_Block_Error_buffer[0+4*RDS_Buffer_Index_read],0,4); + + RDS_Buffer_Index_read++; + + if(RDS_Buffer_Index_read >= RDS_BUFFER_LENGTH) + RDS_Buffer_Index_read = 0; + } + } + + debug_rds("RDS_Buffer_Index_read = %d",RDS_Buffer_Index_read); + +#else + SYSCONFIG1_BITSET_RDSIEN_HIGH(&Si4709_dev.registers[SYSCONFIG1]); + + if((ret = i2c_write(SYSCONFIG1)) < 0) + { + debug("Si4709_dev_RDS_data_get i2c_write 1 failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + else + { + if( (ret=i2c_read(SYSCONFIG1)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 1 failed"); + + debug("sysconfig1: 0x%x",Si4709_dev.registers[SYSCONFIG1] ); + sysconfig1 = Si4709_dev.registers[SYSCONFIG1]; + + Si4709_dev_wait_flag = RDS_WAITING; + + wait_RDS(); + + if((ret=i2c_read(STATUSRSSI)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 2 failed"); + + debug("statusrssi: 0x%x",Si4709_dev.registers[STATUSRSSI] ); + SYSCONFIG1_BITSET_RDSIEN_LOW(&Si4709_dev.registers[SYSCONFIG1]); + + if ((ret = i2c_write(SYSCONFIG1)) < 0) + { + debug("Si4709_dev_RDS_data_get i2c_write 2 failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + } + else if(Si4709_dev_wait_flag == WAIT_OVER) + { + Si4709_dev_wait_flag = NO_WAIT; + + if((ret = i2c_read(RDSD)) < 0) + debug("Si4709_dev_RDS_data_get i2c_read 3 failed"); + else + { + data->rdsa = Si4709_dev.registers[RDSA]; + data->rdsb = Si4709_dev.registers[RDSB]; + data->rdsc = Si4709_dev.registers[RDSC]; + data->rdsd = Si4709_dev.registers[RDSD]; + + get_cur_chan_freq(&(data->curr_channel), Si4709_dev.registers[READCHAN]); + debug("curr_channel: %u",data->curr_channel); + data->curr_rssi = STATUSRSSI_RSSI_SIGNAL_STRENGTH(Si4709_dev.registers[STATUSRSSI]); + debug("curr_rssi:%u",(u32)data->curr_rssi); + data->blera = STATUSRSSI_RDS_BLOCK_A_ERRORS(Si4709_dev.registers[STATUSRSSI]); + data->blerb = READCHAN_BLOCK_B_ERRORS(Si4709_dev.registers[READCHAN]); + data->blerc = READCHAN_BLOCK_C_ERRORS(Si4709_dev.registers[READCHAN]); + data->blerd = READCHAN_BLOCK_D_ERRORS(Si4709_dev.registers[READCHAN]); + } + } + else + { + debug("Si4709_dev_RDS_data_get failure no interrupt or timeout"); + Si4709_dev_wait_flag = NO_WAIT; + ret = -1; + } + } +#endif + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + +int Si4709_dev_RDS_timeout_set(u32 time_out) +{ + int ret = 0; + u32 jiffy_count = 0; + + debug("Si4709_dev_RDS_timeout_set called"); + /****convert time_out(in milliseconds) into jiffies*****/ + + jiffy_count = msecs_to_jiffies(time_out); + + debug("jiffy_count%d",jiffy_count); + + mutex_lock(&(Si4709_dev.lock)); + + if( Si4709_dev.valid == eFALSE ) + { + debug("Si4709_dev_RDS_timeout_set called when DS is invalid"); + ret = -1; + } + else + { + Si4709_dev.settings.timeout_RDS = jiffy_count; + } + + mutex_unlock(&(Si4709_dev.lock)); + + return ret; +} + + +/**************************************************************/ +static int powerup(void) +{ + int ret=0; + u16 powercfg = Si4709_dev.registers[POWERCFG]; + int reg; + /****Resetting the device****/ + + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + +#if 0 + /*Add the i2c driver*/ + if ( (ret = Si4709_i2c_drv_init() < 0) ) + { + debug("Si4709_i2c_drv_init failed"); + } +#endif + /*Resetting the Si4709_dev.registers[] array*/ + for(reg=0;reg < NUM_OF_REGISTERS;reg++) + Si4709_dev.registers[reg] = 0; + + debug("Resetting the Si4709_dev.registers[] array"); + + POWERCFG_BITSET_DMUTE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_ENABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_DISABLE_LOW( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_RESERVED( &Si4709_dev.registers[POWERCFG] ); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("powerup->i2c_write 1 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + /*Si4709/09 datasheet: Table 7*/ + mdelay(110); + Si4709_dev.state.power_state = RADIO_ON; + } + + return ret; +} + +static int powerdown(void) +{ + int ret = 0; + u16 test1 = Si4709_dev.registers[TEST1], + sysconfig1 = Si4709_dev.registers[SYSCONFIG1], + powercfg = Si4709_dev.registers[POWERCFG]; + + if(!(RADIO_POWERDOWN==Si4709_dev.state.power_state)) + { + //TEST1_BITSET_AHIZEN_HIGH( &Si4709_dev.registers[TEST1] ); + //TEST1_BITSET_RESERVED( &Si4709_dev.registers[TEST1] ); + + SYSCONFIG1_BITSET_GPIO_LOW(&Si4709_dev.registers[SYSCONFIG1]); + SYSCONFIG1_BITSET_RESERVED( &Si4709_dev.registers[SYSCONFIG1] ); + /*VNVS: 13-OCT'09---- During Powerdown of the device RDS should be disabled + according to the Si4708/09 datasheet*/ + SYSCONFIG1_BITSET_RDS_LOW(&Si4709_dev.registers[SYSCONFIG1]); + + POWERCFG_BITSET_DMUTE_LOW( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_ENABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_DISABLE_HIGH( &Si4709_dev.registers[POWERCFG] ); + POWERCFG_BITSET_RESERVED( &Si4709_dev.registers[POWERCFG] ); + + /*this will write all the above registers*/ + if( (ret = i2c_write( TEST1 )) < 0 ) + { + debug("powerdown->i2c_write failed"); + Si4709_dev.registers[SYSCONFIG1] = sysconfig1; + Si4709_dev.registers[POWERCFG] = powercfg; + Si4709_dev.registers[TEST1] = test1; + } + else + { + Si4709_dev.state.power_state = RADIO_POWERDOWN; + } + + /****Resetting the device****/ + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + } + else + debug("Device already Powered-OFF"); + + return ret; +} + +static int seek(u32 *frequency, int up) +{ + int ret = 0; + u16 powercfg = Si4709_dev.registers[POWERCFG]; + u16 channel = 0; + int valid_station_found = 0; + + if( up ) + { + POWERCFG_BITSET_SEEKUP_HIGH(&Si4709_dev.registers[POWERCFG]); + } + else + { + POWERCFG_BITSET_SEEKUP_LOW(&Si4709_dev.registers[POWERCFG]); + } + + POWERCFG_BITSET_SKMODE_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_SEEK_HIGH(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 1 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + Si4709_dev_wait_flag = SEEK_WAITING; + + wait(); + + if ( Si4709_dev_wait_flag == SEEK_CANCEL ) + { + powercfg = Si4709_dev.registers[POWERCFG]; + POWERCFG_BITSET_SEEK_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + + if( (ret = i2c_read( READCHAN )) < 0 ) + { + debug("seek i2c_read 1 failed"); + } + else + { + channel = READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + *frequency = channel_to_freq(channel); + } + *frequency = 0; + } + + Si4709_dev_wait_flag = NO_WAIT; + + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("seek i2c_read 2 failed"); + } + else + { + /*VNVS:START 13-OCT'09---- Checking the status of Seek/Tune Bit*/ +#ifdef TEST_FM + if(STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) == COMPLETE) + { + debug("Seek/Tune Status is set to 1 by device"); + if(STATUSRSSI_SF_BL_STATUS(Si4709_dev.registers[STATUSRSSI]) == SEEK_SUCCESSFUL) + { + debug("Seek Fail/Band Limit Status is set to 0 by device ---SeekUp Operation Completed"); + valid_station_found = 1; + } + else + debug("Seek Fail/Band Limit Status is set to 1 by device ---SeekUp Operation Not Completed"); + } + else + debug("Seek/Tune Status is set to 0 by device ---SeekUp Operation Not Completed"); + +#endif + /*VNVS:END*/ + + powercfg = Si4709_dev.registers[POWERCFG]; + + POWERCFG_BITSET_SEEK_LOW(&Si4709_dev.registers[POWERCFG]); + POWERCFG_BITSET_RESERVED(&Si4709_dev.registers[POWERCFG]); + + if( (ret = i2c_write(POWERCFG)) < 0 ) + { + debug("seek i2c_write 2 failed"); + Si4709_dev.registers[POWERCFG] = powercfg; + } + else + { + do + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("seek i2c_read 3 failed"); + break; + } + }while( STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) != CLEAR ); + + if( ret == 0 && valid_station_found == 1 ) + { + if( (ret = i2c_read( READCHAN )) < 0 ) + { + debug("seek i2c_read 4 failed"); + } + else + { + channel = READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + *frequency = channel_to_freq(channel); + debug("Frequency after seek-up is %d \n",*frequency); + } + } + else + { + debug("Valid station not found \n"); + *frequency = 0; + } + } + } + } + + return ret; +} + +static int tune_freq(u32 frequency) +{ + int ret = 0; + u16 channel = Si4709_dev.registers[CHANNEL]; +#ifdef TEST_FM + u16 read_channel; +#endif + debug("tune_freq called"); + + Si4709_dev.registers[CHANNEL] = freq_to_channel(frequency); +#ifdef TEST_FM + read_channel = Si4709_dev.registers[CHANNEL]; + debug(" Input read_channel =%x",read_channel); +#endif + CHANNEL_BITSET_TUNE_HIGH(&Si4709_dev.registers[CHANNEL]); + CHANNEL_BITSET_RESERVED(&Si4709_dev.registers[CHANNEL]); + + if( (ret = i2c_write(CHANNEL)) < 0 ) + { + debug("tune_freq i2c_write 1 failed"); + Si4709_dev.registers[CHANNEL] = channel; + } + else + { + + Si4709_dev_wait_flag = TUNE_WAITING; + debug("Si4709_dev_wait_flag = TUNE_WAITING"); +#ifdef TEST_FM + if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("tune_freq i2c_read 1 failed"); + } + else + { + read_channel=READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + debug("curr_channel before tuning = %x",read_channel); + } +#endif + + wait(); + + Si4709_dev_wait_flag = NO_WAIT; + + /*VNVS:START 13-OCT'09---- Checking the status of Seek/Tune Bit*/ +#ifdef TEST_FM + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("tune_freq i2c_read 2 failed"); + + } + else if(STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) == COMPLETE) + debug("Seek/Tune Status is set to 1 by device ---Tuning Operation Completed"); + else + debug("Seek/Tune Status is set to 0 by device ---Tuning Operation Not Completed"); +#endif + /*VNVS:END*/ + + channel = Si4709_dev.registers[CHANNEL]; + + CHANNEL_BITSET_TUNE_LOW(&Si4709_dev.registers[CHANNEL]); + CHANNEL_BITSET_RESERVED(&Si4709_dev.registers[CHANNEL]); + + if( (ret = i2c_write(CHANNEL)) < 0 ) + { + debug("tune_freq i2c_write 2 failed"); + Si4709_dev.registers[CHANNEL] = channel; + } + else + { + do + { + if( (ret = i2c_read(STATUSRSSI)) < 0 ) + { + debug("tune_freq i2c_read 3 failed"); + break; + } + }while( STATUSRSSI_SEEK_TUNE_STATUS(Si4709_dev.registers[STATUSRSSI]) != CLEAR ); + + } + + /*VNVS:START 13-OCT'09---- Reading the READCHAN register after tuning operation*/ +#ifdef TEST_FM + if( (ret = i2c_read(READCHAN)) < 0 ) + { + debug("tune_freq i2c_read 2 failed"); + } + else + { + read_channel=READCHAN_GET_CHAN(Si4709_dev.registers[READCHAN]); + debug("curr_channel after tuning= %x",read_channel); + } +#endif + /*VNVS:END*/ + } + + return ret; +} + +static void get_cur_chan_freq(u32 *frequency, u16 readchan) +{ + + u16 channel = 0; + debug("get_cur_chan_freq called"); + + channel = READCHAN_GET_CHAN(readchan); + debug("read_channel=%x",channel); + + *frequency = channel_to_freq(channel); + + debug("frequency-> %u",*frequency); +} + +static u16 freq_to_channel(u32 frequency) +{ + u16 channel; + + if( frequency < Si4709_dev.settings.bottom_of_band ) + { + frequency = Si4709_dev.settings.bottom_of_band; + } + + channel = (frequency - Si4709_dev.settings.bottom_of_band) + / Si4709_dev.settings.channel_spacing; + + return channel; +} + +static u32 channel_to_freq(u16 channel) +{ + u32 frequency; + + frequency = Si4709_dev.settings.bottom_of_band + + Si4709_dev.settings.channel_spacing * channel; + + return frequency; +} + +/*Only one thread will be able to call this, since this function call is + protected by a mutex, so no race conditions can arise*/ +static void wait(void) +{ + wait_event_interruptible(Si4709_waitq, + (Si4709_dev_wait_flag == WAIT_OVER) || (Si4709_dev_wait_flag == SEEK_CANCEL)); +} + +static void wait_RDS(void) +{ + wait_event_interruptible_timeout(Si4709_waitq, + (Si4709_dev_wait_flag == WAIT_OVER),Si4709_dev.settings.timeout_RDS); +} + +/*i2c read function*/ +/*Si4709_dev.client should be set before calling this function. + If Si4709_dev.valid = eTRUE then Si4709_dev.client will b valid + This function should be called from the functions in this file. The + callers should check if Si4709_dev.valid = eTRUE before + calling this function. If it is eFALSE then this function should not + be called*/ +static int i2c_read( u8 reg ) +{ + u8 idx, reading_reg = STATUSRSSI; + u8 data[NUM_OF_REGISTERS * 2], data_high, data_low; + int msglen = 0, ret = 0; + + for(idx = 0; idx < NUM_OF_REGISTERS * 2; idx++) + { + data[idx] = 0x00; + } + + msglen = reg - reading_reg + 1; + + if(msglen > 0) + { + msglen = msglen * 2; + } + else + { + msglen = (msglen + NUM_OF_REGISTERS) * 2; + } + + ret = i2c_master_recv((struct i2c_client*)(Si4709_dev.client), data, msglen); + + if(ret == msglen) + { + idx = 0; + do + { + data_high = data[idx]; + data_low = data[idx+1]; + + Si4709_dev.registers[reading_reg] = 0x0000; + Si4709_dev.registers[reading_reg] = (data_high << 8) + data_low; + reading_reg = (reading_reg + 1) & RDSD; + idx = idx + 2; + } while(reading_reg != ((reg +1) & RDSD)); + + ret = 0; + } + else + { + ret = -1; + } + + return ret; +} + +/*i2c write function*/ +/*Si4709_dev.client should be set before calling this function. + If Si4709_dev.valid = eTRUE then Si4709_dev.client will b valid + This function should be called from the functions in this file. The + callers should check if Si4709_dev.valid = eTRUE before + calling this function. If it is eFALSE then this function should not + be called*/ +static int i2c_write( u8 reg ) +{ + u8 writing_reg = POWERCFG; + u8 data[NUM_OF_REGISTERS * 2]; + int i, msglen = 0, ret = 0; + + for(i = 0; i < NUM_OF_REGISTERS * 2; i++) + { + data[i] = 0x00; + } + + do + { + data[msglen++] = (u8)(Si4709_dev.registers[writing_reg] >> 8); + data[msglen++] = (u8)(Si4709_dev.registers[writing_reg] & 0xFF); + + writing_reg = (writing_reg +1) & RDSD; + } while(writing_reg != ((reg + 1) & RDSD)); + + ret = i2c_master_send((struct i2c_client*)(Si4709_dev.client), ( const char *)data, msglen); + + if(ret == msglen) + { + ret = 0; + } + else + { + ret = -1; + } + + return ret; +} + +static int insert_preset(u32 frequency,u8 rssi,u8 *seek_preset_rssi) +{ + u8 i; + u8 min_rssi = 0xff; + u8 min_rssi_preset=0; + int ret = 0; + + /* first find the minimum rssi and its location + this will always stop at the first location with a zero rssi */ + + debug("si4709 autoseek : insert preset\n"); + + for (i=0; i<NUM_SEEK_PRESETS; i++) + { + if (seek_preset_rssi[i] < min_rssi) + { + min_rssi = seek_preset_rssi[i]; + min_rssi_preset = i; + } + } + + if (rssi < min_rssi) + ret = -1; + + /***Delete the preset with the minimum rssi, and clear the last preset + since it would only be a copy of the second to last preset after + the deletion ***/ + for (i=min_rssi_preset; i<NUM_SEEK_PRESETS-1; i++) + { + Si4709_dev.settings.seek_preset[i]= Si4709_dev.settings.seek_preset[i+1]; + seek_preset_rssi[i] = seek_preset_rssi[i+1]; + } + + Si4709_dev.settings.seek_preset[i] = 0; + seek_preset_rssi[i] = 0; + + /*** Fill the first preset with a zero for the frequency. This will + always overwrite the last preset once all presets have been filled. ***/ + for (i=min_rssi_preset; i<NUM_SEEK_PRESETS; i++) + { + if(Si4709_dev.settings.seek_preset[i] == 0) + { + Si4709_dev.settings.seek_preset[i]= frequency; + seek_preset_rssi[i] = rssi; + break; + } + } + return ret; +} + + diff --git a/drivers/media/radio/si4709/radio-si4709_dev.h b/drivers/media/radio/si4709/radio-si4709_dev.h new file mode 100644 index 0000000..bdcde4f --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_dev.h @@ -0,0 +1,181 @@ +#ifndef _Si4709_DEV_H +#define _Si4709_DEV_H + +#include <linux/i2c.h> +#include "radio-si4709_common.h" + +typedef struct +{ + int power_state; + int seek_state; +}dev_state_t; + +typedef struct +{ + u8 curr_rssi; + u8 curr_rssi_th; + u8 curr_snr; +}rssi_snr_t; + +typedef struct +{ + u8 part_number; + u16 manufact_number; +} device_id; + +typedef struct +{ + u8 chip_version; + u8 device; + u8 firmware_version; +}chip_id; + +typedef struct +{ + u16 rssi_th; + u8 fm_band; + u8 fm_chan_spac; + u8 fm_vol; +} sys_config2; + +typedef struct +{ + u8 smmute; + u8 smutea; + u8 volext; + u8 sksnr; + u8 skcnt; +} sys_config3; + +typedef struct +{ + u8 rdsr; + u8 stc; + u8 sfbl; + u8 afcrl; + u8 rdss; + u8 blera; + u8 st; + u16 rssi; +} status_rssi; + +typedef struct +{ + u16 dsmute :1; + u16 dmute:1; + u16 mono:1; + u16 rds_mode:1; + u16 sk_mode:1; + u16 seek_up:1; + u16 seek:1; + u16 power_disable:1; + u16 power_enable:1; +} power_config; + +typedef struct +{ + u16 rdsa; + u16 rdsb; + u16 rdsc; + u16 rdsd; + u8 curr_rssi; + u32 curr_channel; + u8 blera; + u8 blerb; + u8 blerc; + u8 blerd; +}radio_data_t; + +#define NUM_SEEK_PRESETS 20 + +#define WAIT_OVER 0 +#define SEEK_WAITING 1 +#define NO_WAIT 2 +#define TUNE_WAITING 4 +#define RDS_WAITING 5 +#define SEEK_CANCEL 6 + +/*dev settings*/ +/*band*/ +#define BAND_87500_108000_kHz 1 +#define BAND_76000_108000_kHz 2 +#define BAND_76000_90000_kHz 3 + +/*channel spacing*/ +#define CHAN_SPACING_200_kHz 20 /*US*/ +#define CHAN_SPACING_100_kHz 10 /*Europe,Japan*/ +#define CHAN_SPACING_50_kHz 5 + +/*DE-emphasis Time Constant*/ +#define DE_TIME_CONSTANT_50 1 /*Europe,Japan,Australia*/ +#define DE_TIME_CONSTANT_75 0 /*US*/ + +extern int Si4709_dev_wait_flag; + +#ifdef RDS_INTERRUPT_ON_ALWAYS +extern int Si4709_RDS_flag; +extern int RDS_Data_Available; +extern int RDS_Data_Lost; +extern int RDS_Groups_Available_till_now; +extern struct workqueue_struct *Si4709_wq; +extern struct work_struct Si4709_work; +#endif + +/*Function prototypes*/ +extern int Si4709_dev_init(struct i2c_client *); +extern int Si4709_dev_exit(void); + +extern void Si4709_dev_mutex_init(void); + +extern int Si4709_dev_suspend(void); +extern int Si4709_dev_resume(void); + +extern int Si4709_dev_powerup(void); +extern int Si4709_dev_powerdown(void); + +extern int Si4709_dev_band_set(int); +extern int Si4709_dev_ch_spacing_set(int); + +extern int Si4709_dev_chan_select(u32); +extern int Si4709_dev_chan_get(u32*); + +extern int Si4709_dev_seek_up(u32*); +extern int Si4709_dev_seek_down(u32*); +extern int Si4709_dev_seek_auto(u32*); + +extern int Si4709_dev_RSSI_seek_th_set(u8); +extern int Si4709_dev_seek_SNR_th_set(u8); +extern int Si4709_dev_seek_FM_ID_th_set(u8); +extern int Si4709_dev_cur_RSSI_get(rssi_snr_t*); +extern int Si4709_dev_VOLEXT_ENB(void); +extern int Si4709_dev_VOLEXT_DISB(void); +extern int Si4709_dev_volume_set(u8); +extern int Si4709_dev_volume_get(u8*); +extern int Si4709_dev_DSMUTE_ON(void); +extern int Si4709_dev_DSMUTE_OFF(void); +extern int Si4709_dev_MUTE_ON(void); +extern int Si4709_dev_MUTE_OFF(void); +extern int Si4709_dev_MONO_SET(void); +extern int Si4709_dev_STEREO_SET(void); +extern int Si4709_dev_rstate_get(dev_state_t*); +extern int Si4709_dev_RDS_data_get(radio_data_t*); +extern int Si4709_dev_RDS_ENABLE(void); +extern int Si4709_dev_RDS_DISABLE(void); +extern int Si4709_dev_RDS_timeout_set(u32); +extern int Si4709_dev_device_id(device_id *); +extern int Si4709_dev_chip_id(chip_id *); +extern int Si4709_dev_sys_config2(sys_config2 *); +extern int Si4709_dev_sys_config3(sys_config3 *); +extern int Si4709_dev_power_config(power_config *); +extern int Si4709_dev_AFCRL_get(u8*); +extern int Si4709_dev_DE_set(u8); +extern int Si4709_dev_status_rssi(status_rssi *status); +extern int Si4709_dev_sys_config2_set(sys_config2 *sys_conf2); +extern int Si4709_dev_sys_config3_set(sys_config3 *sys_conf3); +extern int Si4709_dev_reset_rds_data(void); + +#ifdef RDS_INTERRUPT_ON_ALWAYS +extern void Si4709_work_func(struct work_struct*); +#endif +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_i2c_drv.c b/drivers/media/radio/si4709/radio-si4709_i2c_drv.c new file mode 100644 index 0000000..5885b04 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_i2c_drv.c @@ -0,0 +1,196 @@ + +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/slab.h> + +#include "radio-si4709_dev.h" +#include "radio-si4709_common.h" + +/*extern functions*/ +int Si4709_i2c_drv_init(void); +void Si4709_i2c_drv_exit(void); + +/*static functions*/ +static int Si4709_probe (struct i2c_client *); +static int Si4709_remove(struct i2c_client *); +static int Si4709_suspend(struct i2c_client *, pm_message_t mesg); +static int Si4709_resume(struct i2c_client *); + +static struct i2c_client *Si4709_i2c_client; + + +struct si4709_data { + struct i2c_client *client; +}; + +/*I2C Setting*/ +#define SI4709_I2C_ADDRESS 0x20 + +static unsigned short Si4709_normal_i2c[] = { I2C_CLIENT_END }; + +static struct i2c_driver Si4709_i2c_driver; + +static const struct i2c_device_id si4709_id[] = { + {"Si4709", 0}, + {} +}; + +static int Si4709_probe (struct i2c_client *client) +{ + int ret = 0; + + debug("Si4709 i2c driver Si4709_probe called"); + + if( strcmp(client->name, "Si4709") != 0 ) + { + ret = -1; + debug("Si4709_probe: device not supported"); + } + else if( (ret = Si4709_dev_init(client)) < 0 ) + { + debug("Si4709_dev_init failed"); + } + + return ret; +} + +static int Si4709_remove(struct i2c_client *client) +{ + int ret = 0; + + debug("Si4709 i2c driver Si4709_remove called"); + + if( strcmp(client->name, "Si4709") != 0 ) + { + ret = -1; + debug("Si4709_remove: device not supported"); + } + else if( (ret = Si4709_dev_exit()) < 0 ) + { + debug("Si4709_dev_exit failed"); + } + + return ret; +} + +static int __devinit si4709_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = 0; + struct si4709_data *si4709_dev; + + debug("----- %s %d\n", __func__, __LINE__); + + si4709_dev = kzalloc(sizeof(struct si4709_data), GFP_KERNEL); + + if(!si4709_dev) + { + err = -ENOMEM; + return err; + } + + Si4709_i2c_client = client; + i2c_set_clientdata(client, si4709_dev); + + if(Si4709_i2c_client == NULL) + { + error("Si4709 i2c_client is NULL"); + return -ENODEV; + } + + Si4709_probe(Si4709_i2c_client); + + return 0; +} + +static int __devexit si4709_i2c_remove(struct i2c_client *client) +{ + struct si4709_data *si4709_dev = i2c_get_clientdata(client); + + printk("----- %s %d\n", __func__, __LINE__); + + Si4709_remove(Si4709_i2c_client); + kfree(si4709_dev); + kfree(client); + si4709_dev = NULL; + Si4709_i2c_client = NULL; + + return 0; +} + + +MODULE_DEVICE_TABLE(i2c, si4709_id); + +static struct i2c_driver Si4709_i2c_driver = +{ + .driver = { + .owner = THIS_MODULE, + .name = "Si4709", + }, + .id_table = si4709_id, + .probe = si4709_i2c_probe, + .remove = __devexit_p(si4709_i2c_remove), + .suspend = Si4709_suspend, + .resume = Si4709_resume, + .address_list = Si4709_normal_i2c, +}; + +static int Si4709_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int ret = 0; + + debug("Si4709 i2c driver Si4709_suspend called"); + + if( strcmp(client->name, "Si4709") != 0 ) + { + ret = -1; + debug("Si4709_suspend: device not supported"); + } + else if( (ret = Si4709_dev_suspend()) < 0 ) + { + debug("Si4709_dev_disable failed"); + } + + return 0; +} + +static int Si4709_resume(struct i2c_client *client) +{ + int ret = 0; + +// debug("Si4709 i2c driver Si4709_resume called"); + + if( strcmp(client->name, "Si4709") != 0 ) + { + ret = -1; + debug("Si4709_resume: device not supported"); + } + else if( (ret = Si4709_dev_resume()) < 0 ) + { + debug("Si4709_dev_enable failed"); + } + + return 0; +} + +int Si4709_i2c_drv_init(void) +{ + int ret = 0; + + debug("Si4709 i2c driver Si4709_i2c_driver_init called"); + + if ( (ret = i2c_add_driver(&Si4709_i2c_driver) < 0) ) + { + error("Si4709 i2c_add_driver failed"); + } + + return ret; +} + +void Si4709_i2c_drv_exit(void) +{ + debug("Si4709 i2c driver Si4709_i2c_driver_exit called"); + + i2c_del_driver(&Si4709_i2c_driver); +} + + diff --git a/drivers/media/radio/si4709/radio-si4709_i2c_drv.h b/drivers/media/radio/si4709/radio-si4709_i2c_drv.h new file mode 100644 index 0000000..fb705a3 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_i2c_drv.h @@ -0,0 +1,8 @@ +#ifndef _Si4709_I2C_DRV_H +#define _Si4709_I2C_DRV_H + +extern int Si4709_i2c_drv_init(void); +extern int Si4709_i2c_drv_exit(void); + +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_ioctl.h b/drivers/media/radio/si4709/radio-si4709_ioctl.h new file mode 100644 index 0000000..5165a99 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_ioctl.h @@ -0,0 +1,104 @@ +#ifndef _Si4709_IOCTL_H +#define _Si4709_IOCTL_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +#include "radio-si4709_dev.h" + +/*****************IOCTLS******************/ +/*magic no*/ +#define Si4709_IOC_MAGIC 0xFA +/*max seq no*/ +#define Si4709_IOC_NR_MAX 40 + +/*commands*/ + +#define Si4709_IOC_POWERUP _IO(Si4709_IOC_MAGIC, 0) + +#define Si4709_IOC_POWERDOWN _IO(Si4709_IOC_MAGIC, 1) + +#define Si4709_IOC_BAND_SET _IOW(Si4709_IOC_MAGIC, 2, int) + +#define Si4709_IOC_CHAN_SPACING_SET _IOW(Si4709_IOC_MAGIC, 3, int) + +#define Si4709_IOC_CHAN_SELECT _IOW(Si4709_IOC_MAGIC, 4, u32) + +#define Si4709_IOC_CHAN_GET _IOR(Si4709_IOC_MAGIC, 5, u32) + +#define Si4709_IOC_SEEK_UP _IOR(Si4709_IOC_MAGIC, 6, u32) + +#define Si4709_IOC_SEEK_DOWN _IOR(Si4709_IOC_MAGIC, 7, u32) + +/*VNVS:28OCT'09---- Si4709_IOC_SEEK_AUTO is disabled as of now*/ +//#define Si4709_IOC_SEEK_AUTO _IOR(Si4709_IOC_MAGIC, 8, u32) + +#define Si4709_IOC_RSSI_SEEK_TH_SET _IOW(Si4709_IOC_MAGIC, 9, u8) + +#define Si4709_IOC_SEEK_SNR_SET _IOW(Si4709_IOC_MAGIC, 10, u8) + +#define Si4709_IOC_SEEK_CNT_SET _IOW(Si4709_IOC_MAGIC, 11, u8) + +#define Si4709_IOC_CUR_RSSI_GET _IOR(Si4709_IOC_MAGIC, 12, rssi_snr_t) + +#define Si4709_IOC_VOLEXT_ENB _IO(Si4709_IOC_MAGIC, 13) + +#define Si4709_IOC_VOLEXT_DISB _IO(Si4709_IOC_MAGIC, 14) + +#define Si4709_IOC_VOLUME_SET _IOW(Si4709_IOC_MAGIC, 15, u8) + +#define Si4709_IOC_VOLUME_GET _IOR(Si4709_IOC_MAGIC, 16, u8) + +#define Si4709_IOC_MUTE_ON _IO(Si4709_IOC_MAGIC, 17) + +#define Si4709_IOC_MUTE_OFF _IO(Si4709_IOC_MAGIC, 18) + +#define Si4709_IOC_MONO_SET _IO(Si4709_IOC_MAGIC, 19) + +#define Si4709_IOC_STEREO_SET _IO(Si4709_IOC_MAGIC, 20) + +#define Si4709_IOC_RSTATE_GET _IOR(Si4709_IOC_MAGIC, 21, dev_state_t) + +#define Si4709_IOC_RDS_DATA_GET _IOR(Si4709_IOC_MAGIC, 22, radio_data_t) + +#define Si4709_IOC_RDS_ENABLE _IO(Si4709_IOC_MAGIC, 23) + +#define Si4709_IOC_RDS_DISABLE _IO(Si4709_IOC_MAGIC, 24) + +#define Si4709_IOC_RDS_TIMEOUT_SET _IOW(Si4709_IOC_MAGIC, 25, u32) + +#define Si4709_IOC_SEEK_CANCEL _IO(Si4709_IOC_MAGIC, 26) + +/*VNVS:START 13-OCT'09---- Added IOCTLs for reading the device-id,chip-id,power configuration, system configuration2 registers*/ +#define Si4709_IOC_DEVICE_ID_GET _IOR(Si4709_IOC_MAGIC, 27,device_id) + +#define Si4709_IOC_CHIP_ID_GET _IOR(Si4709_IOC_MAGIC, 28,chip_id) + +#define Si4709_IOC_SYS_CONFIG2_GET _IOR(Si4709_IOC_MAGIC,29,sys_config2) + +#define Si4709_IOC_POWER_CONFIG_GET _IOR(Si4709_IOC_MAGIC,30,power_config) + +#define Si4709_IOC_AFCRL_GET _IOR(Si4709_IOC_MAGIC,31,u8) /*For reading AFCRL bit, to check for a valid channel*/ + +#define Si4709_IOC_DE_SET _IOW(Si4709_IOC_MAGIC,32,u8) /*Setting DE-emphasis Time Constant. For DE=0,TC=50us(Europe,Japan,Australia) and DE=1,TC=75us(USA)*/ +/*VNVS:END*/ + +#define Si4709_IOC_SYS_CONFIG3_GET _IOR(Si4709_IOC_MAGIC, 33, sys_config3) + +#define Si4709_IOC_STATUS_RSSI_GET _IOR(Si4709_IOC_MAGIC, 34, status_rssi) + +#define Si4709_IOC_SYS_CONFIG2_SET _IOW(Si4709_IOC_MAGIC, 35, sys_config2) + +#define Si4709_IOC_SYS_CONFIG3_SET _IOW(Si4709_IOC_MAGIC, 36, sys_config3) + +#define Si4709_IOC_DSMUTE_ON _IO(Si4709_IOC_MAGIC, 37) + +#define Si4709_IOC_DSMUTE_OFF _IO(Si4709_IOC_MAGIC, 38) + +#define Si4709_IOC_RESET_RDS_DATA _IO(Si4709_IOC_MAGIC, 39) + + +/*****************************************/ + +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_main.c b/drivers/media/radio/si4709/radio-si4709_main.c new file mode 100644 index 0000000..a202b50 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_main.c @@ -0,0 +1,799 @@ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#include <linux/irq.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <linux/wait.h> +#include <linux/stat.h> +#include <linux/ioctl.h> + +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> +#include <../../../arch/arm/mach-s5pv210/include/mach/gpio-aries.h> + +#include "radio-si4709_i2c_drv.h" +#include "radio-si4709_dev.h" +#include "radio-si4709_ioctl.h" +#include "radio-si4709_common.h" + +/*******************************************************/ + +/*Si4709 IRQ Number*/ + +#define FM_IRQ_INT (IRQ_EINT_GROUP20_BASE+4) /* J2_4 */ + +/*static functions*/ + +/*file operatons*/ +static int Si4709_open (struct inode *, struct file *); +static int Si4709_release (struct inode *, struct file *); +static int Si4709_ioctl(struct file *, unsigned int, unsigned long); + +static DEFINE_MUTEX(Si4709_mutex); + +/*ISR*/ +static irqreturn_t Si4709_isr( int irq, void *unused ); +//static void __iomem *gpio_mask_mem; +/**********************************************************/ + +static struct file_operations Si4709_fops = +{ + .owner = THIS_MODULE, + .open = Si4709_open, + .unlocked_ioctl = Si4709_ioctl, + .release = Si4709_release, +}; + +static struct miscdevice Si4709_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "radio0", + .fops = &Si4709_fops, +}; +/*VNVS:START 13-OCT'09----dummy struct which is used as a cookie for FM Radio interrupt */ +typedef struct +{ + int i; + int j; +} radio0; +radio0 radio0_1; +/*VNVS:END*/ + +wait_queue_head_t Si4709_waitq; + +/***************************************************************/ + +static int Si4709_open (struct inode *inode, struct file *filp) +{ + debug("Si4709_open called"); + + return nonseekable_open(inode, filp); +} + +static int Si4709_release (struct inode *inode, struct file *filp) +{ + debug("Si4709_release called"); + + return 0; +} + +static int Si4709_ioctl(struct file *filp, unsigned int ioctl_cmd, unsigned long arg) +{ + int ret = 0; + void __user *argp = (void __user *)arg; + + mutex_lock(&Si4709_mutex); + + if( _IOC_TYPE(ioctl_cmd) != Si4709_IOC_MAGIC ) + { + debug("Inappropriate ioctl 1 0x%x",ioctl_cmd); + ret = -ENOTTY; + goto exit; + } + + if( _IOC_NR(ioctl_cmd) > Si4709_IOC_NR_MAX ) + { + debug("Inappropriate ioctl 2 0x%x",ioctl_cmd); + ret = -ENOTTY; + goto exit; + } + + switch (ioctl_cmd) + { + case Si4709_IOC_POWERUP: + debug("Si4709_IOC_POWERUP called"); + + if( (ret = Si4709_dev_powerup()) < 0 ) + debug("Si4709_IOC_POWERUP failed"); + break; + + case Si4709_IOC_POWERDOWN: + debug("Si4709_IOC_POWERDOWN called"); + + if( (ret = Si4709_dev_powerdown()) < 0 ) + debug("Si4709_IOC_POWERDOWN failed"); + break; + + case Si4709_IOC_BAND_SET: + { + int band; + debug("Si4709_IOC_BAND_SET called"); + + if(copy_from_user((void*) &band, argp, sizeof(int))) + ret = -EFAULT; + else if( (ret = Si4709_dev_band_set(band)) < 0) + debug("Si4709_IOC_BAND_SET failed"); + + } + break; + + case Si4709_IOC_CHAN_SPACING_SET: + { + int ch_spacing; + debug("Si4709_IOC_CHAN_SPACING_SET called"); + + if( copy_from_user((void*) &ch_spacing, argp, sizeof(int)) ) + ret = -EFAULT; + else if ((ret = Si4709_dev_ch_spacing_set(ch_spacing)) < 0) + debug("Si4709_IOC_CHAN_SPACING_SET failed"); + + } + break; + + case Si4709_IOC_CHAN_SELECT: + { + u32 frequency; + debug("Si4709_IOC_CHAN_SELECT called"); + + if( copy_from_user((void*) &frequency, argp, sizeof(u32)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_chan_select(frequency)) < 0 ) + debug("Si4709_IOC_CHAN_SELECT failed"); + } + break; + + case Si4709_IOC_CHAN_GET: + { + u32 frequency; + debug("Si4709_IOC_CHAN_GET called"); + + if( (ret = Si4709_dev_chan_get(&frequency)) < 0) + debug("Si4709_IOC_CHAN_GET failed"); + else if( copy_to_user(argp, (void*) &frequency, sizeof(u32))) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SEEK_UP: + { + u32 frequency; + debug("Si4709_IOC_SEEK_UP called"); + + if( (ret = Si4709_dev_seek_up(&frequency)) < 0) + debug("Si4709_IOC_SEEK_UP failed"); + else if( copy_to_user(argp, (void*) &frequency, sizeof(u32)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SEEK_DOWN: + { + u32 frequency; + debug("Si4709_IOC_SEEK_DOWN called"); + + if( (ret = Si4709_dev_seek_down(&frequency)) < 0) + debug("Si4709_IOC_SEEK_DOWN failed"); + else if( copy_to_user(argp, (void*) &frequency, sizeof(u32)) ) + ret = -EFAULT; + } + break; + +#if 0 + case Si4709_IOC_SEEK_AUTO: + { + u32 *seek_preset_user; + int i = 0; + + debug("Si4709_IOC_SEEK_AUTO called"); + + if( (seek_preset_user = (u32 *)kzalloc(sizeof(u32) * NUM_SEEK_PRESETS, + GFP_KERNEL)) == NULL ) + { + debug("Si4709_ioctl: no memory"); + ret = -ENOMEM; + } + else + { + if((ret = Si4709_dev_seek_auto(seek_preset_user)) < 0) + { + debug("Si4709_IOC_SEEK_AUTO failed"); + } + + else if ( copy_to_user(argp, (u32*) seek_preset_user, sizeof(int) * NUM_SEEK_PRESETS) ) + { + ret = -EFAULT; + } + + kfree(seek_preset_user); + } + } + break; +#endif + + case Si4709_IOC_RSSI_SEEK_TH_SET: + { + u8 RSSI_seek_th; + debug("Si4709_IOC_RSSI_SEEK_TH_SET called"); + + if( copy_from_user((void*) &RSSI_seek_th, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_RSSI_seek_th_set(RSSI_seek_th)) < 0 ) + debug("Si4709_IOC_RSSI_SEEK_TH_SET failed"); + } + break; + + case Si4709_IOC_SEEK_SNR_SET: + { + u8 seek_SNR_th; + debug("Si4709_IOC_SEEK_SNR_SET called"); + + if( copy_from_user((void*) &seek_SNR_th, argp, sizeof(u8)) ) + ret = -EFAULT; + else if( (ret = Si4709_dev_seek_SNR_th_set(seek_SNR_th)) < 0 ) + debug("Si4709_IOC_SEEK_SNR_SET failed"); + } + break; + + case Si4709_IOC_SEEK_CNT_SET: + { + u8 seek_FM_ID_th; + debug("Si4709_IOC_SEEK_CNT_SET called"); + + if( copy_from_user((void*) &seek_FM_ID_th, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_seek_FM_ID_th_set(seek_FM_ID_th)) < 0 ) + debug("Si4709_IOC_SEEK_CNT_SET failed"); + } + break; + + case Si4709_IOC_CUR_RSSI_GET: + { + rssi_snr_t data; + debug("Si4709_IOC_CUR_RSSI_GET called"); + + if( (ret = Si4709_dev_cur_RSSI_get(&data)) < 0) + debug("Si4709_IOC_CUR_RSSI_GET failed"); + else if( copy_to_user(argp, (void*) &data, sizeof(rssi_snr_t )) ) + ret = -EFAULT; + + debug("curr_rssi:%d\ncurr_rssi_th:%d\ncurr_snr:%d\n",data.curr_rssi,data.curr_rssi_th,data.curr_snr); + } + break; + + case Si4709_IOC_VOLEXT_ENB: + debug("Si4709_IOC_VOLEXT_ENB called"); + + if( (ret = Si4709_dev_VOLEXT_ENB()) < 0 ) + debug("Si4709_IOC_VOLEXT_ENB failed"); + break; + + case Si4709_IOC_VOLEXT_DISB: + debug("Si4709_IOC_VOLEXT_DISB called"); + + if( (ret = Si4709_dev_VOLEXT_DISB()) < 0 ) + debug("Si4709_IOC_VOLEXT_DISB failed"); + break; + + case Si4709_IOC_VOLUME_SET: + { + u8 volume; + debug("Si4709_IOC_VOLUME_SET called"); + + if( copy_from_user((void*) &volume, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_volume_set(volume)) < 0 ) + debug("Si4709_IOC_VOLUME_SET failed"); + } + break; + + case Si4709_IOC_VOLUME_GET: + { + u8 volume; + debug("Si4709_IOC_VOLUME_GET called"); + + if( (ret = Si4709_dev_volume_get(&volume)) < 0) + debug("Si4709_IOC_VOLUME_GET failed"); + else if( copy_to_user(argp, (void*) &volume, sizeof(u8)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_DSMUTE_ON: + debug("Si4709_IOC_DSMUTE_ON called"); + + if( (ret = Si4709_dev_DSMUTE_ON()) < 0 ) + error("Si4709_IOC_DSMUTE_ON failed"); + break; + + case Si4709_IOC_DSMUTE_OFF: + debug("Si4709_IOC_DSMUTE_OFF called"); + + if( (ret = Si4709_dev_DSMUTE_OFF()) < 0 ) + error("Si4709_IOC_DSMUTE_OFF failed"); + break; + + case Si4709_IOC_MUTE_ON: + debug("Si4709_IOC_MUTE_ON called"); + + if( (ret = Si4709_dev_MUTE_ON()) < 0 ) + debug("Si4709_IOC_MUTE_ON failed"); + break; + + case Si4709_IOC_MUTE_OFF: + debug("Si4709_IOC_MUTE_OFF called"); + + if( (ret = Si4709_dev_MUTE_OFF()) < 0 ) + debug("Si4709_IOC_MUTE_OFF failed"); + break; + + case Si4709_IOC_MONO_SET: + debug("Si4709_IOC_MONO_SET called"); + + if( (ret = Si4709_dev_MONO_SET()) < 0 ) + debug("Si4709_IOC_MONO_SET failed"); + break; + + case Si4709_IOC_STEREO_SET: + debug("Si4709_IOC_STEREO_SET called"); + + if( (ret = Si4709_dev_STEREO_SET()) < 0 ) + debug("Si4709_IOC_STEREO_SET failed"); + break; + + case Si4709_IOC_RSTATE_GET: + { + dev_state_t dev_state; + + debug("Si4709_IOC_RSTATE_GET called"); + + if( (ret = Si4709_dev_rstate_get(&dev_state)) < 0) + debug("Si4709_IOC_RSTATE_GET failed"); + else if( copy_to_user(argp, (void*) &dev_state, sizeof(dev_state_t)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_RDS_DATA_GET: + { + radio_data_t data; + debug("Si4709_IOC_RDS_DATA_GET called"); + + if( (ret = Si4709_dev_RDS_data_get(&data)) < 0) + debug("Si4709_IOC_RDS_DATA_GET failed"); + else if( copy_to_user(argp, (void*) &data, sizeof(radio_data_t)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_RDS_ENABLE: + debug("Si4709_IOC_RDS_ENABLE called"); + + if( (ret = Si4709_dev_RDS_ENABLE()) < 0 ) + debug("Si4709_IOC_RDS_ENABLE failed"); + break; + + case Si4709_IOC_RDS_DISABLE: + debug("Si4709_IOC_RDS_DISABLE called"); + + if( (ret = Si4709_dev_RDS_DISABLE()) < 0 ) + debug("Si4709_IOC_RDS_DISABLE failed"); + break; + + case Si4709_IOC_RDS_TIMEOUT_SET: + { + u32 time_out; + debug("Si4709_IOC_RDS_TIMEOUT_SET called"); + + if( copy_from_user((void*) &time_out, argp, sizeof(u32)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_RDS_timeout_set(time_out)) < 0 ) + debug("Si4709_IOC_RDS_TIMEOUT_SET failed"); + } + break; + + case Si4709_IOC_SEEK_CANCEL: + debug("Si4709_IOC_SEEK_CANCEL called"); + + if( Si4709_dev_wait_flag == SEEK_WAITING ) + { + Si4709_dev_wait_flag = SEEK_CANCEL; + wake_up_interruptible(&Si4709_waitq); + } + break; + + /*VNVS:START 13-OCT'09---- Switch Case statements for calling functions which reads device-id, + chip-id,power configuration, system configuration2 registers */ + case Si4709_IOC_CHIP_ID_GET: + { + chip_id chp_id; + debug("Si4709_IOC_CHIP_ID called"); + + if( (ret = Si4709_dev_chip_id(&chp_id)) < 0) + debug("Si4709_IOC_CHIP_ID failed"); + else if( copy_to_user(argp, (void*) &chp_id, sizeof(chip_id)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_DEVICE_ID_GET: + { + device_id dev_id; + debug("Si4709_IOC_DEVICE_ID called"); + + if( (ret = Si4709_dev_device_id(&dev_id)) < 0) + debug("Si4709_IOC_DEVICE_ID failed"); + else if( copy_to_user(argp, (void*) &dev_id, sizeof(device_id)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SYS_CONFIG2_GET: + { + sys_config2 sys_conf2; + debug("Si4709_IOC_SYS_CONFIG2 called"); + + if( (ret = Si4709_dev_sys_config2(&sys_conf2)) < 0) + debug("Si4709_IOC_SYS_CONFIG2 failed"); + else if( copy_to_user(argp, (void*) &sys_conf2, sizeof(sys_config2)) ) + ret = -EFAULT; + } + break; + + case Si4709_IOC_SYS_CONFIG3_GET: + { + sys_config3 sys_conf3; + debug("Si4709_IOC_SYS_CONFIG3 called"); + + if( (ret = Si4709_dev_sys_config3(&sys_conf3)) < 0) + debug("Si4709_IOC_SYS_CONFIG3 failed"); + else if(copy_to_user(argp, (void*) &sys_conf3, sizeof(sys_config3))) + ret = -EFAULT; + } + break; + + case Si4709_IOC_POWER_CONFIG_GET: + { + power_config pow_conf; + debug("Si4709_IOC_POWER_CONFIG called"); + + if( (ret = Si4709_dev_power_config(&pow_conf)) < 0) + debug("Si4709_IOC_POWER_CONFIG failed"); + else if( copy_to_user(argp, (void*) &pow_conf, sizeof(power_config)) ) + ret = -EFAULT; + } + break; + /*VNVS:END*/ + /*VNVS:START 18-NOV'09*/ + /*Reading AFCRL Bit*/ + case Si4709_IOC_AFCRL_GET: + { + u8 afc; + debug("Si4709_IOC_AFCRL_GET called"); + + if( (ret = Si4709_dev_AFCRL_get(&afc)) < 0) + debug("Si4709_IOC_AFCRL_GET failed"); + else if( copy_to_user(argp, (void*) &afc, sizeof(u8)) ) + ret = -EFAULT; + } + break; + /*Setting DE-emphasis Time Constant. For DE=0,TC=50us(Europe,Japan,Australia) and DE=1,TC=75us(USA)*/ + case Si4709_IOC_DE_SET: + { + u8 de_tc; + debug("Si4709_IOC_DE_SET called"); + + if( copy_from_user((void*) &de_tc, argp, sizeof(u8)) ) + ret = -EFAULT; + else if ( (ret = Si4709_dev_DE_set(de_tc)) < 0 ) + debug("Si4709_IOC_DE_SET failed"); + } + break; + + case Si4709_IOC_STATUS_RSSI_GET: + { + status_rssi status; + debug("Si4709_IOC_STATUS_RSSI_GET called"); + + if( (ret = Si4709_dev_status_rssi(&status)) < 0) + debug("Si4709_IOC_STATUS_RSSI_GET failed"); + else if(copy_to_user(argp, (void*) &status, sizeof(status_rssi))) + ret = -EFAULT; + } + break; + + + case Si4709_IOC_SYS_CONFIG2_SET: + { + sys_config2 sys_conf2; + unsigned long n; + debug("Si4709_IOC_SYS_CONFIG2_SET called"); + + n = copy_from_user((void*) &sys_conf2, argp, sizeof(sys_config2)); + + if(n) + { + debug("Si4709_IOC_SYS_CONFIG2_SET() : copy_from_user() has error!!Failed to read [%d] byes!", n); + ret = -EFAULT; + } + else if ( (ret = Si4709_dev_sys_config2_set(&sys_conf2)) < 0 ) + debug("Si4709_IOC_SYS_CONFIG2_SET failed"); + } + break; + + case Si4709_IOC_SYS_CONFIG3_SET: + { + sys_config3 sys_conf3; + unsigned long n; + + debug("Si4709_IOC_SYS_CONFIG3_SET called"); + + n = copy_from_user((void*) &sys_conf3, argp, sizeof(sys_config3)); + + if(n < 0) + { + debug("Si4709_IOC_SYS_CONFIG3_SET() : copy_from_user() has error!!Failed to read [%d] byes!", n); + ret = -EFAULT; + }else if ( (ret = Si4709_dev_sys_config3_set(&sys_conf3)) < 0 ) + debug("Si4709_IOC_SYS_CONFIG3_SET failed"); + } + break; + /*Resetting the RDS Data Buffer*/ + case Si4709_IOC_RESET_RDS_DATA: + { + debug("Si4709_IOC_RESET_RDS_DATA called"); + + if( (ret = Si4709_dev_reset_rds_data()) < 0) + error("Si4709_IOC_RESET_RDS_DATA failed"); + } + break; + + /*VNVS:END*/ + default: + debug(" ioctl default"); + ret = -ENOTTY; + break; + } + +exit: + mutex_unlock(&Si4709_mutex); + return ret; +} + +static irqreturn_t Si4709_isr( int irq, void *unused ) +{ + debug("Si4709_isr: FM device called IRQ: %d",irq); +#ifdef RDS_INTERRUPT_ON_ALWAYS + if( (Si4709_dev_wait_flag == SEEK_WAITING) || (Si4709_dev_wait_flag == TUNE_WAITING)) + { + debug("Si4709_isr: FM Seek/Tune Interrupt called IRQ %d",irq); + Si4709_dev_wait_flag = WAIT_OVER; + wake_up_interruptible(&Si4709_waitq); + } + else if(Si4709_RDS_flag == RDS_WAITING) //RDS Interrupt + { + debug_rds("Si4709_isr: FM RDS Interrupt called IRQ %d",irq); + RDS_Data_Available++; + RDS_Groups_Available_till_now++; + + debug_rds("RDS_Groups_Available_till_now b/w Power ON/OFF : %d",RDS_Groups_Available_till_now); + + if (RDS_Data_Available > 1) + RDS_Data_Lost++; + + if(!work_pending(&Si4709_work)) + queue_work(Si4709_wq,&Si4709_work); + } +#else + if( (Si4709_dev_wait_flag == SEEK_WAITING) || (Si4709_dev_wait_flag == TUNE_WAITING) ||(Si4709_dev_wait_flag == RDS_WAITING)) + { + Si4709_dev_wait_flag = WAIT_OVER; + wake_up_interruptible(&Si4709_waitq); + } +#endif + return IRQ_HANDLED; +} + +#if 0 +int Si4709_dev_abort_seek(void) +{ + int ret = 0; + + if( Si4709_dev_wait_flag = SEEK_WAITING ) + { + wake_up_interruptible(&Si4709_waitq); + } + return ret; +} +#endif + + +/************************************************************/ + + +void debug_ioctls(void) +{ + + debug("------------------------------------------------"); + + debug("Si4709_IOC_POWERUP 0x%x",Si4709_IOC_POWERUP ); + + debug("Si4709_IOC_POWERDOWN 0x%x",Si4709_IOC_POWERDOWN ); + + debug("Si4709_IOC_BAND_SET 0x%x",Si4709_IOC_BAND_SET ); + + debug("Si4709_IOC_CHAN_SPACING_SET 0x%x",Si4709_IOC_CHAN_SPACING_SET ); + + debug("Si4709_IOC_CHAN_SELECT 0x%x",Si4709_IOC_CHAN_SELECT ); + + debug("Si4709_IOC_CHAN_GET 0x%x",Si4709_IOC_CHAN_GET ); + + debug("Si4709_IOC_SEEK_UP 0x%x",Si4709_IOC_SEEK_UP ); + + debug("Si4709_IOC_SEEK_DOWN 0x%x",Si4709_IOC_SEEK_DOWN ); + + /*VNVS:28OCT'09---- Si4709_IOC_SEEK_AUTO is disabled as of now*/ + // debug("Si4709_IOC_SEEK_AUTO 0x%x",Si4709_IOC_SEEK_AUTO ); + + debug("Si4709_IOC_RSSI_SEEK_TH_SET 0x%x",Si4709_IOC_RSSI_SEEK_TH_SET ); + + debug("Si4709_IOC_SEEK_SNR_SET 0x%x",Si4709_IOC_SEEK_SNR_SET ); + + debug("Si4709_IOC_SEEK_CNT_SET 0x%x",Si4709_IOC_SEEK_CNT_SET ); + + debug("Si4709_IOC_CUR_RSSI_GET 0x%x",Si4709_IOC_CUR_RSSI_GET ); + + debug("Si4709_IOC_VOLEXT_ENB 0x%x",Si4709_IOC_VOLEXT_ENB ); + + debug("Si4709_IOC_VOLEXT_DISB 0x%x",Si4709_IOC_VOLEXT_DISB ); + + debug("Si4709_IOC_VOLUME_SET 0x%x",Si4709_IOC_VOLUME_SET ); + + debug("Si4709_IOC_VOLUME_GET 0x%x",Si4709_IOC_VOLUME_GET ); + + debug("Si4709_IOC_MUTE_ON 0x%x",Si4709_IOC_MUTE_ON ); + + debug("Si4709_IOC_MUTE_OFF 0x%x",Si4709_IOC_MUTE_OFF ); + + debug("Si4709_IOC_MONO_SET 0x%x",Si4709_IOC_MONO_SET ); + + debug("Si4709_IOC_STEREO_SET 0x%x",Si4709_IOC_STEREO_SET ); + + debug("Si4709_IOC_RSTATE_GET 0x%x",Si4709_IOC_RSTATE_GET ); + + debug("Si4709_IOC_RDS_DATA_GET 0x%x",Si4709_IOC_RDS_DATA_GET ); + + debug("Si4709_IOC_RDS_ENABLE 0x%x",Si4709_IOC_RDS_ENABLE); + + debug("Si4709_IOC_RDS_DISABLE 0x%x",Si4709_IOC_RDS_DISABLE); + + debug("Si4709_IOC_RDS_TIMEOUT_SET 0x%x",Si4709_IOC_RDS_TIMEOUT_SET); + + debug("Si4709_IOC_DEVICE_ID_GET 0x%x",Si4709_IOC_DEVICE_ID_GET); + + debug("Si4709_IOC_CHIP_ID_GET 0x%x",Si4709_IOC_CHIP_ID_GET); + + debug("Si4709_IOC_SYS_CONFIG2_GET 0x%x",Si4709_IOC_SYS_CONFIG2_GET); + + debug("Si4709_IOC_POWER_CONFIG_GET 0x%x",Si4709_IOC_POWER_CONFIG_GET); + + debug("Si4709_IOC_AFCRL_GET 0x%x",Si4709_IOC_AFCRL_GET); + + debug("Si4709_IOC_DE_SET 0x%x",Si4709_IOC_DE_SET); + + debug("Si4709_IOC_DSMUTE_ON 0x%x",Si4709_IOC_DSMUTE_ON); + + debug("Si4709_IOC_DSMUTE_OFF 0x%x",Si4709_IOC_DSMUTE_OFF); + + debug("Si4709_IOC_RESET_RDS_DATA 0x%x",Si4709_IOC_RESET_RDS_DATA); + + debug("------------------------------------------------"); + +} + + + + + int __init Si4709_driver_init(void) +{ + int ret = 0; + + + debug("Si4709_driver_init called"); + + /*Initialize the Si4709 dev mutex*/ + Si4709_dev_mutex_init(); + + + /*misc device registration*/ + if( (ret = misc_register(&Si4709_misc_device)) < 0 ) + { + error("Si4709_driver_init misc_register failed"); + return ret; + } + + s3c_gpio_cfgpin(GPIO_FM_INT, S3C_GPIO_SFN(0xF)); + s3c_gpio_setpull(GPIO_FM_INT, S3C_GPIO_PULL_NONE); + + irq_set_irq_type(FM_IRQ_INT, IRQ_TYPE_EDGE_FALLING); + + /*KGVS: Configuring the GPIO_FM_INT in mach-jupiter.c*/ + if( (ret = request_irq(FM_IRQ_INT, Si4709_isr, IRQF_DISABLED , "Si4709", NULL )) ) + { + error("Si4709_driver_init request_irq failed %d", GPIO_FM_INT); + goto MISC_DREG; + } + else + debug("Si4709_driver_init request_irq success %d", GPIO_FM_INT); + + if (gpio_is_valid(FM_RESET)) { + if (gpio_request(FM_RESET, "GPJ2")) + printk(KERN_ERR "Failed to request FM_RESET!\n"); + gpio_direction_output(FM_RESET, GPIO_LEVEL_LOW); + } + + /*VNVS: 13-OCT'09---- Initially Pulling the interrupt pin HIGH as the FM Radio device gives 5ms low pulse*/ + s3c_gpio_setpull(GPIO_FM_INT, S3C_GPIO_PULL_UP); + + /****Resetting the device****/ + gpio_set_value(FM_RESET, GPIO_LEVEL_LOW); + gpio_set_value(FM_RESET, GPIO_LEVEL_HIGH); + /*VNVS: 13-OCT'09---- Freeing the FM_RESET pin*/ + gpio_free(FM_RESET); + + /*Add the i2c driver*/ + if ( (ret = Si4709_i2c_drv_init() < 0) ) + { + goto MISC_IRQ_DREG; + } + + init_waitqueue_head(&Si4709_waitq); + + debug("Si4709_driver_init successful"); + + return ret; + +MISC_IRQ_DREG: + free_irq(FM_IRQ_INT, NULL); +MISC_DREG: + misc_deregister(&Si4709_misc_device); + + return ret; +} + + +void __exit Si4709_driver_exit(void) +{ + debug("Si4709_driver_exit called"); + + /*Delete the i2c driver*/ + Si4709_i2c_drv_exit(); + free_irq(FM_IRQ_INT, NULL); + + /*misc device deregistration*/ + misc_deregister(&Si4709_misc_device); +} + +module_init(Si4709_driver_init); +module_exit(Si4709_driver_exit); +MODULE_AUTHOR("Varun Mahajan <m.varun@samsung.com>"); +MODULE_DESCRIPTION("Si4709 FM tuner driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/radio/si4709/radio-si4709_main.h b/drivers/media/radio/si4709/radio-si4709_main.h new file mode 100644 index 0000000..adf98e1 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_main.h @@ -0,0 +1,9 @@ +#ifndef _Si4709_MAIN_H +#define _Si4709_MAIN_H + +#include <linux/wait.h> + +extern wait_queue_head_t Si4709_waitq; + +#endif + diff --git a/drivers/media/radio/si4709/radio-si4709_regs.h b/drivers/media/radio/si4709/radio-si4709_regs.h new file mode 100644 index 0000000..599d009 --- /dev/null +++ b/drivers/media/radio/si4709/radio-si4709_regs.h @@ -0,0 +1,859 @@ +#ifndef _Si4709_REGS_H +#define _Si4709_REGS_H + +#define NUM_OF_REGISTERS 0x10 + +/*Si4709 registers*/ +#define DEVICE_ID 0x00 +#define CHIP_ID 0x01 +#define POWERCFG 0x02 +#define CHANNEL 0x03 +#define SYSCONFIG1 0x04 +#define SYSCONFIG2 0x05 +#define SYSCONFIG3 0x06 +#define TEST1 0x07 +#define TEST2 0x08 +#define BOOTCONFIG 0x09 +#define STATUSRSSI 0x0A +#define READCHAN 0x0B +#define RDSA 0x0C +#define RDSB 0x0D +#define RDSC 0x0E +#define RDSD 0x0F + +/***********POWERCFG************/ +#define POWERCFG_DSMUTE 0x8000 +#define POWERCFG_DMUTE 0x4000 +#define POWERCFG_MONO 0x2000 +#define POWERCFG_RDSM 0x0800 +#define POWERCFG_SKMODE 0x0400 +#define POWERCFG_SEEKUP 0x0200 +#define POWERCFG_SEEK 0x0100 +#define POWERCFG_DISABLE 0x0040 +#define POWERCFG_ENABLE 0x0001 +/************************************/ + +/***********CHANNEL************/ +#define CHANNEL_TUNE 0x8000 +/************************************/ + +/***********SYSCONFIG1************/ +#define SYSCONFIG1_RDSIEN 0x8000 +#define SYSCONFIG1_STCIEN 0x4000 +#define SYSCONFIG1_RDS 0x1000 +#define SYSCONFIG1_DE 0x0800 +#define SYSCONFIG1_AGCD 0x0400 +#define SYSCONFIG1_BLNDADJ1 0x0080 +#define SYSCONFIG1_BLNDADJ0 0x0040 +#define SYSCONFIG1_GPO1 0x0008 +#define SYSCONFIG1_GPO0 0x0004 +/************************************/ + +/***********SYSCONFIG2************/ +#define SYSCONFIG2_BAND1 0x0080 +#define SYSCONFIG2_BAND0 0x0040 +#define SYSCONFIG2_SPACE1 0x0020 +#define SYSCONFIG2_SPACE0 0x0010 +#define SYSCONFIG2_VOLUME3 0x0008 +#define SYSCONFIG2_VOLUME2 0x0004 +#define SYSCONFIG2_VOLUME1 0x0002 +#define SYSCONFIG2_VOLUME0 0x0001 +/************************************/ + +/***********SYSCONFIG3************/ +#define SYSCONFIG3_SMUTER1 0x8000 +#define SYSCONFIG3_SMUTER0 0x4000 +#define SYSCONFIG3_SMUTEA1 0x2000 +#define SYSCONFIG3_SMUTEA0 0x1000 +#define SYSCONFIG3_VOLEXT 0x0100 +#define SYSCONFIG3_SKSNR3 0x0080 +#define SYSCONFIG3_SKSNR2 0x0040 +#define SYSCONFIG3_SKSNR1 0x0020 +#define SYSCONFIG3_SKSNR0 0x0010 +#define SYSCONFIG3_SKCNT3 0x0008 +#define SYSCONFIG3_SKCNT2 0x0004 +#define SYSCONFIG3_SKCNT1 0x0002 +#define SYSCONFIG3_SKCNT0 0x0001 +/************************************/ + +/***********TEST1************/ +#define TEST1_AHIZEN 0x4000 +/************************************/ + +/***********STATUSRSSI************/ +#define STATUSRSSI_RDSR 0x8000 +#define STATUSRSSI_STC 0x4000 +#define STATUSRSSI_SF_BL 0x2000 +#define STATUSRSSI_AFCRL 0x1000 +#define STATUSRSSI_RDSS 0x0800 +#define STATUSRSSI_BLERA1 0x0400 +#define STATUSRSSI_BLERA0 0x0200 +#define STATUSRSSI_ST 0x0100 +/************************************/ + +/***********READCHAN************/ +#define READCHAN_BLERB1 0x8000 +#define READCHAN_BLERB0 0x4000 +#define READCHAN_BLERC1 0x2000 +#define READCHAN_BLERC0 0x1000 +#define READCHAN_BLERD1 0x0800 +#define READCHAN_BLERD0 0x0400 + +#define READCHAN_CHAN_MASK 0x03FF +/************************************/ + +/*************************************************************/ +static inline void switch_on_bits(u16 *data, u16 bits_on) +{ + *data |= bits_on; +} + +static inline void switch_off_bits(u16 *data, u16 bits_off) +{ + u16 aux = 0xFFFF; + aux ^= bits_off; + *data &= aux; +} + +#define BIT_ON 1 +#define BIT_OFF 0 + +static inline int check_bit(u16 data, u16 bit) +{ + return (data&bit) ? BIT_ON : BIT_OFF; +} +/**************************************************************/ + + +/********************************************************************/ +static inline void POWERCFG_BITSET_ENABLE_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_ENABLE)); +} + +static inline void POWERCFG_BITSET_DISABLE_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_DISABLE)); +} + +static inline void POWERCFG_BITSET_DISABLE_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_DISABLE)); +} + +static inline void POWERCFG_BITSET_DMUTE_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_DMUTE)); +} + +static inline void POWERCFG_BITSET_DMUTE_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_DMUTE)); +} + +static inline void POWERCFG_BITSET_DSMUTE_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_DSMUTE)); +} + +static inline void POWERCFG_BITSET_DSMUTE_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_DSMUTE)); +} + +static inline void POWERCFG_BITSET_MONO_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_MONO)); +} + +static inline void POWERCFG_BITSET_MONO_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_MONO)); +} + +static inline void POWERCFG_BITSET_RDSM_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_RDSM)); +} + +static inline void POWERCFG_BITSET_RDSM_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_RDSM)); +} + +static inline void POWERCFG_BITSET_SKMODE_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_SKMODE)); +} + +static inline void POWERCFG_BITSET_SKMODE_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_SKMODE)); +} + +static inline void POWERCFG_BITSET_SEEKUP_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_SEEKUP)); +} + +static inline void POWERCFG_BITSET_SEEKUP_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_SEEKUP)); +} + +static inline void POWERCFG_BITSET_SEEK_HIGH(u16 *data) +{ + switch_on_bits(data, (POWERCFG_SEEK)); +} + +static inline void POWERCFG_BITSET_SEEK_LOW(u16 *data) +{ + switch_off_bits(data, (POWERCFG_SEEK)); +} + +static inline void POWERCFG_BITSET_RESERVED(u16 *data) +{ + *data &= 0xEF41; +} + +/********************************************************************/ + +static inline void CHANNEL_BITSET_TUNE_HIGH(u16 *data) +{ + switch_on_bits(data, (CHANNEL_TUNE)); +} + +static inline void CHANNEL_BITSET_TUNE_LOW(u16 *data) +{ + switch_off_bits(data, (CHANNEL_TUNE)); +} + +static inline void CHANNEL_BITSET_RESERVED(u16 *data) +{ + *data &= 0x83FF; +} + +/********************************************************************/ + +static inline void SYSCONFIG1_BITSET_RDSIEN_HIGH(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_RDSIEN)); +} + +static inline void SYSCONFIG1_BITSET_RDSIEN_LOW(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG1_RDSIEN)); +} + +static inline void SYSCONFIG1_BITSET_STCIEN_HIGH(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_STCIEN)); +} + +static inline void SYSCONFIG1_BITSET_STCIEN_LOW(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG1_STCIEN)); +} + +static inline void SYSCONFIG1_BITSET_RDS_HIGH(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_RDS)); +} + +static inline void SYSCONFIG1_BITSET_RDS_LOW(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG1_RDS)); +} + +static inline void SYSCONFIG1_BITSET_DE_50(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_DE)); +} + +static inline void SYSCONFIG1_BITSET_DE_75(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG1_DE)); +} + +static inline void SYSCONFIG1_BITSET_AGCD_HIGH(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_AGCD)); +} + +static inline void SYSCONFIG1_BITSET_AGCD_LOW(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG1_AGCD)); +} + +static inline void SYSCONFIG1_BITSET_RSSI_DEF_31_49(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG1_BLNDADJ1|SYSCONFIG1_BLNDADJ0)); +} + +static inline void SYSCONFIG1_BITSET_RSSI_37_55(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_BLNDADJ0)); + switch_off_bits(data, (SYSCONFIG1_BLNDADJ1)); +} + +static inline void SYSCONFIG1_BITSET_RSSI_19_37(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_BLNDADJ1)); + switch_off_bits(data, (SYSCONFIG1_BLNDADJ0)); +} + +static inline void SYSCONFIG1_BITSET_RSSI_25_43(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_BLNDADJ1|SYSCONFIG1_BLNDADJ0)); +} + +static inline void SYSCONFIG1_BITSET_GPIO_HIGH_IMP(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG1_GPO1|SYSCONFIG1_GPO0)); +} + +static inline void SYSCONFIG1_BITSET_GPIO_STC_RDS_INT(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_GPO0)); + switch_off_bits(data, (SYSCONFIG1_GPO1)); +} + +static inline void SYSCONFIG1_BITSET_GPIO_LOW(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_GPO1)); + switch_off_bits(data, (SYSCONFIG1_GPO0)); +} + +static inline void SYSCONFIG1_BITSET_GPIO_HIGH(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG1_GPO1|SYSCONFIG1_GPO0)); +} + +static inline void SYSCONFIG1_BITSET_RESERVED(u16 *data) +{ + *data &= 0xDCCC; + *data |= 0x22; +} + +/********************************************************************/ + +/*US/EUROPE (Default)*/ +static inline void SYSCONFIG2_BITSET_BAND_87p5_108_MHz(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG2_BAND1|SYSCONFIG2_BAND0)); +} + +/*Japan wide band*/ +static inline void SYSCONFIG2_BITSET_BAND_76_108_MHz(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG2_BAND0)); + switch_off_bits(data, (SYSCONFIG2_BAND1)); +} + +/*Japan*/ +static inline void SYSCONFIG2_BITSET_BAND_76_90_MHz(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG2_BAND1)); + switch_off_bits(data, (SYSCONFIG2_BAND0)); +} + +/*US, Australia (Default)*/ +static inline void SYSCONFIG2_BITSET_SPACE_200_KHz(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG2_SPACE1|SYSCONFIG2_SPACE0)); +} + +/*Europe, Japan*/ +static inline void SYSCONFIG2_BITSET_SPACE_100_KHz(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG2_SPACE0)); + switch_off_bits(data, (SYSCONFIG2_SPACE1)); +} + +static inline void SYSCONFIG2_BITSET_SPACE_50_KHz(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG2_SPACE1)); + switch_off_bits(data, (SYSCONFIG2_SPACE0)); +} + +static inline void SYSCONFIG2_BITSET_VOLUME(u16 *data, u8 volume) +{ + *data &= 0xFFF0; + *data |= (volume & 0x0F); +} + +static inline void SYSCONFIG2_BITSET_SEEKTH(u16 *data, u8 seek_th) +{ + *data &= 0x00FF; + *data |= ((seek_th << 8) & 0xFF00); +} + +static inline u8 SYSCONFIG2_GET_VOLUME(u16 data) +{ + return ( (u8) (data & 0x000F) ); +} + +/********************************************************************/ + +static inline void SYSCONFIG3_BITSET_SMUTER_FASTEST(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG3_SMUTER1|SYSCONFIG3_SMUTER0)); +} + +static inline void SYSCONFIG3_BITSET_SMUTER_FAST(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG3_SMUTER1)); + switch_on_bits(data, (SYSCONFIG3_SMUTER0)); +} + +static inline void SYSCONFIG3_BITSET_SMUTER_SLOW(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG3_SMUTER0)); + switch_on_bits(data, (SYSCONFIG3_SMUTER1)); +} + +static inline void SYSCONFIG3_BITSET_SMUTER_SLOWEST(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG3_SMUTER1|SYSCONFIG3_SMUTER0)); +} + +static inline void SYSCONFIG3_BITSET_SMUTEA_16_dB(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG3_SMUTEA1|SYSCONFIG3_SMUTEA0)); +} + +static inline void SYSCONFIG3_BITSET_SMUTEA_14dB(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG3_SMUTEA1)); + switch_on_bits(data, (SYSCONFIG3_SMUTEA0)); +} + +static inline void SYSCONFIG3_BITSET_SMUTEA_12dB(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG3_SMUTEA0)); + switch_on_bits(data, (SYSCONFIG3_SMUTEA1)); +} + +static inline void SYSCONFIG3_BITSET_SMUTEA_10dB(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG3_SMUTEA1|SYSCONFIG3_SMUTEA0)); +} + +static inline void SYSCONFIG3_BITSET_VOLEXT_DISB(u16 *data) +{ + switch_off_bits(data, (SYSCONFIG3_VOLEXT)); +} + +static inline void SYSCONFIG3_BITSET_VOLEXT_ENB(u16 *data) +{ + switch_on_bits(data, (SYSCONFIG3_VOLEXT)); +} + +static inline void SYSCONFIG3_BITSET_SKSNR(u16 *data, u8 seeksnr) +{ + *data &= 0xFF0F; + *data |= ((seeksnr<<4) & 0xF0); +} + +static inline void SYSCONFIG3_BITSET_SKCNT(u16 *data, u8 seekcnt) +{ + *data &= 0xFFF0; + *data |= ((seekcnt) & 0x0F); +} + +static inline void SYSCONFIG3_BITSET_RESERVED(u16 *data) +{ + *data &= 0xF1FF; +} + +/********************************************************************/ + +static inline void TEST1_BITSET_AHIZEN_HIGH(u16 *data) +{ + switch_on_bits(data, (TEST1_AHIZEN)); +} + +static inline void TEST1_BITSET_AHIZEN_LOW(u16 *data) +{ + switch_off_bits(data, (TEST1_AHIZEN)); +} + +static inline void TEST1_BITSET_RESERVED(u16 *data) +{ + *data &= 0x7FFF; +} + +/********************************************************************/ + +#define NEW_RDS_GROUP_READY 1 +#define NO_RDS_GROUP_READY 0 + +#define COMPLETE 1 +#define CLEAR 0 + +#define SEEK_SUCCESSFUL 1 +#define SEEK_FAILURE_BAND_LMT_RCHD 0 + +#define AFC_RAILED 1 +#define AFC_NOT_RAILED 0 + +#define RDS_DECODER_SYNCHRONIZED 1 +#define RDS_DECODER_NOT_SYNCHRONIZED 0 + +#define STEREO 1 +#define MONO 0 + +#define ERRORS_0 0 +#define ERRORS_1_2 1 +#define ERRORS_3_5 2 +#define ERRORS_NO_CORREC_POSSIBLE_6_p 3 + +static inline int STATUSRSSI_RDS_READY_STATUS(u16 data) +{ + if( check_bit(data, STATUSRSSI_RDSR) == BIT_ON ) + { + return NEW_RDS_GROUP_READY; + } + else + { + return NO_RDS_GROUP_READY; + } +} + +static inline int STATUSRSSI_SEEK_TUNE_STATUS(u16 data) +{ + if( check_bit(data, STATUSRSSI_STC) == BIT_ON ) + { + return COMPLETE; + } + else + { + return CLEAR; + } +} + +static inline int STATUSRSSI_SF_BL_STATUS(u16 data) +{ + if( check_bit(data, STATUSRSSI_SF_BL) == BIT_ON ) + { + return SEEK_FAILURE_BAND_LMT_RCHD; + } + else + { + return SEEK_SUCCESSFUL; + } +} + +static inline int STATUSRSSI_AFC_RAIL_STATUS(u16 data) +{ + if( check_bit(data, STATUSRSSI_AFCRL) == BIT_ON ) + { + return AFC_RAILED; + } + else + { + return AFC_NOT_RAILED; + } +} + +static inline int STATUSRSSI_RDS_SYNC_STATUS(u16 data) +{ + if( check_bit(data, STATUSRSSI_RDSS) == BIT_ON ) + { + return RDS_DECODER_SYNCHRONIZED; + } + else + { + return RDS_DECODER_NOT_SYNCHRONIZED; + } +} + +static inline int STATUSRSSI_RDS_BLOCK_A_ERRORS(u16 data) +{ + int ret = 0; + int bits_status = 0; + + ret = check_bit(data,STATUSRSSI_BLERA1); + + if( ret == BIT_ON ) + bits_status = 0x02; + else + bits_status = 0x00; + + ret = check_bit(data,STATUSRSSI_BLERA0); + + if( ret == BIT_ON ) + bits_status |= 0x01; + + return bits_status; +} + +static inline int STATUSRSSI_STEREO_STATUS(u16 data) +{ + if( check_bit(data, STATUSRSSI_RDSS) == BIT_ON ) + { + return STEREO; + } + else + { + return MONO; + } +} + +static inline u8 STATUSRSSI_RSSI_SIGNAL_STRENGTH(u16 data) +{ + return ((u8) (0x00FF & data)); +} + +static inline u8 DEVICE_ID_PART_NUMBER(u16 data) //vnv.srikanth +{ + data = data>>12; + return((u8)(0x000F & data)); +} + +static inline u16 DEVICE_ID_MANUFACT_NUMBER(u16 data) //vnv.srikanth +{ + return((u16)(0x0FFF & data)); +} + +static inline u8 CHIP_ID_CHIP_VERSION(u16 data) //vnv.srikanth +{ + data = data>>10; + return((u8)(0x003F & data)); +} + +static inline u8 CHIP_ID_DEVICE(u16 data) //vnv.srikanth +{ + data = data>>6; + return((u8)(0x000F & data)); +} + +static inline u8 CHIP_ID_FIRMWARE_VERSION(u16 data) //vnv.srikanth +{ + return((u8)(0x003F & data)); +} + +static inline u8 SYS_CONFIG2_RSSI_TH(u16 data) //vnv.srikanth +{ + data=data>>8; + return((u8)(0x00FF&data)); +} + +static inline u8 SYS_CONFIG2_FM_BAND(u16 data) //vnv.srikanth +{ + data=data>>6; + return((u8)(0x0003&data)); +} + +static inline u8 SYS_CONFIG2_FM_CHAN_SPAC(u16 data) //vnv.srikanth +{ + data=data>>4; + return((u8)(0x0003&data)); +} + +static inline u8 SYS_CONFIG2_FM_VOL(u16 data) //vnv.srikanth +{ + return((u8)(0x000F&data)); +} + +//POWER_CONFIG_STATUS + //vnv.srikanth-start +#define SOFTMUTE_ENABLE 0 +#define SOFTMUTE_DISABLE 1 + +#define MUTE_ENABLE 0 +#define MUTE_DISABLE 1 + +#define STEREO_SELECT 0 +#define MONO_SELECT 1 + +#define RDS_MODE_STANDARD 0 +#define RDS_MODE_VERBOSE 1 + +#define SEEK_MODE_CONT_SEEK 0 +#define SEEK_MODE_STOP_SEEK 1 + +#define SEEK_DOWN 0 +#define SEEK_UP 1 + +#define SEEK_DISABLE 0 +#define SEEK_ABLE 1 + +static inline int POWER_CONFIG_SOFTMUTE_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_DSMUTE) == BIT_ON ) + { + return SOFTMUTE_DISABLE; + } + else + { + return SOFTMUTE_ENABLE; + } +} + +static inline int POWER_CONFIG_MUTE_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_DMUTE) == BIT_ON ) + { + return MUTE_DISABLE; + } + else + { + return MUTE_ENABLE; + } +} + +static inline int POWER_CONFIG_MONO_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_MONO) == BIT_ON ) + { + return MONO_SELECT; + } + else + { + return STEREO_SELECT; + } +} + +static inline int POWER_CONFIG_RDS_MODE_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_RDSM ) == BIT_ON ) + { + return RDS_MODE_VERBOSE; + } + else + { + return RDS_MODE_STANDARD; + } +} + +static inline int POWER_CONFIG_SKMODE_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_SKMODE ) == BIT_ON ) + { + return SEEK_MODE_STOP_SEEK; + } + else + { + return SEEK_MODE_CONT_SEEK; + } +} + +static inline int POWER_CONFIG_SEEKUP_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_SEEKUP ) == BIT_ON ) + { + return SEEK_UP; + } + else + { + return SEEK_DOWN; + } +} + +static inline int POWER_CONFIG_SEEK_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_SEEK ) == BIT_ON ) + { + return SEEK_ABLE; + } + else + { + return SEEK_DISABLE; + } +} + +static inline int POWER_CONFIG_DISABLE_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_DISABLE ) == BIT_ON ) + { + return 1; + } + else + { + return 0; + } +} + +static inline int POWER_CONFIG_ENABLE_STATUS(u16 data) +{ + if( check_bit(data, POWERCFG_ENABLE ) == BIT_ON ) + { + return 1; + } + else + { + return 0; + } +} //vnv.srikanth-end +/********************************************************************/ + +static inline int READCHAN_BLOCK_B_ERRORS(u16 data) +{ + int ret = 0; + int bits_status = 0; + + ret = check_bit(data,READCHAN_BLERB1); + + if( ret == BIT_ON ) + bits_status = 0x02; + else + bits_status = 0x00; + + ret = check_bit(data,READCHAN_BLERB0); + + if( ret == BIT_ON ) + bits_status |= 0x01; + + return bits_status; +} + +static inline int READCHAN_BLOCK_C_ERRORS(u16 data) +{ + int ret = 0; + int bits_status = 0; + + ret = check_bit(data,READCHAN_BLERC1); + + if( ret == BIT_ON ) + bits_status = 0x02; + else + bits_status = 0x00; + + ret = check_bit(data,READCHAN_BLERC0); + + if( ret == BIT_ON ) + bits_status |= 0x01; + + return bits_status; +} + +static inline int READCHAN_BLOCK_D_ERRORS(u16 data) +{ + int ret = 0; + int bits_status = 0; + + ret = check_bit(data,READCHAN_BLERD1); + + if( ret == BIT_ON ) + bits_status = 0x02; + else + bits_status = 0x00; + + ret = check_bit(data,READCHAN_BLERD0); + + if( ret == BIT_ON ) + bits_status |= 0x01; + + return bits_status; +} + +static inline u16 READCHAN_GET_CHAN(u16 data) +{ + return ( data & READCHAN_CHAN_MASK ); +} + +/********************************************************************/ + +#endif + diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 7937b34..515f638 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1032,6 +1032,12 @@ config USB_S2255 endif # V4L_USB_DRIVERS +config VIDEO_CE147 + tristate "CE147 Camera Sensor" + depends on I2C && VIDEO_V4L2 + ---help--- + This driver supports CE147 SoC camera module + config VIDEO_S5KA3DFX tristate "S5KA3DFX Camera Sensor" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c4ce996b..bea5bbb 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -84,7 +84,7 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o - +obj-$(CONFIG_VIDEO_CE147) += ce147.o obj-$(CONFIG_VIDEO_S5KA3DFX) += s5ka3dfx.o obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o # And now the v4l2 drivers: diff --git a/drivers/media/video/ce147.c b/drivers/media/video/ce147.c new file mode 100755 index 0000000..bdf48e1 --- /dev/null +++ b/drivers/media/video/ce147.c @@ -0,0 +1,5670 @@ +/* + * Driver for CE147 (5MP Camera) from NEC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/vmalloc.h> +#include <linux/rtc.h> +#include <linux/completion.h> +#include <media/v4l2-device.h> +#include <media/ce147_platform.h> + +#ifdef CONFIG_VIDEO_SAMSUNG_V4L2 +#include <linux/videodev2_samsung.h> +#endif + +/* #define MDNIE_TUNING */ + +#define CE147_DRIVER_NAME "CE147" + +#define FORMAT_FLAGS_COMPRESSED 0x3 +#define SENSOR_JPEG_SNAPSHOT_MEMSIZE 0x360000 + +/* #define CE147_DEBUG */ +/* #define CE147_INFO */ + +#ifdef CE147_DEBUG +#define ce147_msg dev_err +#else +#define ce147_msg dev_dbg +#endif + +#ifdef CE147_INFO +#define ce147_info dev_err +#else +#define ce147_info dev_dbg +#endif + +/* Default resolution & pixelformat. plz ref ce147_platform.h */ +#define DEFAULT_PIX_FMT V4L2_PIX_FMT_UYVY /* YUV422 */ +#define DEFAULT_MCLK 24000000 +#define POLL_TIME_MS 10 + +/* Camera ISP command */ +#define CMD_VERSION 0x00 +#define DATA_VERSION_FW 0x00 +#define DATA_VERSION_DATE 0x01 +#define CMD_GET_BATCH_REFLECTION_STATUS 0x02 +#define DATA_VERSION_SENSOR 0x03 +#define CMD_HD_PREVIEW 0x03 +#define CMD_SET_WB 0x04 +#define DATA_VERSION_AF 0x05 +#define CMD_SET_FLASH_MANUAL 0x06 +#define CMD_SET_EXIF_CTRL 0x07 +#define CMD_AE_WB_LOCK 0x11 +#define CMD_SET_ANTI_BANDING 0x14 +#define CMD_SET_WB_AUTO 0x1A +#define CMD_SET_AUTO_FOCUS_MODE 0x20 +#define CMD_START_AUTO_FOCUS_SEARCH 0x23 +#define CMD_CHECK_AUTO_FOCUS_SEARCH 0x24 +#define CMD_STOP_LENS_MOVEMENT 0x35 +#define CMD_SET_EFFECT 0x3D +#define CMD_SET_TOUCH_AUTO_FOCUS 0x4D +#define CMD_START_OT 0x50 +#define CMD_CHECK_OT 0x51 +#define CMD_PREVIEW_SIZE 0x54 +#define CMD_FPS 0x5A +#define CMD_SET_ANTI_SHAKE 0x5B +#define CMD_SET_DATA 0x65 +#define CMD_DATA_OUT_REQ 0x66 +#define CMD_PREVIEW 0x6B +#define CMD_PREVIEW_STATUS 0x6C +#define CMD_CAPTURE_SIZE 0x73 +#define CMD_BUFFERING_CAPTURE 0x74 +#define CMD_SET_SMART_AUTO 0x82 +#define CMD_GET_SMART_AUTO_STATUS 0x83 +#define CMD_SET_WDR 0x88 +#define CMD_JPEG_SIZE 0x8E +#define CMD_JPEG_BUFFERING 0x8F +#define CMD_JPEG_CONFIG 0x90 +#define CMD_JPEG_BUFFERING2 0x92 +#define CMD_SET_FACE_DETECTION 0x9A +#define CMD_SET_FACE_LOCK 0x9C +#define CMD_INFO_EXIF 0xA0 +#define CMD_INFO_MODEL 0xA1 +#define CMD_INFO_ROT 0xA2 +#define CMD_INFO_LONGITUDE_LATITUDE 0xA3 +#define CMD_INFO_ALTITUDE 0xA4 +#define CMD_SET_FLASH 0xB2 +#ifdef CONFIG_SAMSUNG_FASCINATE +#define CMD_SET_FLASH_POWER 0xB3 +#endif +#define CMD_SET_DZOOM 0xB9 +#define CMD_GET_DZOOM_LEVEL 0xBA +#define CMD_SET_EFFECT_SHOT 0xC0 +#define DATA_VERSION_GAMMA 0xE0 +#define DATA_VERSION_SENSOR_MAKER 0xE0 +#define CMD_CHECK_DATALINE 0xEC +#define CMD_INIT 0xF0 +#define CMD_FW_INFO 0xF2 +#define CMD_FWU_UPDATE 0xF3 +#define CMD_FW_UPDATE 0xF4 +#define CMD_FW_STATUS 0xF5 +#define CMD_FW_DUMP 0xFB +#define CMD_GPS_TIMESTAMP 0xA7 + +#define CE147_FW_F2_PATH "/system/firmware/CE147F02.bin" +#define FACTORY_CHECK + +/* { FW Maj, FW Min, PRM Maj, PRM Min } */ +static unsigned char MAIN_SW_FW[4] = { 0x0, 0x0, 0x0, 0x0 }; +/* { Year, Month, Date } */ +static int MAIN_SW_DATE_INFO[3] = { 0x0, 0x0, 0x0 }; + +static unsigned char ce147_buf_set_dzoom[31] = { + 0xff, 0xe7, 0xd3, 0xc2, 0xb4, 0xa7, 0x9c, 0x93, 0x8b, 0x83, + 0x7c, 0x76, 0x71, 0x6c, 0x67, 0x63, 0x5f, 0x5b, 0x58, 0x55, + 0x52, 0x4f, 0x4d, 0x4a, 0x48, 0x46, 0x44, 0x42, 0x41, 0x40, + 0x3f +}; +static int DZoom_State; +#ifdef CONFIG_SAMSUNG_FASCINATE +static int Flash_Mode = 0; +#endif + +enum ce147_oprmode { + CE147_OPRMODE_VIDEO = 0, + CE147_OPRMODE_IMAGE = 1, +}; + +/* Declare Funtion */ +static int ce147_set_awb_lock(struct v4l2_subdev *sd, int lock); +static int ce147_set_iso(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int ce147_set_metering(struct v4l2_subdev *sd, + struct v4l2_control *ctrl); +static int ce147_set_ev(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int ce147_set_slow_ae(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int ce147_set_gamma(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int ce147_set_effect(struct v4l2_subdev *sd, struct v4l2_control *ctrl); +static int ce147_set_white_balance(struct v4l2_subdev *sd, + struct v4l2_control *ctrl); +static int ce147_s_ext_ctrl(struct v4l2_subdev *sd, + struct v4l2_ext_control *ctrl); +#ifdef CONFIG_SAMSUNG_FASCINATE +static int ce147_set_preflash(struct v4l2_subdev *sd, int flash_mode); +#endif + +enum { + AUTO_FOCUS_FAILED, + AUTO_FOCUS_DONE, + AUTO_FOCUS_CANCELLED, +}; + +enum af_operation_status { + AF_NONE = 0, + AF_START, + AF_CANCEL, + AF_INITIAL, +}; + +enum ce147_frame_size { + CE147_PREVIEW_QCIF = 0, + CE147_PREVIEW_QVGA, + CE147_PREVIEW_592x480, + CE147_PREVIEW_VGA, + CE147_PREVIEW_D1, + CE147_PREVIEW_WVGA, + CE147_PREVIEW_720P, + CE147_PREVIEW_VERTICAL_QCIF, + CE147_CAPTURE_VGA, /* 640 x 480 */ + CE147_CAPTURE_WVGA, /* 800 x 480 */ + CE147_CAPTURE_W1MP, /* 1600 x 960 */ + CE147_CAPTURE_2MP, /* UXGA - 1600 x 1200 */ + CE147_CAPTURE_W2MP, /* 35mm Academy Offset Standard 1.66 + - 2048 x 1232, 2.4MP */ + CE147_CAPTURE_3MP, /* QXGA - 2048 x 1536 */ + CE147_CAPTURE_W4MP, /* WQXGA - 2560 x 1536 */ + CE147_CAPTURE_5MP, /* 2560 x 1920 */ +}; + +struct ce147_enum_framesize { + /* mode is 0 for preview, 1 for capture */ + enum ce147_oprmode mode; + unsigned int index; + unsigned int width; + unsigned int height; +}; + +static struct ce147_enum_framesize ce147_framesize_list[] = { + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_QCIF, 176, 144 }, + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_QVGA, 320, 240 }, + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_592x480, 592, 480 }, + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_VGA, 640, 480 }, + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_D1, 720, 480 }, + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_WVGA, 800, 480 }, + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_720P, 1280, 720 }, + { CE147_OPRMODE_VIDEO, CE147_PREVIEW_VERTICAL_QCIF, 144, 176}, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_VGA, 640, 480 }, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_WVGA, 800, 480 }, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_W1MP, 1600, 960 }, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_2MP, 1600, 1200 }, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_W2MP, 2048, 1232 }, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_3MP, 2048, 1536 }, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_W4MP, 2560, 1536 }, + { CE147_OPRMODE_IMAGE, CE147_CAPTURE_5MP, 2560, 1920 }, +}; + +struct ce147_version { + unsigned int major; + unsigned int minor; +}; + +struct ce147_date_info { + unsigned int year; + unsigned int month; + unsigned int date; +}; + +enum ce147_runmode { + CE147_RUNMODE_NOTREADY, + CE147_RUNMODE_IDLE, + CE147_RUNMODE_READY, + CE147_RUNMODE_RUNNING, +}; + +struct ce147_firmware { + unsigned int addr; + unsigned int size; +}; + +/* Camera functional setting values configured by user concept */ +struct ce147_userset { + signed int exposure_bias; /* V4L2_CID_EXPOSURE */ + unsigned int ae_lock; + unsigned int awb_lock; + unsigned int auto_wb; /* V4L2_CID_AUTO_WHITE_BALANCE */ + unsigned int manual_wb; /* V4L2_CID_WHITE_BALANCE_PRESET */ + unsigned int wb_temp; /* V4L2_CID_WHITE_BALANCE_TEMPERATURE */ + unsigned int effect; /* Color FX (AKA Color tone) */ + unsigned int contrast; /* V4L2_CID_CONTRAST */ + unsigned int saturation; /* V4L2_CID_SATURATION */ + unsigned int sharpness; /* V4L2_CID_SHARPNESS */ + unsigned int glamour; +}; + +struct ce147_jpeg_param { + unsigned int enable; + unsigned int quality; + unsigned int main_size; /* Main JPEG file size */ + unsigned int thumb_size; /* Thumbnail file size */ + unsigned int main_offset; + unsigned int thumb_offset; + unsigned int postview_offset; +} ; + +struct ce147_position { + int x; + int y; +} ; + +struct ce147_gps_info { + unsigned char ce147_gps_buf[8]; + unsigned char ce147_altitude_buf[4]; + unsigned long gps_timeStamp; + char gps_processingmethod[50]; +}; + +struct ce147_sensor_maker { + unsigned int maker; + unsigned int optical; +}; + +struct ce147_version_af { + unsigned int low; + unsigned int high; +}; + +struct ce147_gamma { + unsigned int rg_low; + unsigned int rg_high; + unsigned int bg_low; + unsigned int bg_high; +}; + +#if 0 +struct tm { + int tm_sec; /* seconds */ + int tm_min; /* minutes */ + int tm_hour; /* hours */ + int tm_mday; /* day of the month */ + int tm_mon; /* month */ + int tm_year; /* year */ + int tm_wday; /* day of the week */ + int tm_yday; /* day in the year */ + int tm_isdst; /* daylight saving time */ + + long int tm_gmtoff; /* Seconds east of UTC. */ + const char *tm_zone; /* Timezone abbreviation. */ +}; +#endif + +struct gps_info_common { + unsigned int direction; + unsigned int dgree; + unsigned int minute; + unsigned int second; +}; + +struct ce147_state { + struct ce147_platform_data *pdata; + struct v4l2_subdev sd; + struct v4l2_pix_format pix; + struct v4l2_fract timeperframe; + struct ce147_userset userset; + struct ce147_jpeg_param jpeg; + struct ce147_version fw; + struct ce147_version prm; + struct ce147_date_info dateinfo; + struct ce147_firmware fw_info; + struct ce147_position position; + struct ce147_sensor_maker sensor_info; + struct ce147_version_af af_info; + struct ce147_gamma gamma; + struct v4l2_streamparm strm; + struct ce147_gps_info gpsInfo; + struct mutex ctrl_lock; + enum ce147_runmode runmode; + enum ce147_oprmode oprmode; + int framesize_index; + int sensor_version; + int freq; /* MCLK in Hz */ + int fps; + int ot_status; + int sa_status; + int anti_banding; + int preview_size; + unsigned int fw_dump_size; + int hd_preview_on; + int pre_focus_mode; + enum af_operation_status af_status; + struct ce147_version main_sw_fw; + struct ce147_version main_sw_prm; + struct ce147_date_info main_sw_dateinfo; + int exif_orientation_info; + int check_dataline; + int hd_slow_ae; + int hd_gamma; + int iso; + int metering; + int ev; + int effect; + int wb; + struct tm *exifTimeInfo; +#if defined(CONFIG_ARIES_NTT) || defined(CONFIG_SAMSUNG_FASCINATE) + int disable_aeawb_lock; +#endif + int exif_ctrl; + int thumb_null; +}; + +static int condition; + +static const struct v4l2_mbus_framefmt capture_fmts[] = { + { + .code = V4L2_MBUS_FMT_FIXED, + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; + +static inline struct ce147_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ce147_state, sd); +} + +/** + * ce147_i2c_write_multi: Write (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * + * Returns 0 on success, <0 on error + */ +static int ce147_i2c_write_multi(struct i2c_client *client, unsigned char cmd, + unsigned char *w_data, unsigned int w_len) +{ + int retry_count = 1; + unsigned char buf[w_len + 1]; + struct i2c_msg msg = { client->addr, 0, w_len + 1, buf }; + + int ret = -1; + + buf[0] = cmd; + memcpy(buf + 1, w_data, w_len); + +#ifdef CE147_DEBUG + { + int j; + pr_debug("W: "); + for (j = 0; j <= w_len; j++) + pr_debug("0x%02x ", buf[j]); + pr_debug("\n"); + } +#endif + + while (retry_count--) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + break; + msleep(POLL_TIME_MS); + } + + return (ret == 1) ? 0 : -EIO; +} + +/** + * ce147_i2c_read_multi: Read (I2C) multiple bytes to the camera sensor + * @client: pointer to i2c_client + * @cmd: command register + * @w_data: data to be written + * @w_len: length of data to be written + * @r_data: buffer where data is read + * @r_len: number of bytes to read + * + * Returns 0 on success, <0 on error + */ +static int ce147_i2c_read_multi(struct i2c_client *client, unsigned char cmd, + unsigned char *w_data, unsigned int w_len, + unsigned char *r_data, unsigned int r_len) +{ + unsigned char buf[w_len + 1]; + struct i2c_msg msg = { client->addr, 0, w_len + 1, buf }; + int ret = -1; + int retry_count = 1; + + buf[0] = cmd; + memcpy(buf + 1, w_data, w_len); + +#ifdef CE147_DEBUG + { + int j; + pr_debug("R: "); + for (j = 0; j <= w_len; j++) + pr_debug("0x%02x ", buf[j]); + pr_debug("\n"); + } +#endif + + while (retry_count--) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + break; + msleep(POLL_TIME_MS); + } + + if (ret < 0) + return -EIO; + + msg.flags = I2C_M_RD; + msg.len = r_len; + msg.buf = r_data; + + retry_count = 1; + while (retry_count--) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + break; + msleep(POLL_TIME_MS); + } + + return (ret == 1) ? 0 : -EIO; +} + +/** + * ce147_power_en: Enable or disable the camera sensor power + * Use only for updating camera firmware + * Returns 0 forever + */ +static int ce147_power_en(int onoff, struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_platform_data *pdata; + + pdata = client->dev.platform_data; + + if (onoff == 1) + pdata->power_en(1); + else + pdata->power_en(0); + + return 0; +} + +/** + * This function checks the status of the camera sensor by polling + * through the 'cmd' command register. + * + * 'polling_interval' is the delay between successive polling events + * + * The function returns if + * o 'timeout' (in ms) expires + * o the data read from device matches 'value' + * + * On success it returns the time taken for successful wait. + * On failure, it returns -EBUSY. + * On I2C related failure, it returns -EIO. + */ +static int ce147_waitfordone_timeout(struct i2c_client *client, + unsigned char cmd, unsigned char value, + int timeout, int polling_interval) +{ + int err; + unsigned char cam_status = 0xFF; + unsigned long jiffies_start = jiffies; + unsigned long jiffies_timeout = + jiffies_start + msecs_to_jiffies(timeout); + + if (polling_interval < 0) + polling_interval = POLL_TIME_MS; + + while (time_before(jiffies, jiffies_timeout)) { + cam_status = 0xFF; + err = ce147_i2c_read_multi(client, + cmd, NULL, 0, &cam_status, 1); + if (err < 0) + return -EIO; + + ce147_msg(&client->dev, "Status check returns %02x\n", + cam_status); + + if (cam_status == value) + break; + + msleep(polling_interval); + } + + if (cam_status != value) + return -EBUSY; + else + return jiffies_to_msecs(jiffies - jiffies_start); +} + +static int ce147_get_batch_reflection_status(struct v4l2_subdev *sd) +{ + int err; + int end_cnt = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_batch_data[1] = { 0x00 }; + unsigned char ce147_batch_ref_status = 0x00; + + err = ce147_i2c_write_multi(client, 0x01, ce147_buf_batch_data, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "forget_batch_reflection_status\n", __func__); + return -EIO; + } + + /* TODO: This code needs timeout API for do-while */ + do { + msleep(10); + err = ce147_i2c_read_multi(client, + CMD_GET_BATCH_REFLECTION_STATUS, NULL, 0, + &ce147_batch_ref_status, 1); + + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read " + "for get_batch_reflection_status\n", + __func__); + return -EIO; + } + end_cnt++; + } while (ce147_batch_ref_status && end_cnt < 200); + + if (end_cnt > 5) { + ce147_msg(&client->dev, "%s: count(%d) status(%02x)\n", + __func__, end_cnt, ce147_batch_ref_status); + } + + if (ce147_batch_ref_status != 0x00) { + dev_err(&client->dev, "%s: failed: " + "to get_batch_reflection_status\n", __func__); + return -EINVAL; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_read_fw_bin(const char *path, char *fwBin, int *fwSize) +{ + char *buffer = NULL; + unsigned int file_size = 0; + + struct file *filep = NULL; + mm_segment_t old_fs; + + filep = filp_open(path, O_RDONLY, 0) ; + + if (filep && (filep != ERR_PTR(-ENOENT))) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + + file_size = filep->f_op->llseek(filep, 0, SEEK_END); + filep->f_op->llseek(filep, 0, SEEK_SET); + + buffer = kmalloc(file_size + 1, GFP_KERNEL); + + filep->f_op->read(filep, buffer, file_size, &filep->f_pos); + buffer[file_size] = '\0'; + + filp_close(filep, current->files); + + set_fs(old_fs); + + pr_debug("File size : %d\n", file_size); + } else + return -EINVAL; + + memcpy(fwBin, buffer, file_size); + *fwSize = file_size; + + kfree(buffer); + + return 0; +} + +static int ce147_get_main_sw_fw_version(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + char fw_data[20] = { 0, }; + int fw_size = 0; + int main_sw_fw_prm_offset = 4; + int main_sw_date_offset = 10; + int err = 0; +#if 0 + int i; +#endif + + pr_debug("ce147_get_main_sw_fw_version Enter\n"); + + if ((MAIN_SW_DATE_INFO[0] == 0x00) && (MAIN_SW_DATE_INFO[1] == 0x00) + && (MAIN_SW_DATE_INFO[2] == 0x00)) { + err = ce147_read_fw_bin(CE147_FW_F2_PATH, fw_data, &fw_size); + if (err < 0) { + pr_debug("fail : read main_sw_version\n"); + return err; + } + +#if 0 + pr_debug("fw_size : %d\n", fw_size); + + for (i = 0; i < fw_size; i++) + pr_debug("fw_data : %x\n", fw_data[i]); +#endif + + /* Main SW FW/PRM info */ + MAIN_SW_FW[0] = fw_data[main_sw_fw_prm_offset]; + MAIN_SW_FW[1] = fw_data[main_sw_fw_prm_offset + 1]; + MAIN_SW_FW[2] = fw_data[main_sw_fw_prm_offset + 2]; + MAIN_SW_FW[3] = fw_data[main_sw_fw_prm_offset + 3]; + + /* Main SW Date info */ + MAIN_SW_DATE_INFO[0] = (2000 + fw_data[main_sw_date_offset]); + MAIN_SW_DATE_INFO[1] = fw_data[main_sw_date_offset + 1]; + MAIN_SW_DATE_INFO[2] = fw_data[main_sw_date_offset + 2]; + + pr_debug("fw M:%d m:%d |prm M:%d m:%d\n", + MAIN_SW_FW[0], MAIN_SW_FW[1], + MAIN_SW_FW[2], MAIN_SW_FW[3]); + pr_debug("y. m. d = %d.%d.%d\n", + MAIN_SW_DATE_INFO[0], MAIN_SW_DATE_INFO[1], + MAIN_SW_DATE_INFO[2]); + } else + pr_debug("already read main sw version\n"); + + state->main_sw_fw.major = MAIN_SW_FW[0]; + state->main_sw_fw.minor = MAIN_SW_FW[1]; + state->main_sw_prm.major = MAIN_SW_FW[2]; + state->main_sw_prm.minor = MAIN_SW_FW[3]; + state->main_sw_dateinfo.year = MAIN_SW_DATE_INFO[0]; + state->main_sw_dateinfo.month = MAIN_SW_DATE_INFO[1]; + state->main_sw_dateinfo.date = MAIN_SW_DATE_INFO[2]; + + return 0; +} + +static int ce147_load_fw(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int ce147_reglen_init = 1; + unsigned char ce147_regbuf_init[1] = { 0x00 }; + int err; + + /* Just before this function call, we enable the power and clock. Hence + * we need to wait for some time before we can start communicating + * with the sensor. + */ + msleep(10); + + err = ce147_i2c_write_multi(client, CMD_INIT, + ce147_regbuf_init, ce147_reglen_init); + if (err < 0) + return -EIO; + + /* At least 700ms delay required to load the firmware + * for ce147 camera ISP */ + msleep(700); + + state->runmode = CE147_RUNMODE_IDLE; + + return 0; +} + + +static int ce147_get_version(struct v4l2_subdev *sd, int object_id, + unsigned char version_info[]) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned char cmd_buf[1] = { 0x00 }; + unsigned int cmd_len = 1; + unsigned int info_len = 4; + int err; + + switch (object_id) { + case DATA_VERSION_FW: + case DATA_VERSION_DATE: + case DATA_VERSION_SENSOR: + case DATA_VERSION_SENSOR_MAKER: + case DATA_VERSION_AF: + cmd_buf[0] = object_id; + break; + default: + return -EINVAL; + } + + err = ce147_i2c_read_multi(client, CMD_VERSION, cmd_buf, cmd_len, + version_info, info_len); + if (err < 0) + return -EIO; + + return 0; +} + +static int ce147_get_fw_version(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + unsigned char version_info[4] = { 0x00, 0x00, 0x00, 0x00 }; + int err = -1; + + err = ce147_get_version(sd, DATA_VERSION_FW, version_info); + + if (err < 0) + return err; + + state->fw.minor = version_info[0]; + state->fw.major = version_info[1]; + + state->prm.minor = version_info[2]; + state->prm.major = version_info[3]; + + return 0; +} + +static int ce147_get_dateinfo(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + unsigned char version_info[4] = { 0x00, 0x00, 0x00, 0x00 }; + int err = -1; + + err = ce147_get_version(sd, DATA_VERSION_DATE, version_info); + + if (err < 0) + return err; + + state->dateinfo.year = version_info[0] - 'A' + 2007; + state->dateinfo.month = version_info[1] - 'A' + 1; + state->dateinfo.date = version_info[2]; + + return 0; +} + +static int ce147_get_sensor_version(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + unsigned char version_info[4] = { 0x00, 0x00, 0x00, 0x00 }; + int err = -1; + + err = ce147_get_version(sd, DATA_VERSION_SENSOR, version_info); + + if (err < 0) + return err; + + state->sensor_version = version_info[0]; + + return 0; +} + +static int ce147_get_sensor_maker_version(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + unsigned char version_info[4] = { 0x00, 0x00, 0x00, 0x00 }; + int err = -1; + + err = ce147_get_version(sd, DATA_VERSION_SENSOR_MAKER, version_info); + + if (err < 0) + return err; + + state->sensor_info.maker = version_info[0]; + state->sensor_info.optical = version_info[1]; + + return 0; +} + +static int ce147_get_af_version(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + unsigned char version_info[4] = { 0x00, 0x00, 0x00, 0x00 }; + int err = -1; + + err = ce147_get_version(sd, DATA_VERSION_AF, version_info); + + if (err < 0) + return err; + + /* pr_debug("ce147_get_af_version: data0: 0x%02x, data1: 0x%02x\n", + version_info[0], version_info[1]); */ + + state->af_info.low = version_info[1]; + state->af_info.high = version_info[0]; + + return 0; +} + +static int ce147_get_gamma_version(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + unsigned char gamma_info[2] = { 0x00, 0x00 }; + unsigned int info_len = 2; + int err = -1; + + unsigned char rg_low_buf[2] = { 0x0C, 0x00 }; + unsigned char rg_high_buf[2] = { 0x0D, 0x00 }; + unsigned char bg_low_buf[2] = { 0x0E, 0x00 }; + unsigned char bg_high_buf[2] = { 0x0F, 0x00 }; + unsigned int buf_len = 2; + + + err = ce147_i2c_read_multi(client, DATA_VERSION_GAMMA, + rg_low_buf, buf_len, gamma_info, info_len); + if (err < 0) + return -EIO; + + state->gamma.rg_low = gamma_info[1]; + /* pr_debug("ce147_get_gamma_version1: data1: 0x%02x, data1: 0x%02x\n", + gamma_info[0], gamma_info[1]); */ + + err = ce147_i2c_read_multi(client, DATA_VERSION_GAMMA, + rg_high_buf, buf_len, gamma_info, info_len); + if (err < 0) + return -EIO; + + state->gamma.rg_high = gamma_info[1]; + /* pr_debug("ce147_get_gamma_version1: data1: 0x%02x, data1: 0x%02x\n", + gamma_info[0], gamma_info[1]); */ + + err = ce147_i2c_read_multi(client, DATA_VERSION_GAMMA, + bg_low_buf, buf_len, gamma_info, info_len); + if (err < 0) + return -EIO; + + state->gamma.bg_low = gamma_info[1]; + /* pr_debug("ce147_get_gamma_version1: data1: 0x%02x, data1: 0x%02x\n", + gamma_info[0], gamma_info[1]); */ + + err = ce147_i2c_read_multi(client, DATA_VERSION_GAMMA, + bg_high_buf, buf_len, gamma_info, info_len); + if (err < 0) + return -EIO; + + state->gamma.bg_high = gamma_info[1]; + /* pr_debug("ce147_get_gamma_version1: data1: 0x%02x, data1: 0x%02x\n", + gamma_info[0], gamma_info[1]); */ + + return 0; +} + +#ifndef MDNIE_TUNING +static int ce147_update_fw(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + unsigned char *mbuf = NULL; + unsigned char *fw_buf[4]; + int fw_size[4]; + int index = 0; + int i = 0; + int err; + + const unsigned int packet_size = 129; /* Data 128 + Checksum 1 */ + unsigned int packet_num, k, j = 0, l = 0; + unsigned char res = 0x00; + unsigned char data[129]; + unsigned char data2[129]; + + /* dev_err(&client->dev, "%s: ce147_fw: buf = 0x%p, len = %d\n", + __func__, (void*)state->fw_info.addr, state->fw_info.size); */ + + mbuf = vmalloc(state->fw_info.size); + + if (NULL == mbuf) + return -ENOMEM; + + if (copy_from_user(mbuf, (void *)state->fw_info.addr, + state->fw_info.size)) { + err = -EFAULT; + goto out; + } + + /* The firmware buffer is now copied to mbuf, + * so the firmware code is now in mbuf. + * We can use mbuf with i2c_tranfer call + */ + for (i = 0; i < 4; i++) { + if (index > state->fw_info.size - 4) { + dev_err(&client->dev, "%s:Error size parameter\n", + __func__); + break; + } + memcpy(fw_size + i, mbuf + index, 4); + index += 4; + fw_buf[i] = mbuf + index; + index += ((fw_size[i] - 1) & (~0x3)) + 4; + dev_err(&client->dev, "%s: [%d] fw_size = %d, fw_buf = 0x%p\n", + __func__, i, fw_size[i], fw_buf[i]); + } + + err = ce147_power_en(1, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(on)\n", + __func__); + err = -EIO; + goto out; + } + + msleep(100); + + /* [1] set fw updater info */ + err = ce147_i2c_write_multi(client, CMD_FW_INFO, fw_buf[0], 4); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for 0xf2, " + "fw_size[0]: %d, fw_buf[0]: 0x%02x\n", + __func__, fw_size[0], + (unsigned int)(fw_buf[0])); + err = -EIO; + goto out; + } + msleep(100); + + /* pr_debug("ce147_update_fw: i2c_write for 0xf2, " + "fw_size[0]: %d, fw_buf[0]: 0x%02x\n", + fw_size[0], fw_buf[0]); */ + + packet_num = *(fw_buf[0]) + (*(fw_buf[0]+1)<<8); + + /* [2] update firmware */ + for (k = 0; k < packet_num; k++) { + memcpy(&data[0], fw_buf[1]+j, packet_size); + err = ce147_i2c_read_multi(client, CMD_FWU_UPDATE, + data, packet_size, &res, 1); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read for 0xf3, " + "data: 0x%02x\n", __func__, data[0]); + err = -EIO; + goto out; + } + msleep(10); + j += 129; + /* pr_debug("ce147_update_fw: i2c_read for 0xf3, " + "data: 0x%02x, count: %d\n", data[0], k); */ + } + + k = 0; + /* [3] get fw status */ + do { + msleep(100); + + err = ce147_i2c_read_multi(client, CMD_FW_STATUS, NULL, 0, + &res, 1); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read for 0xf5", + __func__); + err = -EIO; + goto out; + } + /* pr_debug("ce147_update_fw: i2c_read for 0xf5, " + "data: 0x%02x\n", res); */ + + k++; + if (k == 500) + break; + } while (res != 0x05); + + msleep(500); + + fw_size[2] = 4; + + /* [4] set fw updater info */ + err = ce147_i2c_write_multi(client, CMD_FW_INFO, fw_buf[2], fw_size[2]); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for 0xf2, " + "fw_size[2]: %d, fw_buf[2]: 0x%02x\n", + __func__, fw_size[2], + (unsigned int)(fw_buf[2])); + err = -EIO; + goto out; + } + msleep(100); + + /* pr_debug("ce147_update_fw: i2c_write for 0xf2, fw_size[2]: %d, + fw_buf[2]: 0x%02x\n", fw_size[2], fw_buf[2]); */ + + packet_num = *(fw_buf[2]) + (*(fw_buf[2] + 1) << 8); + + /* pr_debug("ce147_update_fw: packet_num: %d\n", packet_num); */ + + j = 0; + + /* [5] update firmware */ + for (l = 0; l < packet_num; l++) { + memcpy(&data2[0], fw_buf[3] + j, packet_size); + err = ce147_i2c_write_multi(client, CMD_FW_UPDATE, + data2, packet_size); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read " + "for 0xf4, data:2 0x%02x\n", + __func__, data2[0]); + err = -EIO; + goto out; + } + + /* pr_debug("ce147_update_fw: i2c_write for 0xf4, " + "data2: 0x%02x, count: %d\n", data2[0], l); */ + + msleep(10); + j += 129; + } + + l = 0; + /* [6] get fw status */ + do { + msleep(100); + + err = ce147_i2c_read_multi(client, CMD_FW_STATUS, + NULL, 0, &res, 1); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read for 0xf5", + __func__); + err = -EIO; + goto out; + } + /* pr_debug("ce147_update_fw: i2c_read for 0xf5, " + "data: 0x%02x\n", res); */ + + l++; + if (l == 500) + break; + } while (res != 0x06); + + vfree(mbuf); + + err = ce147_power_en(0, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(off)\n", + __func__); + return -EIO; + } + + dev_err(&client->dev, "%s: ce147_power_en(off)\n", __func__); + + return 0; +out: + vfree(mbuf); + + return err; +} + +#else +unsigned short *test[1]; +EXPORT_SYMBOL(test); +extern void mDNIe_txtbuf_to_parsing(void); +extern void mDNIe_txtbuf_to_parsing_for_lightsensor(void); +extern void mDNIe_txtbuf_to_parsing_for_backlight(void); +static int ce147_update_fw(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + unsigned char *mbuf = NULL; + unsigned char *fw_buf[4]; + int fw_size[4]; + int index = 0; + int i = 0; + int err; + + const unsigned int packet_size = 129; /* Data 128 + Checksum 1 */ + unsigned int packet_num, k, j, l = 0; + unsigned char res = 0x00; + unsigned char data[129]; + unsigned char data2[129]; + + /* dev_err(&client->dev, "%s: ce147_fw: buf = 0x%p, len = %d\n", + __func__, (void*)state->fw_info.addr, + state->fw_info.size); */ + + mbuf = vmalloc(state->fw_info.size); + + if (!mbuf) + return -ENOMEM; + + if (copy_from_user(mbuf, (void *)state->fw_info.addr, + state->fw_info.size)) { + vfree(mbuf); + return -EFAULT; + } + + /* The firmware buffer is now copied to mbuf, + * so the firmware code is now in mbuf. + * We can use mbuf with i2c_tranfer call */ + for (i = 0; i < 4; i++) { + if (index > state->fw_info.size - 4) { + dev_err(&client->dev, "%s:Error size parameter\n", + __func__); + break; + } + memcpy(fw_size + i, mbuf + index, 4); + index += 4; + fw_buf[i] = mbuf + index; + index += ((fw_size[i] - 1) & (~0x3)) + 4; + dev_err(&client->dev, "%s: [%d] fw_size = %d, fw_buf = 0x%p\n", + __func__, i, fw_size[i], fw_buf[i]); + } + + test[0] = fw_buf[0]; + + for (j = 0; j < fw_size[0]; j++) { + pr_debug("ce147_update_fw: , fw_size[0]: %d, test[0]: 0x%x\n", + fw_size[0], test[0][j]); + test[0][j] = ((test[0][j] & 0xff00) >> 8) | + ((test[0][j] & 0x00ff) << 8); + pr_debug("ce147_update_fw: , test1[0]: 0x%x\n", test[0][j]); + } + + /* for mdnie tuning */ + + mDNIe_txtbuf_to_parsing(); + /* mDNIe_txtbuf_to_parsing_for_lightsensor(); */ + /* mDNIe_txtbuf_to_parsing_for_backlight(); */ + + return 0; +} +#endif + +static int ce147_dump_fw(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + unsigned char *mbuf = NULL; + unsigned char *fw_buf[4]; + int fw_size[4]; + int index = 0; + int i = 0; + int err; + + const unsigned int packet_size = 129; /* Data 128 + Checksum 1 */ + unsigned int packet_num, k, j = 0, l = 0; + unsigned char res = 0x00; + unsigned char data[129]; + unsigned char data2[130]; + unsigned char addr[4] = { 0x03, 0x00, 0x00, 0x01 }; + unsigned int addr_len = 4; + unsigned char dump[1] = { 0x00 }; + + /* dev_err(&client->dev, "%s: ce147_fw: buf = 0x%p, len = %d\n", + __func__, (void*)state->fw_info.addr, state->fw_info.size); */ + + mbuf = vmalloc(state->fw_info.size); + + if (NULL == mbuf) + return -ENOMEM; + + if (copy_from_user(mbuf, (void *)state->fw_info.addr, + state->fw_info.size)) { + err = -EFAULT; + goto out; + } + + /* The firmware buffer is now copied to mbuf, + * so the firmware code is now in mbuf. + * We can use mbuf with i2c_tranfer call */ + for (i = 0; i < 4; i++) { + if (index > state->fw_info.size - 4) { + dev_err(&client->dev, "%s:Error size parameter\n", + __func__); + break; + } + memcpy(fw_size+i, mbuf + index, 4); + index += 4; + fw_buf[i] = mbuf + index; + index += ((fw_size[i] - 1) & (~0x3)) + 4; + dev_err(&client->dev, "%s: [%d] fw_size = %d, fw_buf = 0x%p\n", + __func__, i, fw_size[i], fw_buf[i]); + } + + err = ce147_power_en(1, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(on)\n", + __func__); + err = -EIO; + goto out; + } + + msleep(100); + + /* [1] set fw updater info */ + err = ce147_i2c_write_multi(client, CMD_FW_INFO, fw_buf[0], 4); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for 0xf2, " + "fw_size[0]: %d, fw_buf[0]: 0x%02x\n", + __func__, fw_size[0], + (unsigned int)(fw_buf[0])); + err = -EIO; + goto out; + } + msleep(100); + + /* pr_debug("ce147_update_fw: i2c_write for 0xf2, fw_size[0]: %d, " + "fw_buf[0]: 0x%02x\n", fw_size[0], fw_buf[0]); */ + + packet_num = *(fw_buf[0]) + (*(fw_buf[0] + 1) << 8); + + /* [2] update firmware */ + for (k = 0; k < packet_num; k++) { + memcpy(&data[0], fw_buf[1] + j, packet_size); + err = ce147_i2c_read_multi(client, CMD_FWU_UPDATE, + data, packet_size, &res, 1); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read for 0xf3, " + "data: 0x%02x\n", __func__, data[0]); + err = -EIO; + goto out; + } + msleep(10); + j += 129; + /* pr_debug("ce147_update_fw: i2c_read for 0xf3, data: 0x%02x, " + "count: %d\n", data[0], k); */ + } + + k = 0; + /* [3] get fw status */ + do { + msleep(100); + + err = ce147_i2c_read_multi(client, CMD_FW_STATUS, NULL, 0, + &res, 1); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read for 0xf5", + __func__); + err = -EIO; + goto out; + } + /* pr_debug("ce147_update_fw: i2c_read for 0xf5, " + "data: 0x%02x\n", res); */ + + k++; + if (k == 500) + break; + } while (res != 0x05); + + msleep(500); + + /* [4] change from dump mode */ + err = ce147_i2c_write_multi(client, CMD_FW_DUMP, dump, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for 0xfb, 0x00", + __func__); + err = -EIO; + goto out; + } + msleep(100); + + dump[0] = 0x02; + + /* [5] check fw mode is in dump mode */ + err = ce147_i2c_read_multi(client, CMD_FW_DUMP, dump, 1, &res, 1); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read for 0xfb", __func__); + err = -EIO; + goto out; + } + + if (res != 1) { + dev_err(&client->dev, "%s: fail: res is %x", __func__, res); + err = -EIO; + goto out; + } + + msleep(100); + + /* [6] set dump start address */ + err = ce147_i2c_write_multi(client, CMD_FW_DUMP, addr, addr_len); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for 0xfb, 0x03", + __func__); + err = -EIO; + goto out; + } + msleep(100); + + j = 0; + + packet_num = *(fw_buf[2]) + (*(fw_buf[2] + 1) << 8); + /* pr_debug("ce147_update_fw: i2c_read for 0xfb, packet_num: %d\n", + packet_num); */ + + dump[0] = 0x04; + + /* [7] dump firmware data */ + for (l = 0; l < packet_num; l++) { + err = ce147_i2c_read_multi(client, CMD_FW_DUMP, dump, 1, + data2, packet_size + 1); + if (err < 0) { + dev_err(&client->dev, "%s: fail: i2c_read for 0xfb, " + "0x04\n", __func__); + err = -EIO; + goto out; + } + memcpy(fw_buf[3] + j, &data2[0], packet_size - 1); + + msleep(10); + j += 129; + /* pr_debug("ce147_update_fw: i2c_read for 0xfb, count: %d\n", + l); */ + } + + state->fw_dump_size = packet_num * packet_size; + + if (copy_to_user((void *)(state->fw_info.addr), fw_buf[3], + state->fw_dump_size)) { + err = -EIO; + goto out; + } + + vfree(mbuf); + + err = ce147_power_en(0, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(off)\n", + __func__); + return -EIO; + } + + dev_err(&client->dev, "%s: ce147_power_en(off)\n", __func__); + + return 0; +out: + vfree(mbuf); + + return err; +} + +static int ce147_check_dataline(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_check_dataline[2] = { 0x01, 0x01 }; + unsigned int ce147_len_check_dataline = 2; + + err = ce147_i2c_write_multi(client, CMD_CHECK_DATALINE, + ce147_buf_check_dataline, ce147_len_check_dataline); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "check_dataline\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_check_dataline_stop(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_check_dataline[2] = { 0x00, 0x00 }; + unsigned int ce147_len_check_dataline = 2; + + err = ce147_i2c_write_multi(client, CMD_CHECK_DATALINE, + ce147_buf_check_dataline, ce147_len_check_dataline); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "check_dataline stop\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_preview_size(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int index = state->framesize_index; + /* Default VGA resolution = { 0x04, 0x01 } */ + unsigned char ce147_regbuf_preview_size[2] = { 0x04, 0x01 }; + unsigned int ce147_reglen_preview_size = 2; + unsigned char ce147_regbuf_hd_preview[1] = { 0x00 }; + unsigned int ce147_reglen_hd_preview = 1; + + ce147_msg(&client->dev, "%s: index = %d\n", __func__, index); + + switch (index) { + case CE147_PREVIEW_QCIF: + ce147_regbuf_preview_size[0] = 0x1E; + break; + case CE147_PREVIEW_QVGA: + ce147_regbuf_preview_size[0] = 0x02; + break; + + case CE147_PREVIEW_592x480: + ce147_regbuf_preview_size[0] = 0x24; + break; + + case CE147_PREVIEW_VGA: + ce147_regbuf_preview_size[0] = 0x04; + break; + case CE147_PREVIEW_WVGA: + ce147_regbuf_preview_size[0] = 0x13; + break; + case CE147_PREVIEW_D1: + ce147_regbuf_preview_size[0] = 0x20; + break; + case CE147_PREVIEW_720P: + ce147_regbuf_preview_size[0] = 0x16; + ce147_regbuf_preview_size[1] = 0x02; + break; + case CE147_PREVIEW_VERTICAL_QCIF: + ce147_regbuf_preview_size[0] = 0x26; + break; + default: + /* When running in image capture mode, the call comes here. + * Set the default video resolution - CE147_PREVIEW_VGA + */ + ce147_msg(&client->dev, "Setting preview resoution as VGA " + "for image capture mode\n"); + break; + } + + if (index == CE147_PREVIEW_720P) { + ce147_regbuf_hd_preview[0] = 0x01; + state->hd_preview_on = 1; + pr_info("%s: preview_size is HD (%d)\n", + __func__, state->hd_preview_on); + err = ce147_i2c_write_multi(client, CMD_HD_PREVIEW, + ce147_regbuf_hd_preview, + ce147_reglen_hd_preview); + if (err < 0) + return -EIO; + } else { + state->hd_preview_on = 0; + pr_info("%s: preview_size is not HD (%d)\n", + __func__, state->hd_preview_on); + err = ce147_i2c_write_multi(client, CMD_HD_PREVIEW, + ce147_regbuf_hd_preview, + ce147_reglen_hd_preview); + if (err < 0) + return -EIO; + } + mdelay(5); + + err = ce147_i2c_write_multi(client, CMD_PREVIEW_SIZE, + ce147_regbuf_preview_size, ce147_reglen_preview_size); + if (err < 0) { + pr_info("%s: preview_size is not HD (%d)\n", + __func__, state->hd_preview_on); + return -EIO; + } + + ce147_msg(&client->dev, "Done\n"); + + return err; +} + +static int ce147_set_frame_rate(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_regbuf_fps[2] = { 0x1E, 0x00 }; + unsigned int ce147_reglen_fps = 2; + + switch (state->fps) { + case FRAME_RATE_7: + ce147_regbuf_fps[0] = 0x07; + break; + + case FRAME_RATE_10: + ce147_regbuf_fps[0] = 0x0A; + break; + + case FRAME_RATE_15: + ce147_regbuf_fps[0] = 0x0F; + break; + + case FRAME_RATE_20: + ce147_regbuf_fps[0] = 0x14; + break; + + case FRAME_RATE_30: + ce147_regbuf_fps[0] = 0x1E; + break; + + case FRAME_RATE_60: + ce147_regbuf_fps[0] = 0x3C; + break; + + case FRAME_RATE_120: + ce147_regbuf_fps[0] = 0x78; + break; + + default: + return -EINVAL; + } + + err = ce147_i2c_write_multi(client, CMD_FPS, ce147_regbuf_fps, + ce147_reglen_fps); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "for set_frame_rate\n", __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_reflection" + "_status for set_frame_rate\n", __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_anti_banding(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_regbuf_anti_banding[1] = { 0x02 }; + unsigned int ce147_reglen_anti_banding = 1; + + switch (state->anti_banding) { + case ANTI_BANDING_OFF: + ce147_regbuf_anti_banding[0] = 0x00; + break; + + case ANTI_BANDING_AUTO: + ce147_regbuf_anti_banding[0] = 0x01; + break; + + case ANTI_BANDING_50HZ: + ce147_regbuf_anti_banding[0] = 0x02; + break; + + case ANTI_BANDING_60HZ: + default: + ce147_regbuf_anti_banding[0] = 0x03; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_ANTI_BANDING, + ce147_regbuf_anti_banding, ce147_reglen_anti_banding); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "anti_banding\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_preview_stop(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int ce147_reglen_preview = 1; + unsigned char ce147_regbuf_preview_stop[1] = { 0x00 }; + int err; + + /* pr_debug("%s: (%d)\n", __func__, state->runmode); */ + + if (CE147_RUNMODE_RUNNING == state->runmode) { + err = ce147_i2c_write_multi(client, CMD_PREVIEW, + ce147_regbuf_preview_stop, + ce147_reglen_preview); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "for preview_stop\n", __func__); + return -EIO; + } + + err = ce147_waitfordone_timeout(client, CMD_PREVIEW_STATUS, + 0x00, 3000, POLL_TIME_MS); + if (err < 0) { + dev_err(&client->dev, "%s: Wait for preview_stop " + "failed\n", __func__); + return err; + } + ce147_msg(&client->dev, "%s: preview_stop - wait time %d ms\n", + __func__, err); + + state->runmode = CE147_RUNMODE_READY; + } + return 0; +} + +static int ce147_set_dzoom(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct ce147_state *state = to_state(sd); + int err; + int count; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_get_dzoom_status[2] = { 0x00, 0x00 }; + unsigned int ce147_len_get_dzoom_status = 2; + + if (CE147_RUNMODE_RUNNING == state->runmode) { + err = ce147_i2c_write_multi(client, CMD_SET_DZOOM, + &ce147_buf_set_dzoom[ctrl->value], 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "for set_dzoom\n", __func__); + return -EIO; + } + + /* TODO: This code needs to use + * ce147_waitfordone_timeout() API + */ + for (count = 0; count < 300; count++) { + err = ce147_i2c_read_multi(client, CMD_GET_DZOOM_LEVEL, + NULL, 0, ce147_buf_get_dzoom_status, + ce147_len_get_dzoom_status); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read " + "for set_dzoom\n", __func__); + return -EIO; + } + if (ce147_buf_get_dzoom_status[1] == 0x00) + break; + } + } + + DZoom_State = ctrl->value; + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_preview_start(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + struct v4l2_control ctrl; + int ce147_reglen_preview = 1; + unsigned char ce147_regbuf_preview_start[1] = { 0x01 }; + + int count; + unsigned char ce147_buf_get_dzoom_status[2] = { 0x00, 0x00 }; + unsigned int ce147_len_get_dzoom_status = 2; + + if (!state->pix.width || !state->pix.height || !state->fps) + return -EINVAL; + + /* This is for 15 testmode */ + if (state->check_dataline) { + err = ce147_check_dataline(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Could not check data" + "line.\n", __func__); + return -EIO; + } + } else { /* Normal preview sequence */ + /* Stop it if it is already running */ + err = ce147_set_preview_stop(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Could not stop the " + "running preview.\n", __func__); + return -EIO; + } + + err = ce147_set_preview_size(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Could not set " + "preview size\n", __func__); + return -EIO; + } + + if (DZoom_State != 0) { + err = ce147_i2c_write_multi(client, CMD_SET_DZOOM, + &ce147_buf_set_dzoom[DZoom_State], 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "for set_dzoom in " + "preview_start\n", __func__); + return -EIO; + } + + for (count = 0; count < 300; count++) { + err = ce147_i2c_read_multi(client, + CMD_GET_DZOOM_LEVEL, NULL, 0, + ce147_buf_get_dzoom_status, + ce147_len_get_dzoom_status); + if (err < 0) { + dev_err(&client->dev, "%s: failed: " + "i2c_read for set_dzoom" + "in preview_start\n", + __func__); + return -EIO; + } + if (ce147_buf_get_dzoom_status[1] == 0x00) + break; + } + } + + err = ce147_set_anti_banding(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Could not set anti " + "banding\n", __func__); + return -EIO; + } + + err = ce147_set_frame_rate(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Could not set fps\n", + __func__); + return -EIO; + } + + if (state->runmode != CE147_RUNMODE_READY) { + /* iso */ + ctrl.value = state->iso; + err = ce147_set_iso(sd, &ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_" + "iso, err %d\n", __func__, err); + return -EIO; + } + + /* metering */ + ctrl.value = state->metering; + err = ce147_set_metering(sd, &ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_" + "metering, err %d\n", + __func__, err); + return -EIO; + } + + /* ev */ + ctrl.value = state->ev; + err = ce147_set_ev(sd, &ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_" + "ev, err %d\n", __func__, err); + return -EIO; + } + + /* effect */ + ctrl.value = state->effect; + err = ce147_set_effect(sd, &ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_" + "effect, err %d\n", + __func__, err); + return -EIO; + } + + /* wb */ + ctrl.value = state->wb; + err = ce147_set_white_balance(sd, &ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_" + "white_balance, err %d\n", + __func__, err); + return -EIO; + } + } + /* slow ae */ + ctrl.value = state->hd_slow_ae; + err = ce147_set_slow_ae(sd, &ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_slow_ae, " + "err %d\n", __func__, err); + return -EIO; + } + + /* RGB gamma */ + ctrl.value = state->hd_gamma; + err = ce147_set_gamma(sd, &ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_gamma, " + "err %d\n", __func__, err); + return -EIO; + } + + /* batch reflection */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for " + "set_frame_rate\n", __func__); + return -EIO; + } + + /* Release AWB unLock */ + err = ce147_set_awb_lock(sd, 0); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_awb_lock, " + "err %d\n", __func__, err); + return -EIO; + } + + /* Start preview */ + err = ce147_i2c_write_multi(client, CMD_PREVIEW, + ce147_regbuf_preview_start, + ce147_reglen_preview); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "preview_start\n", __func__); + return -EIO; + } + + err = ce147_waitfordone_timeout(client, CMD_PREVIEW_STATUS, + 0x08, 3000, POLL_TIME_MS); + if (err < 0) { + dev_err(&client->dev, "%s: Wait for preview_start " + "failed\n", __func__); + return err; + } + ce147_msg(&client->dev, "%s: preview_start - wait time %d ms\n", + __func__, err); + } + + state->runmode = CE147_RUNMODE_RUNNING; + + return 0; +} + +static int ce147_set_capture_size(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + int index = state->framesize_index; + /* Default 5 MP = { 0x08, 0x00, 0x01, 0x00 } */ + unsigned char ce147_regbuf_capture_size[4] = { 0x0B, 0x00, 0x01, 0x00 }; + unsigned int ce147_reglen_capture_size = 4; + + switch (index) { + case CE147_CAPTURE_VGA: /* 640x480 */ + ce147_regbuf_capture_size[0] = 0x04; + break; + case CE147_CAPTURE_WVGA: /* 800x480 */ + ce147_regbuf_capture_size[0] = 0x13; + break; + case CE147_CAPTURE_W1MP: /* 1600x960 */ + ce147_regbuf_capture_size[0] = 0x0E; + break; + case CE147_CAPTURE_2MP: /* 1600x1200 */ + ce147_regbuf_capture_size[0] = 0x08; + break; + case CE147_CAPTURE_W2MP: /* 2048x1232 */ + ce147_regbuf_capture_size[0] = 0x0F; + break; + case CE147_CAPTURE_3MP: /* 2048x1536 */ + ce147_regbuf_capture_size[0] = 0x09; + break; + case CE147_CAPTURE_W4MP: /* 2560x1536 */ + ce147_regbuf_capture_size[0] = 0x15; + break; + case CE147_CAPTURE_5MP: /* 2560x1920 */ + ce147_regbuf_capture_size[0] = 0x0B; + break; + default: + /* The framesize index was not set properly. + * Check s_fmt call - it must be for video mode. */ + return -EINVAL; + } + + /* Set capture image size */ + err = ce147_i2c_write_multi(client, CMD_CAPTURE_SIZE, + ce147_regbuf_capture_size, ce147_reglen_capture_size); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "for capture_resolution\n", __func__); + return -EIO; + } + + /* This is for postview */ + if (ce147_regbuf_capture_size[0] < 0x0C) { + state->preview_size = CE147_PREVIEW_VGA; + /* pr_debug("%s: preview_size is VGA (%d)\n", + __func__, state->preview_size); */ + } else { + state->preview_size = CE147_PREVIEW_WVGA; + /* pr_debug("%s: preview_size is WVGA (%d)\n", + __func__, state->preview_size); */ + } + + /* pr_debug("%s: 0x%02x\n", __func__, index); */ + + return 0; +} + +static int ce147_set_ae_awb(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_ae_awb[1] = { 0x00 }; + + switch (ctrl->value) { + case AE_LOCK_AWB_UNLOCK: + ce147_buf_set_ae_awb[0] = 0x01; + break; + + case AE_UNLOCK_AWB_LOCK: + ce147_buf_set_ae_awb[0] = 0x10; + break; + + case AE_LOCK_AWB_LOCK: + ce147_buf_set_ae_awb[0] = 0x11; + break; + + case AE_UNLOCK_AWB_UNLOCK: + default: + ce147_buf_set_ae_awb[0] = 0x00; + break; + } + err = ce147_i2c_write_multi(client, CMD_AE_WB_LOCK, + ce147_buf_set_ae_awb, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_effect\n", + __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +/** + * lock: 1 to lock, 0 to unlock + */ +static int ce147_set_awb_lock(struct v4l2_subdev *sd, int lock) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_regbuf_awb_lock[1] = { 0x11 }; + unsigned int ce147_reglen_awb_lock = 1; + + if (lock) + ce147_regbuf_awb_lock[0] = 0x11; + else + ce147_regbuf_awb_lock[0] = 0x00; + + err = ce147_i2c_write_multi(client, CMD_AE_WB_LOCK, + ce147_regbuf_awb_lock, ce147_reglen_awb_lock); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for awb_lock\n", + __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_capture_cmd(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_regbuf_buffering_capture[1] = { 0x00 }; + unsigned int ce147_reglen_buffering_capture = 1; + + err = ce147_i2c_write_multi(client, CMD_BUFFERING_CAPTURE, + ce147_regbuf_buffering_capture, + ce147_reglen_buffering_capture); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "for buffering_capture\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} +static int ce147_set_exif_ctrl(struct v4l2_subdev *sd , int onoff) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_regbuf_exif_ctrl[2] = { 0x10, 0x00 }; + unsigned int ce147_reglen_exif_ctrl = 2; + + if ((onoff == 0) && (state->thumb_null == 0)) + ce147_regbuf_exif_ctrl[1] = 0x00; + else if ((onoff == 1) && (state->thumb_null == 0)) + ce147_regbuf_exif_ctrl[1] = 0x01; + else if ((onoff == 0) && (state->thumb_null == 0)) + ce147_regbuf_exif_ctrl[1] = 0x02; + else if ((onoff == 0) && (state->thumb_null == 1)) + ce147_regbuf_exif_ctrl[1] = 0x03; + else if ((onoff == 1) && (state->thumb_null == 1)) + ce147_regbuf_exif_ctrl[1] = 0x04; + + err = ce147_i2c_write_multi(client, CMD_SET_EXIF_CTRL, + ce147_regbuf_exif_ctrl, ce147_reglen_exif_ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write " + "for ce147_reglen_exif_ctrl\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_capture_exif(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + struct rtc_time gps_timestamp; + + unsigned char ce147_regbuf_exif[7] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned int ce147_reglen_exif = 7; + + unsigned char ce147_regbuf_timestamp[7] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned int ce147_reglen_timestamp = 7; + + unsigned char ce147_regbuf_rot[1] = { 0x01 }; + unsigned int ce147_reglen_rot = 1; + + unsigned char ce147_model_name[130] = { 0x00, }; + unsigned int ce147_reglen_model = 130; + + unsigned char ce147_gps_processing[130] = { 0x00, }; + unsigned int ce147_reglen_gps_processing = 130; +#if !defined(CONFIG_ARIES_NTT) + unsigned char ce147_str_model[9] = "GT-I9000\0"; +#elif defined(CONFIG_SAMSUNG_FASCINATE) + unsigned char ce147_str_model[9] = "SCH-I500\0"; +#else /* Modify NTTS1 */ + unsigned char ce147_str_model[7] = "SC-02B\0"; +#endif +#if 0 + struct timeval curr_time; + struct rtc_time time; +#endif + ce147_model_name[0] = 0x06; + ce147_model_name[1] = 0x09; + + memcpy(ce147_model_name + 2, ce147_str_model, sizeof(ce147_str_model)); + + ce147_gps_processing[0] = 0x10; + ce147_gps_processing[1] = 0x32; + + memcpy(ce147_gps_processing + 2, state->gpsInfo.gps_processingmethod, + sizeof(state->gpsInfo.gps_processingmethod)); + +#if 0 + do_gettimeofday(&curr_time); + rtc_time_to_tm(curr_time.tv_sec, &time); + + time.tm_year += 1900; + time.tm_mon += 1; + + ce147_regbuf_exif[0] = (time.tm_year & 0x00FF); + ce147_regbuf_exif[1] = (time.tm_year & 0xFF00) >> 8; + ce147_regbuf_exif[2] = time.tm_mon; + ce147_regbuf_exif[3] = time.tm_mday; + ce147_regbuf_exif[4] = time.tm_hour; + ce147_regbuf_exif[5] = time.tm_min; + ce147_regbuf_exif[6] = time.tm_sec; +#else + state->exifTimeInfo->tm_year += 1900; + state->exifTimeInfo->tm_mon += 1; + ce147_regbuf_exif[0] = (state->exifTimeInfo->tm_year & 0x00FF); + ce147_regbuf_exif[1] = (state->exifTimeInfo->tm_year & 0xFF00) >> 8; + ce147_regbuf_exif[2] = state->exifTimeInfo->tm_mon; + ce147_regbuf_exif[3] = state->exifTimeInfo->tm_mday; + ce147_regbuf_exif[4] = state->exifTimeInfo->tm_hour; + ce147_regbuf_exif[5] = state->exifTimeInfo->tm_min; + ce147_regbuf_exif[6] = state->exifTimeInfo->tm_sec; +#endif + + rtc_time_to_tm(state->gpsInfo.gps_timeStamp, &gps_timestamp); + gps_timestamp.tm_year += 1900; + gps_timestamp.tm_mon += 1; + + pr_debug("====!! Exif Time YEAR: %d, MONTH: %d, " + "DAY: %d, HOUR: %d, MIN: %d, SEC: %d\n", + gps_timestamp.tm_year, gps_timestamp.tm_mon, + gps_timestamp.tm_mday, gps_timestamp.tm_hour, + gps_timestamp.tm_min, gps_timestamp.tm_sec); + + ce147_regbuf_timestamp[0] = (gps_timestamp.tm_year & 0x00FF); + ce147_regbuf_timestamp[1] = (gps_timestamp.tm_year & 0xFF00) >> 8; + ce147_regbuf_timestamp[2] = gps_timestamp.tm_mon; + ce147_regbuf_timestamp[3] = gps_timestamp.tm_mday; + ce147_regbuf_timestamp[4] = gps_timestamp.tm_hour; + ce147_regbuf_timestamp[5] = gps_timestamp.tm_min; + ce147_regbuf_timestamp[6] = gps_timestamp.tm_sec; + + + pr_debug("Exif Time YEAR: %ld, MONTH: %d, DAY: %d, " + "HOUR: %d, MIN: %d, SEC: %d\n", + state->exifTimeInfo->tm_year, + state->exifTimeInfo->tm_mon, + state->exifTimeInfo->tm_mday, + state->exifTimeInfo->tm_hour, + state->exifTimeInfo->tm_min, + state->exifTimeInfo->tm_sec); + + ce147_regbuf_rot[0] = state->exif_orientation_info; + + err = ce147_i2c_write_multi(client, CMD_INFO_MODEL, ce147_model_name, + ce147_reglen_model); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for exif model " + "name\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_INFO_EXIF, ce147_regbuf_exif, + ce147_reglen_exif); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for exif\n", + __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_INFO_ROT, ce147_regbuf_rot, + ce147_reglen_rot); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for exif\n", + __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_INFO_LONGITUDE_LATITUDE, + state->gpsInfo.ce147_gps_buf, + sizeof(state->gpsInfo.ce147_gps_buf)); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for gps " + "longitude latitude\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_INFO_ALTITUDE, + state->gpsInfo.ce147_altitude_buf, + sizeof(state->gpsInfo.ce147_altitude_buf)); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for gps " + "altitude\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_GPS_TIMESTAMP, + ce147_regbuf_timestamp, ce147_reglen_timestamp); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for gps " + "timestamp\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_INFO_MODEL, + ce147_gps_processing, ce147_reglen_gps_processing); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for gps method\n", + __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_jpeg_quality(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + +#if 0 + unsigned char ce147_regbuf_jpeg_comp_level[7] = { + 0x00, 0xF4, 0x01, 0x90, 0x01, 0x05, 0x01 + }; + unsigned int ce147_reglen_jpeg_comp_level = 7; + + unsigned int comp_ratio = 1500; + + int err; + + if (state->jpeg.quality < 0) + state->jpeg.quality = 0; + if (state->jpeg.quality > 100) + state->jpeg.quality = 100; + + comp_ratio -= (100 - state->jpeg.quality) * 10; + ce147_regbuf_jpeg_comp_level[1] = comp_ratio & 0xFF; + ce147_regbuf_jpeg_comp_level[2] = (comp_ratio & 0xFF00) >> 8; + + ce147_msg(&client->dev, "Quality = %d, Max value = %d\n", + state->jpeg.quality, comp_ratio); + + /* 10% range for final JPEG image size */ + comp_ratio = (comp_ratio * 9) / 10; + ce147_regbuf_jpeg_comp_level[3] = comp_ratio & 0xFF; + ce147_regbuf_jpeg_comp_level[4] = (comp_ratio & 0xFF00) >> 8; + + ce147_msg(&client->dev, "Quality = %d, Min Comp Ratio = %d\n", + state->jpeg.quality, comp_ratio); +#endif + + unsigned char ce147_regbuf_jpeg_comp_level[7] = { + 0x00, 0xA4, 0x06, 0x78, 0x05, 0x05, 0x01 + }; + unsigned int ce147_reglen_jpeg_comp_level = 7; + unsigned int quality = state->jpeg.quality; + unsigned int compressionRatio = 0; + unsigned int minimumCompressionRatio = 0; + int err; + + if (quality >= 91 && quality <= 100) { /* 91 ~ 100 */ + compressionRatio = 17; /* 17% */ + } else if (quality >= 81 && quality <= 90) { /* 81 ~ 90 */ + compressionRatio = 16; /* 16% */ + } else if (quality >= 71 && quality <= 80) { /* 71 ~ 80 */ + compressionRatio = 15; /* 15% */ + } else if (quality >= 61 && quality <= 70) { /* 61 ~ 70 */ + compressionRatio = 14; /* 14% */ + } else if (quality >= 51 && quality <= 60) { /* 51 ~ 60 */ + compressionRatio = 13; /* 13% */ + } else if (quality >= 41 && quality <= 50) { /* 41 ~ 50 */ + compressionRatio = 12; /* 12% */ + } else if (quality >= 31 && quality <= 40) { /* 31 ~ 40 */ + compressionRatio = 11; /* 11% */ + } else if (quality >= 21 && quality <= 30) { /* 21 ~ 30 */ + compressionRatio = 10; /* 10% */ + } else if (quality >= 11 && quality <= 20) { /* 11 ~ 20 */ + compressionRatio = 9; /* 9% */ + } else if (quality >= 1 && quality <= 10) { /* 1 ~ 10 */ + compressionRatio = 8; /* 8% */ + } else { + dev_err(&client->dev, "%s: Invalid Quality(%d)\n", + __func__, quality); + return -1; + } + + /* ex) if compression ratio is 17%, minimum compression ratio is 14%*/ + minimumCompressionRatio = compressionRatio - 3; + ce147_regbuf_jpeg_comp_level[1] = (compressionRatio * 100) & 0xFF; + ce147_regbuf_jpeg_comp_level[2] = ((compressionRatio * 100) & 0xFF00) + >> 8; + ce147_regbuf_jpeg_comp_level[3] = (minimumCompressionRatio * 100) + & 0xFF; + ce147_regbuf_jpeg_comp_level[4] = ((minimumCompressionRatio * 100) + & 0xFF00) >> 8; + + err = ce147_i2c_write_multi(client, CMD_JPEG_CONFIG, + ce147_regbuf_jpeg_comp_level, + ce147_reglen_jpeg_comp_level); + + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "jpeg_comp_level\n", __func__); + return -EIO; + } + + return 0; +} + +static int ce147_set_jpeg_config(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int preview_size = state->preview_size; + + unsigned char ce147_regbuf_set_lump[2] = { 0x00, 0x04}; + unsigned int ce147_reglen_set_lump = 2; + + /* unsigned char ce147_regbuf_set_lump2[1] = {0x00}; + unsigned int ce147_reglen_set_lump2 = 1; */ + + err = ce147_set_jpeg_quality(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_jpeg_quality\n", + __func__); + return -EIO; + } + + if (preview_size != CE147_PREVIEW_VGA) { + /* pr_debug("[5B] ce147_set_jpeg_config: preview_size is WVGA " + "(%d)\n", preview_size); */ + ce147_regbuf_set_lump[1] = 0x13; + } + + /* if (!state->thumb_null) */ + err = ce147_i2c_write_multi(client, CMD_JPEG_BUFFERING, + ce147_regbuf_set_lump, ce147_reglen_set_lump); + /* else if (state->thumb_null) */ + /* err = ce147_i2c_write_multi(client, CMD_JPEG_BUFFERING2, + ce147_regbuf_set_lump2, ce147_reglen_set_lump2); */ + + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_lump\n", + __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_get_snapshot_data(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char cmd_buf_framesize[1] = { 0x00 }; + unsigned int cmd_len_framesize = 1; + + unsigned char cmd_buf_setdata[2] = { 0x02, 0x00 }; + unsigned int cmd_len_setdata = 2; + + unsigned char jpeg_status[3] = { 0x00, 0x00, 0x00 }; + unsigned char jpeg_status_len = 3; + + unsigned char jpeg_framesize[4] = { 0x00, 0x00, 0x00, 0x00 }; + unsigned int jpeg_framesize_len = 4; + + if (state->jpeg.enable) { + /* Get main JPEG size */ + cmd_buf_framesize[0] = 0x00; + err = ce147_i2c_read_multi(client, CMD_JPEG_SIZE, + cmd_buf_framesize, cmd_len_framesize, + jpeg_framesize, jpeg_framesize_len); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read for " + "jpeg_framesize\n", __func__); + return -EIO; + } + state->jpeg.main_size = jpeg_framesize[1] + | (jpeg_framesize[2] << 8) + | (jpeg_framesize[3] << 16); + + ce147_info(&client->dev, "%s: JPEG main filesize = %d bytes\n", + __func__, state->jpeg.main_size); + + /* Get Thumbnail size */ + if (!state->thumb_null) { + cmd_buf_framesize[0] = 0x01; + err = ce147_i2c_read_multi(client, CMD_JPEG_SIZE, + cmd_buf_framesize, cmd_len_framesize, + jpeg_framesize, jpeg_framesize_len); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read " + "for jpeg_framesize\n", + __func__); + return -EIO; + } + state->jpeg.thumb_size = jpeg_framesize[1] + | (jpeg_framesize[2] << 8) + | (jpeg_framesize[3] << 16); + } else + state->jpeg.thumb_size = 0; + + ce147_msg(&client->dev, "%s: JPEG thumb filesize = %d bytes\n", + __func__, state->jpeg.thumb_size); + + state->jpeg.main_offset = 0; + state->jpeg.thumb_offset = 0x271000; + state->jpeg.postview_offset = 0x280A00; + } + + if (state->jpeg.enable) + cmd_buf_setdata[0] = 0x02; + else + cmd_buf_setdata[0] = 0x01; + /* Set Data out */ + err = ce147_i2c_read_multi(client, CMD_SET_DATA, + cmd_buf_setdata, cmd_len_setdata, + jpeg_status, jpeg_status_len); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read for set_data\n", + __func__); + return -EIO; + } + ce147_msg(&client->dev, "%s:JPEG framesize (after set_data_out) = " + "0x%02x.%02x.%02x\n", __func__, + jpeg_status[2], jpeg_status[1], jpeg_status[0]); + + /* 0x66 */ + err = ce147_i2c_read_multi(client, CMD_DATA_OUT_REQ, NULL, 0, + jpeg_status, jpeg_status_len); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read for " + "set_data_request\n", __func__); + return -EIO; + } + ce147_msg(&client->dev, "%s:JPEG framesize (after set_data_request) " + "= 0x%02x.%02x.%02x\n", __func__, + jpeg_status[2], jpeg_status[1], jpeg_status[0]); + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_capture_config(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* + * 1. Set image size + */ + err = ce147_set_capture_size(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "capture_resolution\n", __func__); + return -EIO; + } + + /* + * Set DZoom + */ + if (DZoom_State != 0) { + ctrl->value = DZoom_State; + err = ce147_set_dzoom(sd, ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Could not set Zoom " + "in Capture_start\n", __func__); + return -EIO; + } + } + +#ifdef CONFIG_SAMSUNG_FASCINATE + /* + * Set Flash + */ + err = ce147_set_awb_lock(sd, 0); + if(err < 0){ + dev_err(&client->dev, "%s: failed: ce147_set_awb_lock, err %d\n", __func__, err); + return -EIO; + } + ce147_set_preflash(sd, 1); +#endif + + /* + * Set AWB Lock + */ + err = ce147_set_awb_lock(sd, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_awb_lock, " + "err %d\n", __func__, err); + return -EIO; + } + /* + * 2. Set Capture Command + */ + err = ce147_set_capture_cmd(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: set_capture_cmd failed\n", + __func__); + return err; + } + + return 0; +} + +static int ce147_set_capture_start(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + /* + * Right after ce147_set_capture_config, + * 3. Wait for capture to complete for ce147_set_capture_cmd() + * in ce147_set_capture_config() + */ + err = ce147_waitfordone_timeout(client, 0x6C, 0x00, 3000, POLL_TIME_MS); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Wait for " + "buffering_capture\n", __func__); + return err; + } + ce147_msg(&client->dev, "%s: buffering_capture - wait time %d ms\n", + __func__, err); + + + err = ce147_set_exif_ctrl(sd, state->exif_ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: set_capture_cmd failed\n", + __func__); + return err; + } + + + if (state->jpeg.enable) { + /* + * 4. Set EXIF information + */ + err = ce147_set_capture_exif(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "exif\n", __func__); + return -EIO; + } + + /* + * 6. Set JPEG Encoding parameters + */ + err = ce147_set_jpeg_config(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Setting JPEG encoding " + "parameters\n", __func__); + return err; + } + /* + * 7. Wait for encoding to complete + */ + err = ce147_waitfordone_timeout(client, 0x6C, 0x00, 3000, + POLL_TIME_MS); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Wait for " + "jpeg_encoding\n", __func__); + return err; + } + ce147_msg(&client->dev, "%s: jpeg_encoding - wait time %d ms\n", + __func__, err); + } + /* + * 8. Get JPEG Main Data + */ + err = ce147_get_snapshot_data(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: get_snapshot_data\n", + __func__); + return err; + } + /* + * 9. Wait for done + */ + err = ce147_waitfordone_timeout(client, 0x61, 0x00, 3000, POLL_TIME_MS); + if (err < 0) { + dev_err(&client->dev, "%s: failed: Wait for data_transfer\n", + __func__); + return err; + } + ce147_msg(&client->dev, "%s: data_transfer - wait time %d ms\n", + __func__, err); + + return 0; +} + +static int ce147_get_focus_mode(struct i2c_client *client, unsigned char cmd, + unsigned char *value) +{ + int err; + int count; + + unsigned char ce147_buf_get_af_status[1] = { 0x00 }; + + /* set focus mode: AF or MACRO */ + err = ce147_i2c_write_multi(client, cmd, value, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "get_focus_mode\n", __func__); + return -EIO; + } + /* check whether af data is valid or not */ + for (count = 0; count < 600; count++) { + msleep(10); + ce147_buf_get_af_status[0] = 0xFF; + err = ce147_i2c_read_multi(client, CMD_CHECK_AUTO_FOCUS_SEARCH, + NULL, 0, ce147_buf_get_af_status, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read for " + "get_focus_mode\n", __func__); + return -EIO; + } + if ((ce147_buf_get_af_status[0] & 0x01) == 0x00) + break; + } + + if ((ce147_buf_get_af_status[0] & 0x01) != 0x00) + return -EBUSY; + else + return ce147_buf_get_af_status[0] & 0x01; +} + +static int ce147_set_af_softlanding(struct v4l2_subdev *sd) +{ + int err; + int count; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_buf_get_af_status[1] = { 0x00 }; + unsigned char ce147_buf_set_af_land[1] = { 0x08 }; + unsigned int ce147_len_set_af_land = 1; + + if (state->runmode > CE147_RUNMODE_IDLE) { + /* make lens landing mode */ + err = ce147_i2c_write_multi(client, CMD_SET_AUTO_FOCUS_MODE, + ce147_buf_set_af_land, ce147_len_set_af_land); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "auto_focus\n", __func__); + return -EIO; + } + /* check whether af data is valid or not */ + for (count = 0; count < 600; count++) { + msleep(10); + ce147_buf_get_af_status[0] = 0xFF; + err = ce147_i2c_read_multi(client, + CMD_CHECK_AUTO_FOCUS_SEARCH, NULL, 0, + ce147_buf_get_af_status, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read " + "for get_focus_mode\n", + __func__); + return -EIO; + } + if ((ce147_buf_get_af_status[0]) == 0x08) + break; + } + } + return 0; +} + +static int ce147_set_flash(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_flash[2] = { 0x03, 0x00 }; + unsigned int ce147_len_set_flash = 2; + unsigned char ce147_buf_set_flash_manual[2] = { 0x00, 0x00 }; + unsigned int ce147_len_set_flash_manual = 2; + +#ifdef CONFIG_SAMSUNG_FASCINATE + unsigned char ce147_buf_set_flash_power_control[4] = {0x03,0x01,0x1D,0x0c}; + unsigned int ce147_len_set_flash_power_control = 4; + + if(ctrl->value != FLASH_MODE_TORCH_ON && ctrl->value != FLASH_MODE_TORCH_OFF) + Flash_Mode = ctrl->value; +#endif + + switch (ctrl->value) { + case FLASH_MODE_OFF: + ce147_buf_set_flash[1] = 0x00; + break; + + case FLASH_MODE_AUTO: + ce147_buf_set_flash[1] = 0x02; + break; + + case FLASH_MODE_ON: + ce147_buf_set_flash[1] = 0x01; + break; + +#ifdef CONFIG_SAMSUNG_FASCINATE + case FLASH_MODE_TORCH_ON: + ce147_buf_set_flash_manual[1] = 0x01; + break; + + case FLASH_MODE_TORCH_OFF: + ce147_buf_set_flash_manual[1] = 0x00; + break; + + case FLASH_MODE_BACKLIGHT_ON: + ce147_buf_set_flash_power_control[1] = 0x00; + ce147_buf_set_flash[1] = 0x01; + break; +#else + case FLASH_MODE_TORCH: + ce147_buf_set_flash_manual[1] = 0x01; + break; +#endif + + default: + ce147_buf_set_flash[1] = 0x00; + break; + } + +#ifdef CONFIG_SAMSUNG_FASCINATE + // set flash power + err = ce147_i2c_write_multi(client, CMD_SET_FLASH_POWER, ce147_buf_set_flash_power_control, ce147_len_set_flash_power_control); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_flash_power\n", __func__); + return -EIO; + } + //need to modify flash off for torch mode + if(ctrl->value == FLASH_MODE_TORCH_ON ||ctrl->value == FLASH_MODE_TORCH_OFF) { + err = ce147_i2c_write_multi(client, CMD_SET_FLASH_MANUAL, ce147_buf_set_flash_manual, ce147_len_set_flash_manual); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_flash\n", __func__); + return -EIO; + } + ce147_msg(&client->dev, "%s: done, camcorder_flash: 0x%02x\n", __func__, ce147_buf_set_flash_manual[1]); + } + else { + err = ce147_i2c_write_multi(client, CMD_SET_FLASH, ce147_buf_set_flash, ce147_len_set_flash); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_flash\n", __func__); + return -EIO; + } + ce147_msg(&client->dev, "%s: done, flash: 0x%02x\n", __func__, ce147_buf_set_flash[1]); + } +#else + if (ctrl->value == FLASH_MODE_OFF) { + err = ce147_i2c_write_multi(client, CMD_SET_FLASH_MANUAL, + ce147_buf_set_flash_manual, + ce147_len_set_flash_manual); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "set_flash\n", __func__); + return -EIO; + } + } + + err = ce147_i2c_write_multi(client, CMD_SET_FLASH, + ce147_buf_set_flash, ce147_len_set_flash); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_flash\n", + __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done, flash: 0x%02x\n", + __func__, ce147_buf_set_flash[1]); +#endif + + return 0; +} + +#ifdef CONFIG_SAMSUNG_FASCINATE +static int ce147_set_preflash(struct v4l2_subdev *sd, int flash_mode) //SecFeature.Camera aswoogi +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_preflash[2] = { 0x01, 0x00 }; + unsigned int ce147_len_set_preflash = 2; + unsigned char ce147_buf_set_preflash_manual[2] = { 0x00, 0x00 }; + unsigned int ce147_len_set_preflash_manual = 2; + unsigned char ce147_buf_set_flash[2] = { 0x03, 0x00 }; + unsigned int ce147_len_set_flash = 2; + unsigned char ce147_buf_set_flash_manual[2] = { 0x00, 0x00 }; + unsigned int ce147_len_set_flash_manual = 2; + unsigned char ce147_buf_set_flash_off[2] = { 0x03, 0x00 }; + unsigned int ce147_len_set_flash_off = 2; + unsigned char ce147_buf_set_preflash_off[2] = { 0x01, 0x00 }; + unsigned int ce147_len_set_preflash_off = 2; + unsigned char ce147_buf_set_preflash_init[2] = { 0x02, 0x02 }; + unsigned int ce147_len_set_preflash_init = 2; + unsigned char ce147_buf_set_preflash_init2[2] = { 0x02, 0x00 }; + unsigned int ce147_len_set_preflash_init2 = 2; + + + ce147_msg(&client->dev, "%s, %d\n", __func__, flash_mode); + + switch(Flash_Mode) { + case FLASH_MODE_OFF: + ce147_buf_set_preflash[1] = 0x00; + ce147_buf_set_flash[1] = 0x00; + break; + + case FLASH_MODE_AUTO: + ce147_buf_set_preflash[1] = 0x02; + ce147_buf_set_flash[1] = 0x02; + err = ce147_i2c_write_multi(client, 0x07, ce147_buf_set_preflash_init2, ce147_len_set_preflash_init2); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_preflash\n", __func__); + return -EIO; + } + break; + + case FLASH_MODE_ON: + ce147_buf_set_preflash[1] = 0x01; + ce147_buf_set_flash[1] = 0x01; + err = ce147_i2c_write_multi(client, 0x07, ce147_buf_set_preflash_init2, ce147_len_set_preflash_init2); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_preflash\n", __func__); + return -EIO; + } + break; + + case FLASH_MODE_BACKLIGHT_ON: + ce147_buf_set_preflash[1] = 0x01; + ce147_buf_set_flash[1] = 0x01; + err = ce147_i2c_write_multi(client, 0x07, ce147_buf_set_preflash_init, ce147_len_set_preflash_init); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_preflash\n", __func__); + return -EIO; + } + break; + default: + ce147_buf_set_preflash[1] = 0x00; + ce147_buf_set_flash[1] = 0x00; + break; + } + + //need to modify flash off for torch mode + if(flash_mode == 0) { + err = ce147_i2c_write_multi(client, CMD_SET_FLASH, ce147_buf_set_preflash, ce147_len_set_preflash); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_preflash\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_SET_FLASH, ce147_buf_set_flash_off, ce147_len_set_flash_off); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_flash_off\n", __func__); + return -EIO; + } + + dev_err(&client->dev, "%s: done, preflash: 0x%02x\n", __func__, ce147_buf_set_preflash[1]); + } + else { + err = ce147_i2c_write_multi(client, CMD_SET_FLASH, ce147_buf_set_flash, ce147_len_set_flash); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_flash\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_SET_FLASH, ce147_buf_set_preflash_off, ce147_len_set_preflash_off); + if(err < 0){ + dev_err(&client->dev, "%s: failed: i2c_write for set_preflash_off\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done, flash: 0x%02x\n", __func__, ce147_buf_set_flash[1]); + } + + return 0; +} +#endif + +static int ce147_set_effect(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_effect[2] = { 0x05, 0x00 }; + unsigned int ce147_len_set_effect = 2; + + switch (ctrl->value) { + case IMAGE_EFFECT_NONE: + ce147_buf_set_effect[1] = 0x00; + break; + + case IMAGE_EFFECT_BNW: + ce147_buf_set_effect[1] = 0x01; + break; + + case IMAGE_EFFECT_SEPIA: + ce147_buf_set_effect[1] = 0x03; + break; + + case IMAGE_EFFECT_AQUA: + ce147_buf_set_effect[1] = 0x0D; + break; + + case IMAGE_EFFECT_ANTIQUE: + ce147_buf_set_effect[1] = 0x06; + break; + + case IMAGE_EFFECT_NEGATIVE: + ce147_buf_set_effect[1] = 0x05; + break; + + case IMAGE_EFFECT_SHARPEN: + ce147_buf_set_effect[1] = 0x04; + break; + + default: + ce147_buf_set_effect[1] = 0x00; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT, + ce147_buf_set_effect, ce147_len_set_effect); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_effect\n", + __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for set_effect\n", __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_saturation(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_saturation[2] = { 0x06, 0x00 }; + unsigned int ce147_len_set_saturation = 2; + + switch (ctrl->value) { + case SATURATION_MINUS_2: + ce147_buf_set_saturation[1] = 0x01; + break; + + case SATURATION_MINUS_1: + ce147_buf_set_saturation[1] = 0x02; + break; + + case SATURATION_DEFAULT: + ce147_buf_set_saturation[1] = 0x03; + break; + + case SATURATION_PLUS_1: + ce147_buf_set_saturation[1] = 0x04; + break; + + case SATURATION_PLUS_2: + ce147_buf_set_saturation[1] = 0x05; + break; + + default: + ce147_buf_set_saturation[1] = 0x03; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT, + ce147_buf_set_saturation, ce147_len_set_saturation); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "set_saturation\n", __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for set_saturation\n", + __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done, saturation: 0x%02x\n", + __func__, ce147_buf_set_saturation[1]); + + return 0; +} + +static int ce147_set_contrast(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_contrast[2] = { 0x07, 0x00 }; + unsigned int ce147_len_set_contrast = 2; + + switch (ctrl->value) { + case CONTRAST_MINUS_2: + ce147_buf_set_contrast[1] = 0x01; + break; + + case CONTRAST_MINUS_1: + ce147_buf_set_contrast[1] = 0x02; + break; + + case CONTRAST_DEFAULT: + ce147_buf_set_contrast[1] = 0x03; + break; + + case CONTRAST_PLUS_1: + ce147_buf_set_contrast[1] = 0x04; + break; + + case CONTRAST_PLUS_2: + ce147_buf_set_contrast[1] = 0x05; + break; + + default: + ce147_buf_set_contrast[1] = 0x03; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT, + ce147_buf_set_contrast, ce147_len_set_contrast); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "set_contrast\n", __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for set_contrast\n", + __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done, contrast: 0x%02x\n", + __func__, ce147_buf_set_contrast[1]); + + return 0; +} + +static int ce147_set_sharpness(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_saturation[2] = { 0x02, 0x00 }; + unsigned int ce147_len_set_saturation = 2; + + switch (ctrl->value) { + case SHARPNESS_MINUS_2: + ce147_buf_set_saturation[1] = 0x01; + break; + + case SHARPNESS_MINUS_1: + ce147_buf_set_saturation[1] = 0x02; + break; + + case SHARPNESS_DEFAULT: + ce147_buf_set_saturation[1] = 0x03; + break; + + case SHARPNESS_PLUS_1: + ce147_buf_set_saturation[1] = 0x04; + break; + + case SHARPNESS_PLUS_2: + ce147_buf_set_saturation[1] = 0x05; + break; + + default: + ce147_buf_set_saturation[1] = 0x03; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT, + ce147_buf_set_saturation, ce147_len_set_saturation); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "set_saturation\n", __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for set_saturation\n", + __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done, sharpness: 0x%02x\n", + __func__, ce147_buf_set_saturation[1]); + + return 0; +} + +static int ce147_set_wdr(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_wdr[1] = { 0x00 }; + unsigned int ce147_len_set_wdr = 1; + + switch (ctrl->value) { + case WDR_ON: + ce147_buf_set_wdr[0] = 0x01; + break; + + case WDR_OFF: + default: + ce147_buf_set_wdr[0] = 0x00; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_WDR, + ce147_buf_set_wdr, ce147_len_set_wdr); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_wdr\n", + __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done, wdr: 0x%02x\n", + __func__, ce147_buf_set_wdr[0]); + + return 0; +} + +static int ce147_set_anti_shake(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_anti_shake[1] = { 0x00 }; + unsigned int ce147_len_set_anti_shake = 1; + + switch (ctrl->value) { + case ANTI_SHAKE_STILL_ON: + ce147_buf_set_anti_shake[0] = 0x01; + break; + + case ANTI_SHAKE_MOVIE_ON: + ce147_buf_set_anti_shake[0] = 0x10; + break; + + case ANTI_SHAKE_OFF: + default: + ce147_buf_set_anti_shake[0] = 0x00; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_ANTI_SHAKE, + ce147_buf_set_anti_shake, ce147_len_set_anti_shake); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for anti_shake\n", + __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done, AHS: 0x%02x\n", + __func__, ce147_buf_set_anti_shake[0]); + + return 0; +} + +static int ce147_set_continous_af(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_caf[1] = { 0x02 }; + unsigned char ce147_buf_start_af_search[1] = { 0x00 }; + unsigned int ce147_len_start_af_search = 1; +#if 0 + unsigned char ce147_buf_set_af[1] = { 0x00 }; +#endif + unsigned char ce147_buf_stop_lens_movement[1] = { 0x00 }; + + /* need to set face_detection with noline */ + + if (ctrl->value) { + err = ce147_get_focus_mode(client, CMD_SET_AUTO_FOCUS_MODE, + ce147_buf_set_caf); + if (err < 0) { + dev_err(&client->dev, "%s: failed: " + "start_continous_af\n", __func__); + return -EIO; + } + + /* start af search */ + err = ce147_i2c_write_multi(client, CMD_START_AUTO_FOCUS_SEARCH, + ce147_buf_start_af_search, + ce147_len_start_af_search); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "start_continous_af\n", __func__); + return -EIO; + } + } else { + err = ce147_get_focus_mode(client, CMD_STOP_LENS_MOVEMENT, + ce147_buf_stop_lens_movement); + if (err < 0) { + dev_err(&client->dev, "%s: failed: stop_continous_af\n", + __func__); + return -EIO; + } +#if 0 + err = ce147_get_focus_mode(client, CMD_SET_AUTO_FOCUS_MODE, + ce147_buf_set_af); + if (err < 0) { + dev_err(&client->dev, "%s: failed: stop_continous_af\n", + __func__); + return -EIO; + } +#endif + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_object_tracking(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + int count; + unsigned short x; + unsigned short y; + + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_object_tracking[7] = { 0x00, }; + unsigned int ce147_len_set_object_tracking = 7; + unsigned char ce147_buf_check_object_tracking[9] = { 0x00, }; + unsigned int ce147_len_check_object_tracking = 9; + unsigned char ce147_buf_stop_lens[1] = { 0x00 }; + + /* get x,y touch position */ + x = state->position.x; + y = state->position.y; + + if (OT_START) { + ce147_buf_set_object_tracking[3] = (x & 0x00FF); + ce147_buf_set_object_tracking[4] = ((x & 0xFF00) >> 8); + ce147_buf_set_object_tracking[5] = (y & 0x00FF); + ce147_buf_set_object_tracking[6] = ((y & 0xFF00) >> 8); + + err = ce147_i2c_write_multi(client, CMD_START_OT, + ce147_buf_set_object_tracking, + ce147_len_set_object_tracking); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "object_tracking\n", __func__); + return -EIO; + } + + /* Read status whether AF Tracking is successful or fail */ + for (count = 0; count < 300; count++) { + msleep(10); + ce147_buf_check_object_tracking[0] = 0xFF; + err = ce147_i2c_read_multi(client, CMD_CHECK_OT, + NULL, 0, + ce147_buf_check_object_tracking, + ce147_len_check_object_tracking); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read " + "for object_tracking\n", + __func__); + return -EIO; + } + if (ce147_buf_check_object_tracking[0] == 0x02 + || ce147_buf_check_object_tracking[0] == 0x03) + break; + } + + /* OT status: searching an object in progess */ + if (ce147_buf_check_object_tracking[0] == 0x01) { + state->ot_status = 1; + } else if (ce147_buf_check_object_tracking[0] == 0x02) { + /* OT status: an object is detected successfully */ + err = ce147_set_continous_af(sd, ctrl); + if (err < 0) { + dev_err(&client->dev, "%s: failed: " + "ce147_start_continous_af for " + "object_tracking\n", __func__); + return -EIO; + } + state->ot_status = 2; + } else if (ce147_buf_check_object_tracking[0] == 0x03) { + /* OT status: an object detecting is failed */ + state->ot_status = 3; + } + } else { + err = ce147_get_focus_mode(client, CMD_STOP_LENS_MOVEMENT, + ce147_buf_stop_lens); + if (err < 0) { + dev_err(&client->dev, "%s: failed: " + "ce147_start_continous_af for " + "object_tracking\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_START_OT, + ce147_buf_set_object_tracking, + ce147_len_set_object_tracking); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "object_tracking\n", __func__); + return -EIO; + } + } + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_get_object_tracking(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_check_object_tracking[9] = { 0x00, }; + unsigned int ce147_len_check_object_tracking = 9; + + ce147_buf_check_object_tracking[0] = 0xFF; + err = ce147_i2c_read_multi(client, CMD_CHECK_OT, NULL, 0, + ce147_buf_check_object_tracking, + ce147_len_check_object_tracking); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read for " + "object_tracking\n", __func__); + return -EIO; + } + + /* OT status: searching an object in progess */ + if (ce147_buf_check_object_tracking[0] == 0x01) { + state->ot_status = 1; + } else if (ce147_buf_check_object_tracking[0] == 0x02) { + /* OT status: an object is detected successfully */ + state->ot_status = 2; + } else if (ce147_buf_check_object_tracking[0] == 0x03) { + /* OT status: an object detecting is failed */ + state->ot_status = 3; + } else if (ce147_buf_check_object_tracking[0] == 0x04) { + /* OT status: detected object is missing */ + state->ot_status = 4; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_face_detection(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_fd[3] = { 0x00, 0x00, 0x00 }; + unsigned int ce147_len_set_fd = 3; + + switch (ctrl->value) { + case FACE_DETECTION_ON: + ce147_buf_set_fd[0] = 0x03; + ce147_buf_set_fd[1] = 0x01; + ce147_buf_set_fd[2] = 0x0A; + break; + + case FACE_DETECTION_ON_BEAUTY: + ce147_buf_set_fd[0] = 0x01; + ce147_buf_set_fd[1] = 0x01; + ce147_buf_set_fd[2] = 0x0A; + break; + + case FACE_DETECTION_NOLINE: + ce147_buf_set_fd[0] = 0x03; + ce147_buf_set_fd[1] = 0x00; + ce147_buf_set_fd[2] = 0x0A; + break; + + case FACE_DETECTION_OFF: + default: + ce147_buf_set_fd[0] = 0x00; + ce147_buf_set_fd[1] = 0x00; + ce147_buf_set_fd[2] = 0x00; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_FACE_DETECTION, + ce147_buf_set_fd, ce147_len_set_fd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "face_detection\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_smart_auto(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_smart_auto[1] = { 0x00 }; + unsigned int ce147_len_set_smart_auto = 1; + + if (ctrl->value == SMART_AUTO_ON) { + ce147_buf_set_smart_auto[0] = 0x01; + err = ce147_i2c_write_multi(client, CMD_SET_SMART_AUTO, + ce147_buf_set_smart_auto, + ce147_len_set_smart_auto); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "smart_auto\n", __func__); + return -EIO; + } +#if 0 + err = ce147_set_continous_af(sd, CAF_START); + if (err < 0) { + dev_err(&client->dev, "%s: failed: CAF_START for " + "smart_auto\n", __func__); + return -EIO; + } +#endif + } else { +#if 0 + err = ce147_set_continous_af(sd, CAF_STOP); + if (err < 0) { + dev_err(&client->dev, "%s: failed: CAF_START for " + "smart_auto\n", __func__); + return -EIO; + } +#endif + + ce147_buf_set_smart_auto[0] = 0x00; + err = ce147_i2c_write_multi(client, CMD_SET_SMART_AUTO, + ce147_buf_set_smart_auto, + ce147_len_set_smart_auto); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "smart_auto\n", __func__); + return -EIO; + } + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_get_smart_auto_status(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_smart_auto_status[2] = {0x00, 0x00}; + + ce147_buf_smart_auto_status[0] = 0xFF; + err = ce147_i2c_read_multi(client, CMD_GET_SMART_AUTO_STATUS, NULL, 0, + ce147_buf_smart_auto_status, 2); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read for auto_status\n", + __func__); + return -EIO; + } + + if (ce147_buf_smart_auto_status[0] == 0x00 + || ce147_buf_smart_auto_status[0] == 0x01) { + state->sa_status = SMART_AUTO_STATUS_AUTO; + } else { + switch (ce147_buf_smart_auto_status[1]) { + case 0x00: + state->sa_status = SMART_AUTO_STATUS_LANDSCAPE; + break; + + case 0x01: + state->sa_status = SMART_AUTO_STATUS_PORTRAIT; + break; + + case 0x02: + state->sa_status = SMART_AUTO_STATUS_NIGHT; + break; + + case 0x03: + state->sa_status = SMART_AUTO_STATUS_PORTRAIT_NIGHT; + break; + + case 0x04: + state->sa_status = SMART_AUTO_STATUS_MACRO; + break; + + case 0x05: + state->sa_status = SMART_AUTO_STATUS_PORTRAIT_BACKLIT; + break; + + case 0x06: + state->sa_status = SMART_AUTO_STATUS_PORTRAIT_ANTISHAKE; + break; + + case 0x07: + state->sa_status = SMART_AUTO_STATUS_ANTISHAKE; + break; + } + } + + ce147_msg(&client->dev, "%s: done(smartauto_status:%d)\n", + __func__, state->sa_status); + + return 0; +} + +static int ce147_set_touch_auto_focus(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + unsigned short x; + unsigned short y; + + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_touch_af[11] = { 0x00, }; + unsigned int ce147_len_set_touch_af = 11; + +#if defined(CONFIG_ARIES_NTT) || defined(CONFIG_SAMSUNG_FASCINATE)/* Modify NTTS1 */ + state->disable_aeawb_lock = 1; + err = ce147_set_awb_lock(sd, 0); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_awb_lock, " + "err %d\n", __func__, err); + return -EIO; + } +#endif + /* get x,y touch position */ + x = state->position.x; + y = state->position.y; + + if (ctrl->value == TOUCH_AF_START) { + ce147_buf_set_touch_af[0] = 0x01; + ce147_buf_set_touch_af[1] = 0x03; + ce147_buf_set_touch_af[2] = 0x00; + ce147_buf_set_touch_af[3] = ((x - 0x32) & 0x00FF); + ce147_buf_set_touch_af[4] = (((x - 0x32) & 0xFF00) >> 8); + ce147_buf_set_touch_af[5] = ((y - 0x32) & 0x00FF); + ce147_buf_set_touch_af[6] = (((y - 0x32) & 0xFF00) >> 8); + ce147_buf_set_touch_af[7] = ((x + 0x32) & 0x00FF); + ce147_buf_set_touch_af[8] = (((x + 0x32) & 0xFF00) >> 8); + ce147_buf_set_touch_af[9] = ((y + 0x32) & 0x00FF); + ce147_buf_set_touch_af[10] = (((y + 0x32) & 0xFF00) >> 8); + } + + err = ce147_i2c_write_multi(client, CMD_SET_TOUCH_AUTO_FOCUS, + ce147_buf_set_touch_af, ce147_len_set_touch_af); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "touch_auto_focus\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_focus_mode(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_focus_mode[1] = { 0x00 }; + + switch (ctrl->value) { + case FOCUS_MODE_MACRO: + case FOCUS_MODE_MACRO_DEFAULT: + ce147_buf_set_focus_mode[0] = 0x01; + break; + + /* case FOCUS_MODE_FD: + break; */ + + case FOCUS_MODE_AUTO: + case FOCUS_MODE_AUTO_DEFAULT: + /* case FOCUS_MODE_FD_DEFAULT: */ + default: + ce147_buf_set_focus_mode[0] = 0x00; + break; + } +#if 0 + if (state->hd_preview_on == 1) + ce147_buf_set_focus_mode[0] = 0x07; +#endif + /* if (ctrl->value != FOCUS_MODE_FD) { */ + if ((state->pre_focus_mode != ce147_buf_set_focus_mode[0]) + || (ctrl->value == FOCUS_MODE_MACRO_DEFAULT) + || (ctrl->value == FOCUS_MODE_AUTO_DEFAULT)) { + /* || (ctrl->value == FOCUS_MODE_FD_DEFAULT)) */ +#if defined(CONFIG_ARIES_NTT) || defined(CONFIG_SAMSUNG_FASCINATE)/* Modify NTTS1 */ + ce147_msg(&client->dev, "%s: unlock\n", __func__); + state->disable_aeawb_lock = 0; + err = ce147_set_awb_lock(sd, 0); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_awb_" + "unlock, err %d\n", __func__, err); + return -EIO; + } +#endif + /* pr_debug("[5B] ce147_set_focus_mode: %d\n", + ce147_buf_set_focus_mode[0]); */ + err = ce147_get_focus_mode(client, CMD_SET_AUTO_FOCUS_MODE, + ce147_buf_set_focus_mode); + if (err < 0) { + dev_err(&client->dev, "%s: failed: get_focus_mode\n", + __func__); + return -EIO; + } + } + state->pre_focus_mode = ce147_buf_set_focus_mode[0]; + /* } */ + + return 0; +} + +static int ce147_set_vintage_mode(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_vintage_mode[4] = { + 0x10, 0x01, 0x32, 0x00 + }; + unsigned int ce147_len_set_vintage_mode = 4; + + switch (ctrl->value) { + case VINTAGE_MODE_OFF: + ce147_buf_set_vintage_mode[1] = 0x00; + ce147_buf_set_vintage_mode[2] = 0x00; + ce147_buf_set_vintage_mode[3] = 0x00; + break; + + case VINTAGE_MODE_NORMAL: + ce147_buf_set_vintage_mode[3] = 0x00; + break; + + case VINTAGE_MODE_WARM: + ce147_buf_set_vintage_mode[3] = 0x02; + break; + + case VINTAGE_MODE_COOL: + ce147_buf_set_vintage_mode[3] = 0x01; + break; + + case VINTAGE_MODE_BNW: + ce147_buf_set_vintage_mode[3] = 0x03; + break; + + default: + ce147_buf_set_vintage_mode[1] = 0x00; + ce147_buf_set_vintage_mode[2] = 0x00; + ce147_buf_set_vintage_mode[3] = 0x00; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT_SHOT, + ce147_buf_set_vintage_mode, + ce147_len_set_vintage_mode); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "vintage_mode\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_face_beauty(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_face_beauty[4] = { 0x00, 0x00, 0x00, 0x00 }; + unsigned int ce147_len_set_face_beauty = 4; + + switch (ctrl->value) { + case BEAUTY_SHOT_ON: + ce147_buf_set_face_beauty[1] = 0x01; + ce147_buf_set_face_beauty[2] = 0x32; + ce147_buf_set_face_beauty[3] = 0x01; + break; + + case BEAUTY_SHOT_OFF: + default: + break; + } + + /* Need to set face detection as 'face beauty on' mode. */ + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT_SHOT, + ce147_buf_set_face_beauty, ce147_len_set_face_beauty); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "set_face_beauty\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + + +static int ce147_set_white_balance(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_wb_auto[1] = { 0x01 }; + unsigned char ce147_buf_set_wb[2] = { 0x10, 0x00 }; + unsigned int ce147_len_set_wb_auto = 1; + unsigned int ce147_len_set_wb = 2; + + switch (ctrl->value) { + case WHITE_BALANCE_AUTO: + ce147_buf_set_wb_auto[0] = 0x00; + break; + + case WHITE_BALANCE_SUNNY: + ce147_buf_set_wb[1] = 0x00; + break; + + case WHITE_BALANCE_CLOUDY: + ce147_buf_set_wb[1] = 0x01; + break; + + case WHITE_BALANCE_TUNGSTEN: + ce147_buf_set_wb[1] = 0x02; + break; + + case WHITE_BALANCE_FLUORESCENT: + ce147_buf_set_wb[1] = 0x03; + break; + + default: + dev_err(&client->dev, "%s: failed: to set_white_balance, " + "enum: %d\n", __func__, ctrl->value); + return -EINVAL; + } + + if (ctrl->value != WHITE_BALANCE_AUTO) { + err = ce147_i2c_write_multi(client, CMD_SET_WB, + ce147_buf_set_wb, ce147_len_set_wb); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "white_balance\n", __func__); + return -EIO; + } + } + err = ce147_i2c_write_multi(client, CMD_SET_WB_AUTO, + ce147_buf_set_wb_auto, ce147_len_set_wb_auto); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "white_balance\n", __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for white_balance\n", + __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_ev(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_buf_set_ev[2] = { 0x02, 0x00 }; + unsigned int ce147_len_set_ev = 2; + unsigned int ce147_ev_offset = 13; + + switch (ctrl->value) { + case EV_MINUS_4: + ce147_buf_set_ev[1] = 0x02; + break; + + case EV_MINUS_3: + ce147_buf_set_ev[1] = 0x03; + break; + + case EV_MINUS_2: + ce147_buf_set_ev[1] = 0x04; + break; + + case EV_MINUS_1: + ce147_buf_set_ev[1] = 0x05; + break; + + case EV_DEFAULT: + ce147_buf_set_ev[1] = 0x06; + break; + + case EV_PLUS_1: + ce147_buf_set_ev[1] = 0x07; + break; + + case EV_PLUS_2: + ce147_buf_set_ev[1] = 0x08; + break; + + case EV_PLUS_3: + ce147_buf_set_ev[1] = 0x09; + break; + + case EV_PLUS_4: + ce147_buf_set_ev[1] = 0x0A; + break; + + default: + dev_err(&client->dev, "%s: failed: to set_ev, enum: %d\n", + __func__, ctrl->value); + return -EINVAL; + } + + if (state->hd_preview_on) { /* This is for HD REC preview */ + ce147_buf_set_ev[1] += ce147_ev_offset; + } + /* pr_debug("ce147_set_ev: set_ev:, data: 0x%02x\n", + ce147_buf_set_ev[1]); */ + + err = ce147_i2c_write_multi(client, CMD_SET_WB, + ce147_buf_set_ev, ce147_len_set_ev); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_ev, " + "HD preview(%d)\n", + __func__, state->hd_preview_on); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for set_ev\n", __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_metering(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_buf_set_metering[2] = { 0x00, 0x00 }; + unsigned int ce147_len_set_metering = 2; + + switch (ctrl->value) { + case METERING_MATRIX: + ce147_buf_set_metering[1] = 0x02; + break; + + case METERING_CENTER: + ce147_buf_set_metering[1] = 0x00; + break; + + case METERING_SPOT: + ce147_buf_set_metering[1] = 0x01; + break; + + default: + dev_err(&client->dev, "%s: failed: to set_photometry, " + "enum: %d\n", __func__, ctrl->value); + return -EINVAL; + } + + if (state->hd_preview_on) + ce147_buf_set_metering[1] = 0x03; + + err = ce147_i2c_write_multi(client, CMD_SET_WB, + ce147_buf_set_metering, ce147_len_set_metering); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "set_photometry\n", __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for set_photometry\n", + __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_set_iso(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_iso[2] = { 0x01, 0x00 }; + unsigned int ce147_len_set_iso = 2; + + ce147_msg(&client->dev, "%s: Enter : iso %d\n", __func__, ctrl->value); + + switch (ctrl->value) { + case ISO_AUTO: + ce147_buf_set_iso[1] = 0x06; + break; + + case ISO_50: + ce147_buf_set_iso[1] = 0x07; + break; + + case ISO_100: + ce147_buf_set_iso[1] = 0x08; + break; + + case ISO_200: + ce147_buf_set_iso[1] = 0x09; + break; + + case ISO_400: + ce147_buf_set_iso[1] = 0x0A; + break; + + case ISO_800: + ce147_buf_set_iso[1] = 0x0B; + break; + + case ISO_1600: + ce147_buf_set_iso[1] = 0x0C; + break; + + /* This is additional setting for Sports' scene mode */ + case ISO_SPORTS: + ce147_buf_set_iso[1] = 0x12; + break; + + /* This is additional setting for 'Night' scene mode */ + case ISO_NIGHT: + ce147_buf_set_iso[1] = 0x17; + break; + + /* This is additional setting for video recording mode */ + case ISO_MOVIE: + ce147_buf_set_iso[1] = 0x02; + break; + + default: + dev_err(&client->dev, "%s: failed: to set_iso, enum: %d\n", + __func__, ctrl->value); + return -EINVAL; + } + + err = ce147_i2c_write_multi(client, CMD_SET_WB, + ce147_buf_set_iso, ce147_len_set_iso); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for set_iso\n", + __func__); + return -EIO; + } +#if 0 /* remove batch */ + err = ce147_get_batch_reflection_status(sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_get_batch_" + "reflection_status for set_iso\n", __func__); + return -EIO; + } +#endif + ce147_msg(&client->dev, "%s: done, iso: 0x%02x\n", + __func__, ce147_buf_set_iso[1]); + + return 0; +} + +static int ce147_set_gamma(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_buf_set_gamma[2] = { 0x01, 0x00 }; + unsigned int ce147_len_set_gamma = 2; + + unsigned char ce147_buf_set_uv[2] = { 0x03, 0x00 }; + unsigned int ce147_len_set_uv = 2; + + if (ctrl->value == GAMMA_ON) { + if (state->hd_preview_on) { + ce147_buf_set_gamma[1] = 0x01; + ce147_buf_set_uv[1] = 0x01; + } + } + + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT, + ce147_buf_set_gamma, ce147_len_set_gamma); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "ce147_set_gamma\n", __func__); + return -EIO; + } + + err = ce147_i2c_write_multi(client, CMD_SET_EFFECT, + ce147_buf_set_uv, ce147_len_set_uv); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "ce147_set_gamma\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done, gamma: 0x%02x, uv: 0x%02x, hd: %d\n", + __func__, ce147_buf_set_gamma[1], ce147_buf_set_uv[1], + state->hd_preview_on); + + return 0; +} + +static int ce147_set_slow_ae(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + unsigned char ce147_buf_set_slow_ae[2] = { 0x03, 0x00 }; + unsigned int ce147_len_set_slow_ae = 2; + + if (ctrl->value == SLOW_AE_ON) + if (state->hd_preview_on) + ce147_buf_set_slow_ae[1] = 0x02; + + err = ce147_i2c_write_multi(client, CMD_SET_WB, + ce147_buf_set_slow_ae, ce147_len_set_slow_ae); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "ce147_set_slow_ae\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done, slow_ae: 0x%02x, hd: %d\n", + __func__, ce147_buf_set_slow_ae[1], + state->hd_preview_on); + + return 0; +} + +static int ce147_set_face_lock(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + unsigned char ce147_buf_set_fd_lock[1] = { 0x00 }; + unsigned int ce147_len_set_fd_lock = 1; + + switch (ctrl->value) { + case FACE_LOCK_ON: + ce147_buf_set_fd_lock[0] = 0x01; + break; + + case FIRST_FACE_TRACKING: + ce147_buf_set_fd_lock[0] = 0x02; + break; + + case FACE_LOCK_OFF: + default: + ce147_buf_set_fd_lock[0] = 0x00; + break; + } + + err = ce147_i2c_write_multi(client, CMD_SET_FACE_LOCK, + ce147_buf_set_fd_lock, ce147_len_set_fd_lock); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "face_lock\n", __func__); + return -EIO; + } + + ce147_msg(&client->dev, "%s: done\n", __func__); + + return 0; +} + +static int ce147_finish_auto_focus(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); +#if defined(CONFIG_ARIES_NTT) || defined(CONFIG_SAMSUNG_FASCINATE) + if (!state->disable_aeawb_lock) { + err = ce147_set_awb_lock(sd, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_awb_lock, err %d\n",__func__, err); + return -EIO; + } + } +#endif + + state->af_status = AF_NONE; + return 0; +} + +static int ce147_start_auto_focus(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned char ce147_buf_set_af[1] = { 0x00 }; + unsigned int ce147_len_set_af = 1; + struct ce147_state *state = to_state(sd); + + ce147_msg(&client->dev, "%s\n", __func__); + +#ifdef CONFIG_SAMSUNG_FASCINATE + ce147_msg(&client->dev, "%s: unlock\n", __func__); + err = ce147_set_awb_lock(sd, 0); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_set_awb_" + "unlock, err %d\n", __func__, err); + return -EIO; + } +#endif + + /* start af */ + err = ce147_i2c_write_multi(client, CMD_START_AUTO_FOCUS_SEARCH, + ce147_buf_set_af, ce147_len_set_af); + state->af_status = AF_INITIAL; + + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_write for " + "auto_focus\n", __func__); + return -EIO; + } + + return 0; +} + +static int ce147_stop_auto_focus(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int err; + unsigned char ce147_buf_set_af = 0x00; + + ce147_msg(&client->dev, "%s\n", __func__); + /* stop af */ + err = ce147_i2c_write_multi(client, CMD_STOP_LENS_MOVEMENT, + &ce147_buf_set_af, 1); + if (err < 0) + dev_err(&client->dev, "%s: failed: i2c_write for auto_focus\n", + __func__); + + if (state->af_status != AF_START) { + /* we weren't in the middle auto focus operation, we're done */ + dev_dbg(&client->dev, + "%s: auto focus not in progress, done\n", __func__); + + return 0; + } + + state->af_status = AF_CANCEL; + + return err; +} + +static int ce147_get_auto_focus_status(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + unsigned char ce147_buf_get_af_status[1] = { 0x00 }; + int err; + + ce147_msg(&client->dev, "%s\n", __func__); + + if (state->af_status == AF_INITIAL) { + dev_dbg(&client->dev, "%s: Check AF Result\n", __func__); + if (state->af_status == AF_NONE) { + dev_dbg(&client->dev, + "%s: auto focus never started, returning 0x2\n", + __func__); + ctrl->value = AUTO_FOCUS_CANCELLED; + return 0; + } + } else if (state->af_status == AF_CANCEL) { + dev_dbg(&client->dev, + "%s: AF is cancelled while doing\n", __func__); + ctrl->value = AUTO_FOCUS_CANCELLED; + ce147_finish_auto_focus(sd); + return 0; + } + + ce147_buf_get_af_status[0] = 0xFF; + err = ce147_i2c_read_multi(client, + CMD_CHECK_AUTO_FOCUS_SEARCH, NULL, 0, + ce147_buf_get_af_status, 1); + if (err < 0) { + dev_err(&client->dev, "%s: failed: i2c_read " + "for auto_focus\n", __func__); + return -EIO; + } + + if (ce147_buf_get_af_status[0] != 0x02 && ce147_buf_get_af_status[0] != 0x05) { + ce147_set_focus_mode(sd, ctrl); + } + + ctrl->value = ce147_buf_get_af_status[0]; + ce147_msg(&client->dev, "%s: done\n", __func__); + return 0; +} + +static void ce147_init_parameters(struct v4l2_subdev *sd) +{ + struct ce147_state *state = to_state(sd); + + /* Set initial values for the sensor stream parameters */ + state->strm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + state->strm.parm.capture.timeperframe.numerator = 1; + state->strm.parm.capture.capturemode = 0; + + /* state->framesize_index = CE147_PREVIEW_VGA; */ + /*state->fps = 30;*/ /* Default value */ + + state->jpeg.enable = 0; + state->jpeg.quality = 100; + state->jpeg.main_offset = 0; + state->jpeg.main_size = 0; + state->jpeg.thumb_offset = 0; + state->jpeg.thumb_size = 0; + state->jpeg.postview_offset = 0; + +} + +static int ce147_get_fw_data(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int err = -EINVAL; + + err = ce147_power_en(1, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(on)\n", + __func__); + return -EIO; + } + + err = ce147_load_fw(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Camera Initialization\n", + __func__); + return -EIO; + } + + /* pr_debug("ce147_get_fw_data: ce147_load_fw is ok\n"); */ + + ce147_init_parameters(sd); + + /* pr_debug("ce147_get_fw_data: ce147_init_parameters is ok\n"); */ + + err = ce147_get_fw_version(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading firmware version\n", + __func__); + return -EIO; + } + + /* pr_debug("ce147_get_fw_data: ce147_get_fw_version is ok\n"); */ + + err = ce147_get_dateinfo(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading dateinfo\n", + __func__); + return -EIO; + } + + /* pr_debug("ce147_get_fw_data: ce147_get_dateinfo is ok\n"); */ + + err = ce147_get_sensor_version(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading sensor info\n", + __func__); + return -EIO; + } + + /* pr_debug("ce147_get_fw_data: ce147_get_sensor_version is ok\n"); */ + + err = ce147_get_sensor_maker_version(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading maker info\n", + __func__); + return -EIO; + } + + err = ce147_get_af_version(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading af info\n", + __func__); + return -EIO; + } + + err = ce147_get_gamma_version(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading camera gamma info\n", + __func__); + return -EIO; + } + + err = ce147_power_en(0, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(off)\n", + __func__); + return -EIO; + } + + /* pr_debug("ce147_get_fw_data: ce147_power_en is ok\n"); */ + + ce147_info(&client->dev, "FW Version: %d.%d\n", + state->fw.major, state->fw.minor); + ce147_info(&client->dev, "PRM Version: %d.%d\n", + state->prm.major, state->prm.minor); + ce147_info(&client->dev, "Date(y.m.d): %d.%d.%d\n", + state->dateinfo.year, state->dateinfo.month, + state->dateinfo.date); + ce147_info(&client->dev, "Sensor version: %d\n", + state->sensor_version); + + return 0; +} + +/* s1_camera [ Defense process by ESD input ] _[ */ +static int ce147_reset(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int err = -EINVAL; + + dev_err(&client->dev, "%s: Enter\n", __func__); + + err = ce147_power_en(0, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(off)\n", + __func__); + return -EIO; + } + + mdelay(5); + + err = ce147_power_en(1, sd); + if (err < 0) { + dev_err(&client->dev, "%s: failed: ce147_power_en(off)\n", + __func__); + return -EIO; + } + + err = ce147_load_fw(sd); /* ce147_init(sd); */ + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Camera Initialization\n", + __func__); + return -EIO; + } + + return 0; +} +/* _] */ + +#if 0 +/* Sample code */ +static const char *ce147_querymenu_wb_preset[] = { + "WB Tungsten", "WB Fluorescent", "WB sunny", "WB cloudy", NULL +}; +#endif + +static struct v4l2_queryctrl ce147_controls[] = { +#if 0 + /* Sample code */ + { + .id = V4L2_CID_WHITE_BALANCE_PRESET, + .type = V4L2_CTRL_TYPE_MENU, + .name = "White balance preset", + .minimum = 0, + .maximum = ARRAY_SIZE(ce147_querymenu_wb_preset) - 2, + .step = 1, + .default_value = 0, + }, +#endif +}; + +const char **ce147_ctrl_get_menu(u32 id) +{ + switch (id) { +#if 0 + /* Sample code */ + case V4L2_CID_WHITE_BALANCE_PRESET: + return ce147_querymenu_wb_preset; +#endif + default: + return v4l2_ctrl_get_menu(id); + } +} + +static inline struct v4l2_queryctrl const *ce147_find_qctrl(int id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ce147_controls); i++) + if (ce147_controls[i].id == id) + return &ce147_controls[i]; + + return NULL; +} + +static int ce147_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ce147_controls); i++) { + if (ce147_controls[i].id == qc->id) { + memcpy(qc, &ce147_controls[i], + sizeof(struct v4l2_queryctrl)); + return 0; + } + } + + return -EINVAL; +} + +static int ce147_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm) +{ + struct v4l2_queryctrl qctrl; + + qctrl.id = qm->id; + ce147_queryctrl(sd, &qctrl); + + return v4l2_ctrl_query_menu(qm, &qctrl, ce147_ctrl_get_menu(qm->id)); +} + +/* + * Clock configuration + * Configure expected MCLK from host and return EINVAL if not supported clock + * frequency is expected + * freq : in Hz + * flag : not supported for now + */ +static int ce147_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags) +{ + int err = -EINVAL; + + return err; +} + +static int ce147_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + int err = 0; + + return err; +} + +static int ce147_get_framesize_index(struct v4l2_subdev *sd); +static int ce147_set_framesize_index(struct v4l2_subdev *sd, + unsigned int index); +/* Information received: + * width, height + * pixel_format -> to be handled in the upper layer + * + * */ +static int ce147_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + int err = 0; + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int framesize_index = -1; + + if (fmt->code == V4L2_MBUS_FMT_FIXED && + fmt->colorspace != V4L2_COLORSPACE_JPEG) { + dev_err(&client->dev, "%s: mismatch in pixelformat and " + "colorspace\n", __func__); + return -EINVAL; + } + + state->pix.width = fmt->width; + state->pix.height = fmt->height; + if (fmt->colorspace == V4L2_COLORSPACE_JPEG) + state->pix.pixelformat = V4L2_PIX_FMT_JPEG; + else + state->pix.pixelformat = 0; /* is this used anywhere? */ + + if (fmt->colorspace == V4L2_COLORSPACE_JPEG) + state->oprmode = CE147_OPRMODE_IMAGE; + else + state->oprmode = CE147_OPRMODE_VIDEO; + + framesize_index = ce147_get_framesize_index(sd); + + ce147_msg(&client->dev, "%s:framesize_index = %d\n", + __func__, framesize_index); + + err = ce147_set_framesize_index(sd, framesize_index); + if (err < 0) { + dev_err(&client->dev, "%s: set_framesize_index failed\n", + __func__); + return -EINVAL; + } + + if (state->pix.pixelformat == V4L2_PIX_FMT_JPEG) + state->jpeg.enable = 1; + else + state->jpeg.enable = 0; + + if (state->oprmode == CE147_OPRMODE_VIDEO) { + if (framesize_index == CE147_PREVIEW_720P) + state->hd_preview_on = 1; + else + state->hd_preview_on = 0; + } + + return 0; +} + +static int ce147_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_frmsizeenum *fsize) +{ + struct ce147_state *state = to_state(sd); + int num_entries = sizeof(ce147_framesize_list) + / sizeof(struct ce147_enum_framesize); + struct ce147_enum_framesize *elem; + int index = 0; + int i = 0; + + /* The camera interface should read this value, this is the resolution + * at which the sensor would provide framedata to the camera i/f + * In case of image capture, + * this returns the default camera resolution (VGA) + */ + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + if (state->pix.pixelformat == V4L2_PIX_FMT_JPEG) + index = CE147_PREVIEW_VGA; + else + index = state->framesize_index; + + for (i = 0; i < num_entries; i++) { + elem = &ce147_framesize_list[i]; + if (elem->index == index) { + fsize->discrete.width = + ce147_framesize_list[index].width; + fsize->discrete.height = + ce147_framesize_list[index].height; + return 0; + } + } + + return -EINVAL; +} + +static int ce147_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_frmivalenum *fival) +{ + int err = 0; + + return err; +} + +static int ce147_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + int num_entries; + + num_entries = sizeof(capture_fmts) / sizeof(struct v4l2_mbus_framefmt); + + if (index >= num_entries) + return -EINVAL; + + *code = capture_fmts[index].code; + + return 0; +} + +static int ce147_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + int num_entries; + int i; + + num_entries = sizeof(capture_fmts) / sizeof(struct v4l2_mbus_framefmt); + + for (i = 0; i < num_entries; i++) { + if (capture_fmts[i].code == fmt->code && + capture_fmts[i].colorspace == fmt->colorspace) { + return 0; + } + } + + return -EINVAL; +} + +/** Gets current FPS value */ +static int ce147_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) +{ + struct ce147_state *state = to_state(sd); + int err = 0; + + state->strm.parm.capture.timeperframe.numerator = 1; + state->strm.parm.capture.timeperframe.denominator = state->fps; + + memcpy(param, &state->strm, sizeof(param)); + + return err; +} + +/** Sets the FPS value */ +static int ce147_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) +{ + int err = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + + if (param->parm.capture.timeperframe.numerator + != state->strm.parm.capture.timeperframe.numerator + || param->parm.capture.timeperframe.denominator + != state->strm.parm.capture.timeperframe.denominator) { + + int fps = 0; + int fps_max = 30; + + if (param->parm.capture.timeperframe.numerator + && param->parm.capture.timeperframe.denominator) + fps = (int)(param->parm.capture.timeperframe.denominator + / param->parm.capture + .timeperframe.numerator); + else + fps = 0; + + if (fps <= 0 || fps > fps_max) { + dev_err(&client->dev, "%s: Framerate %d not supported, " + "setting it to %d fps.\n", + __func__, fps, fps_max); + fps = fps_max; + } + + state->strm.parm.capture.timeperframe.numerator = 1; + state->strm.parm.capture.timeperframe.denominator = fps; + + state->fps = fps; + } + + /* Don't set the fps value, just update it in the state + * We will set the resolution and fps in the start operation + * (preview/capture) call */ + + return err; +} + +/* This function is called from the g_ctrl api + * + * This function should be called only after the s_fmt call, + * which sets the required width/height value. + * + * It checks a list of available frame sizes and returns the + * most appropriate index of the frame size. + * + * Note: The index is not the index of the entry in the list. It is + * the value of the member 'index' of the particular entry. This is + * done to add additional layer of error checking. + * + * The list is stored in an increasing order (as far as possible). + * Hene the first entry (searching from the beginning) where both the + * width and height is more than the required value is returned. + * In case of no match, we return the last entry (which is supposed + * to be the largest resolution supported.) + * + * It returns the index (enum ce147_frame_size) of the framesize entry. + */ +static int ce147_get_framesize_index(struct v4l2_subdev *sd) +{ + int i = 0; + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_enum_framesize *frmsize; + + ce147_msg(&client->dev, "%s: Requested Res: %dx%d\n", + __func__, state->pix.width, state->pix.height); + + /* Check for video/image mode */ + for (i = 0; i < (sizeof(ce147_framesize_list) + / sizeof(struct ce147_enum_framesize)); i++) { + frmsize = &ce147_framesize_list[i]; + + if (frmsize->mode != state->oprmode) + continue; + + if (state->oprmode == CE147_OPRMODE_IMAGE) { + /* In case of image capture mode, + * if the given image resolution is not supported, + * return the next higher image resolution. */ + /* pr_debug("frmsize->width(%d) state->pix.width(%d) " + "frmsize->height(%d) " + "state->pix.height(%d)\n", + frmsize->width, + state->pix.width, + frmsize->height, + state->pix.height); */ + if (frmsize->width == state->pix.width + && frmsize->height == state->pix.height) { + /* pr_debug("frmsize->index(%d)\n", + frmsize->index); */ + return frmsize->index; + } + } else { + /* In case of video mode, + * if the given video resolution is not matching, use + * the default rate (currently CE147_PREVIEW_VGA). + */ + /* pr_debug("frmsize->width(%d) state->pix.width(%d) " + "frmsize->height(%d) " + "state->pix.height(%d)\n", + frmsize->width, + state->pix.width, + frmsize->height, + state->pix.height); */ + if (frmsize->width == state->pix.width + && frmsize->height == state->pix.height) { + /* pr_debug("frmsize->index(%d)\n", + frmsize->index); */ + return frmsize->index; + } + } + } + /* If it fails, return the default value. */ + return (state->oprmode == CE147_OPRMODE_IMAGE) + ? CE147_CAPTURE_3MP : CE147_PREVIEW_VGA; +} + + +/* This function is called from the s_ctrl api + * Given the index, it checks if it is a valid index. + * On success, it returns 0. + * On Failure, it returns -EINVAL + */ +static int ce147_set_framesize_index(struct v4l2_subdev *sd, unsigned int index) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int i = 0; + + for (i = 0; i < (sizeof(ce147_framesize_list) + / sizeof(struct ce147_enum_framesize)); i++) { + if (ce147_framesize_list[i].index == index + && ce147_framesize_list[i].mode == state->oprmode) { + state->framesize_index = ce147_framesize_list[i].index; + state->pix.width = ce147_framesize_list[i].width; + state->pix.height = ce147_framesize_list[i].height; + ce147_info(&client->dev, "%s: Camera Res: %dx%d\n", + __func__, state->pix.width, + state->pix.height); + return 0; + } + } + + return -EINVAL; +} + +static int ce147_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + struct ce147_userset userset = state->userset; + int err = -ENOIOCTLCMD; + + mutex_lock(&state->ctrl_lock); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ctrl->value = userset.exposure_bias; + err = 0; + break; + + case V4L2_CID_AUTO_WHITE_BALANCE: + ctrl->value = userset.auto_wb; + err = 0; + break; + + case V4L2_CID_WHITE_BALANCE_PRESET: + ctrl->value = userset.manual_wb; + err = 0; + break; + + case V4L2_CID_COLORFX: + ctrl->value = userset.effect; + err = 0; + break; + + case V4L2_CID_CONTRAST: + ctrl->value = userset.contrast; + err = 0; + break; + + case V4L2_CID_SATURATION: + ctrl->value = userset.saturation; + err = 0; + break; + + case V4L2_CID_SHARPNESS: + ctrl->value = userset.sharpness; + err = 0; + break; + + case V4L2_CID_CAM_JPEG_MAIN_SIZE: + ctrl->value = state->jpeg.main_size; + err = 0; + break; + + case V4L2_CID_CAM_JPEG_MAIN_OFFSET: + ctrl->value = state->jpeg.main_offset; + err = 0; + break; + + case V4L2_CID_CAM_JPEG_THUMB_SIZE: + ctrl->value = state->jpeg.thumb_size; + err = 0; + break; + + case V4L2_CID_CAM_JPEG_THUMB_OFFSET: + ctrl->value = state->jpeg.thumb_offset; + err = 0; + break; + + case V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET: + ctrl->value = state->jpeg.postview_offset; + err = 0; + break; + + case V4L2_CID_CAM_JPEG_MEMSIZE: + ctrl->value = SENSOR_JPEG_SNAPSHOT_MEMSIZE; + err = 0; + break; + + /* need to be modified */ + case V4L2_CID_CAM_JPEG_QUALITY: + ctrl->value = state->jpeg.quality; + err = 0; + break; + + case V4L2_CID_CAMERA_OBJ_TRACKING_STATUS: + err = ce147_get_object_tracking(sd, ctrl); + ctrl->value = state->ot_status; + break; + + case V4L2_CID_CAMERA_SMART_AUTO_STATUS: + err = ce147_get_smart_auto_status(sd, ctrl); + ctrl->value = state->sa_status; + break; + + case V4L2_CID_CAMERA_AUTO_FOCUS_RESULT_FIRST: + err = ce147_get_auto_focus_status(sd, ctrl); + break; + + case V4L2_CID_CAM_DATE_INFO_YEAR: + ctrl->value = state->dateinfo.year; + err = 0; + break; + + case V4L2_CID_CAM_DATE_INFO_MONTH: + ctrl->value = state->dateinfo.month; + err = 0; + break; + + case V4L2_CID_CAM_DATE_INFO_DATE: + ctrl->value = state->dateinfo.date; + err = 0; + break; + + case V4L2_CID_CAM_SENSOR_VER: + ctrl->value = state->sensor_version; + err = 0; + break; + + case V4L2_CID_CAM_FW_MINOR_VER: + ctrl->value = state->fw.minor; + err = 0; + break; + + case V4L2_CID_CAM_FW_MAJOR_VER: + ctrl->value = state->fw.major; + err = 0; + break; + + case V4L2_CID_CAM_PRM_MINOR_VER: + ctrl->value = state->prm.minor; + err = 0; + break; + + case V4L2_CID_CAM_PRM_MAJOR_VER: + ctrl->value = state->prm.major; + err = 0; + break; + + case V4L2_CID_CAM_SENSOR_MAKER: + ctrl->value = state->sensor_info.maker; + err = 0; + break; + + case V4L2_CID_CAM_SENSOR_OPTICAL: + ctrl->value = state->sensor_info.optical; + err = 0; + break; + + case V4L2_CID_CAM_AF_VER_LOW: + ctrl->value = state->af_info.low; + err = 0; + break; + + case V4L2_CID_CAM_AF_VER_HIGH: + ctrl->value = state->af_info.high; + err = 0; + break; + + case V4L2_CID_CAM_GAMMA_RG_LOW: + ctrl->value = state->gamma.rg_low; + err = 0; + break; + + case V4L2_CID_CAM_GAMMA_RG_HIGH: + ctrl->value = state->gamma.rg_high; + err = 0; + break; + + case V4L2_CID_CAM_GAMMA_BG_LOW: + ctrl->value = state->gamma.bg_low; + err = 0; + break; + + case V4L2_CID_CAM_GAMMA_BG_HIGH: + ctrl->value = state->gamma.bg_high; + err = 0; + break; + + case V4L2_CID_CAM_GET_DUMP_SIZE: + ctrl->value = state->fw_dump_size; + err = 0; + break; + + case V4L2_CID_MAIN_SW_DATE_INFO_YEAR: + ctrl->value = state->main_sw_dateinfo.year; + err = 0; + break; + + case V4L2_CID_MAIN_SW_DATE_INFO_MONTH: + ctrl->value = state->main_sw_dateinfo.month; + err = 0; + break; + + case V4L2_CID_MAIN_SW_DATE_INFO_DATE: + ctrl->value = state->main_sw_dateinfo.date; + err = 0; + break; + + case V4L2_CID_MAIN_SW_FW_MINOR_VER: + ctrl->value = state->main_sw_fw.minor; + err = 0; + break; + + case V4L2_CID_MAIN_SW_FW_MAJOR_VER: + ctrl->value = state->main_sw_fw.major; + err = 0; + break; + + case V4L2_CID_MAIN_SW_PRM_MINOR_VER: + ctrl->value = state->main_sw_prm.minor; + err = 0; + break; + + case V4L2_CID_MAIN_SW_PRM_MAJOR_VER: + ctrl->value = state->main_sw_prm.major; + err = 0; + break; + + default: + dev_err(&client->dev, "%s: no such ctrl\n", __func__); + break; + } + + mutex_unlock(&state->ctrl_lock); + + return err; +} + +static int ce147_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int err = -ENOIOCTLCMD; + int offset = 134217728; + int value = ctrl->value; + + mutex_lock(&state->ctrl_lock); + + switch (ctrl->id) { + case V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK: + err = ce147_set_ae_awb(sd, ctrl); + break; + + case V4L2_CID_CAMERA_FLASH_MODE: + err = ce147_set_flash(sd, ctrl); + break; + + case V4L2_CID_CAMERA_BRIGHTNESS: + if (state->runmode != CE147_RUNMODE_RUNNING) { + state->ev = ctrl->value; + err = 0; + } else + err = ce147_set_ev(sd, ctrl); + break; + + case V4L2_CID_CAMERA_WHITE_BALANCE: + if (state->runmode != CE147_RUNMODE_RUNNING) { + state->wb = ctrl->value; + err = 0; + } else + err = ce147_set_white_balance(sd, ctrl); + break; + + case V4L2_CID_CAMERA_EFFECT: + if (state->runmode != CE147_RUNMODE_RUNNING) { + state->effect = ctrl->value; + err = 0; + } else + err = ce147_set_effect(sd, ctrl); + break; + + case V4L2_CID_CAMERA_ISO: + if (state->runmode != CE147_RUNMODE_RUNNING) { + state->iso = ctrl->value; + err = 0; + } else + err = ce147_set_iso(sd, ctrl); + break; + + case V4L2_CID_CAMERA_METERING: + if (state->runmode != CE147_RUNMODE_RUNNING) { + state->metering = ctrl->value; + err = 0; + } else + err = ce147_set_metering(sd, ctrl); + break; + + case V4L2_CID_CAMERA_CONTRAST: + err = ce147_set_contrast(sd, ctrl); + break; + + case V4L2_CID_CAMERA_SATURATION: + err = ce147_set_saturation(sd, ctrl); + break; + + case V4L2_CID_CAMERA_SHARPNESS: + err = ce147_set_sharpness(sd, ctrl); + break; + + case V4L2_CID_CAMERA_WDR: + err = ce147_set_wdr(sd, ctrl); + break; + + case V4L2_CID_CAMERA_ANTI_SHAKE: + err = ce147_set_anti_shake(sd, ctrl); + break; + + case V4L2_CID_CAMERA_FACE_DETECTION: + err = ce147_set_face_detection(sd, ctrl); + break; + + case V4L2_CID_CAMERA_SMART_AUTO: + err = ce147_set_smart_auto(sd, ctrl); + break; + + case V4L2_CID_CAMERA_FOCUS_MODE: + err = ce147_set_focus_mode(sd, ctrl); + break; + + case V4L2_CID_CAMERA_VINTAGE_MODE: + err = ce147_set_vintage_mode(sd, ctrl); + break; + + case V4L2_CID_CAMERA_BEAUTY_SHOT: + err = ce147_set_face_beauty(sd, ctrl); + break; + + case V4L2_CID_CAMERA_FACEDETECT_LOCKUNLOCK: + err = ce147_set_face_lock(sd, ctrl); + break; + + /* need to be modified */ + case V4L2_CID_CAM_JPEG_QUALITY: + if (ctrl->value < 0 || ctrl->value > 100) + err = -EINVAL; + else { + state->jpeg.quality = ctrl->value; + err = 0; + } + break; + + case V4L2_CID_CAMERA_ZOOM: + err = ce147_set_dzoom(sd, ctrl); + break; + + case V4L2_CID_CAMERA_TOUCH_AF_START_STOP: + err = ce147_set_touch_auto_focus(sd, ctrl); + break; + + case V4L2_CID_CAMERA_CAF_START_STOP: + err = ce147_set_continous_af(sd, ctrl); + break; + + case V4L2_CID_CAMERA_OBJECT_POSITION_X: + state->position.x = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_OBJECT_POSITION_Y: + state->position.y = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_OBJ_TRACKING_START_STOP: + err = ce147_set_object_tracking(sd, ctrl); + break; + + case V4L2_CID_CAMERA_SET_AUTO_FOCUS: +#ifdef CONFIG_SAMSUNG_FASCINATE + ce147_set_preflash(sd, 0); +#endif + if (value == AUTO_FOCUS_ON) + err = ce147_start_auto_focus(sd, ctrl); + else if (value == AUTO_FOCUS_OFF) + err = ce147_stop_auto_focus(sd); + else { + err = -EINVAL; + dev_err(&client->dev, + "%s: bad focus value requestion %d\n", + __func__, value); + } + break; + + case V4L2_CID_CAMERA_FRAME_RATE: + state->fps = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_ANTI_BANDING: + state->anti_banding = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_SET_GAMMA: + state->hd_gamma = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_SET_SLOW_AE: + state->hd_slow_ae = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_CAPTURE: + err = ce147_set_capture_start(sd, ctrl); + break; + + case V4L2_CID_CAM_CAPTURE: + err = ce147_set_capture_config(sd, ctrl); + break; + + /* Used to start / stop preview operation. + * This call can be modified to START/STOP operation, + * which can be used in image capture also */ + case V4L2_CID_CAM_PREVIEW_ONOFF: + if (ctrl->value) + err = ce147_set_preview_start(sd); + else + err = ce147_set_preview_stop(sd); + break; + + case V4L2_CID_CAM_UPDATE_FW: + err = ce147_update_fw(sd); + break; + + case V4L2_CID_CAM_SET_FW_ADDR: + state->fw_info.addr = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAM_SET_FW_SIZE: + state->fw_info.size = ctrl->value; + err = 0; + break; + +#if defined(CONFIG_ARIES_NTT) || defined(CONFIG_SAMSUNG_FASCINATE) /* Modify NTTS1 */ + case V4L2_CID_CAMERA_AE_AWB_DISABLE_LOCK: + state->disable_aeawb_lock = ctrl->value; + err = 0; + break; +#endif + + case V4L2_CID_CAMERA_FINISH_AUTO_FOCUS: + err = ce147_finish_auto_focus(sd); + break; + + case V4L2_CID_CAM_FW_VER: + err = ce147_get_fw_data(sd); + break; + + case V4L2_CID_CAM_DUMP_FW: + err = ce147_dump_fw(sd); + break; + + case V4L2_CID_CAMERA_BATCH_REFLECTION: + err = ce147_get_batch_reflection_status(sd); + break; + + case V4L2_CID_CAMERA_EXIF_ORIENTATION: + state->exif_orientation_info = ctrl->value; + err = 0; + break; + + /* s1_camera [ Defense process by ESD input ] _[ */ + case V4L2_CID_CAMERA_RESET: + dev_err(&client->dev, "%s: V4L2_CID_CAMERA_RESET\n", __func__); + pr_debug("======ESD\n"); + err = ce147_reset(sd); + break; + /* _] */ + + case V4L2_CID_CAMERA_CHECK_DATALINE: + state->check_dataline = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_CHECK_DATALINE_STOP: + err = ce147_check_dataline_stop(sd); + break; + + case V4L2_CID_CAMERA_THUMBNAIL_NULL: + state->thumb_null = ctrl->value; + err = 0; + break; + +#ifdef CONFIG_SAMSUNG_FASCINATE + case V4L2_CID_CAMERA_LENS_SOFTLANDING: + ce147_set_af_softlanding(sd); + err = 0; +#endif + + default: + dev_err(&client->dev, "%s: no such control\n", __func__); + break; + } + + if (err < 0) + dev_err(&client->dev, "%s: vidioc_s_ctrl failed %d, " + "s_ctrl: id(%d), value(%d)\n", + __func__, err, (ctrl->id - offset), + ctrl->value); + + mutex_unlock(&state->ctrl_lock); + + return err; +} +static int ce147_s_ext_ctrls(struct v4l2_subdev *sd, + struct v4l2_ext_controls *ctrls) +{ + struct v4l2_ext_control *ctrl = ctrls->controls; + int ret = 0; + int i; + + for (i = 0; i < ctrls->count; i++, ctrl++) { + ret = ce147_s_ext_ctrl(sd, ctrl); + + if (ret) { + ctrls->error_idx = i; + break; + } + } + + return ret; +} + +static int ce147_s_ext_ctrl(struct v4l2_subdev *sd, + struct v4l2_ext_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int err = -ENOIOCTLCMD; + unsigned long temp = 0; + char *temp2; + struct gps_info_common *tempGPSType = NULL; + + state->exif_ctrl = 0; + + switch (ctrl->id) { + + case V4L2_CID_CAMERA_GPS_LATITUDE: + tempGPSType = (struct gps_info_common *)ctrl->reserved2[1]; + state->gpsInfo.ce147_gps_buf[0] = tempGPSType->direction; + state->gpsInfo.ce147_gps_buf[1] = tempGPSType->dgree; + state->gpsInfo.ce147_gps_buf[2] = tempGPSType->minute; + state->gpsInfo.ce147_gps_buf[3] = tempGPSType->second; + + if ((tempGPSType->direction == 0) + && (tempGPSType->dgree == 0) + && (tempGPSType->minute == 0) + && (tempGPSType->second == 0)) + condition = 1; + else + condition = 0; + + err = 0; + break; + + case V4L2_CID_CAMERA_GPS_LONGITUDE: + tempGPSType = (struct gps_info_common *)ctrl->reserved2[1]; + state->gpsInfo.ce147_gps_buf[4] = tempGPSType->direction; + state->gpsInfo.ce147_gps_buf[5] = tempGPSType->dgree; + state->gpsInfo.ce147_gps_buf[6] = tempGPSType->minute; + state->gpsInfo.ce147_gps_buf[7] = tempGPSType->second; + + if ((tempGPSType->direction == 0) + && (tempGPSType->dgree == 0) + && (tempGPSType->minute == 0) + && (tempGPSType->second == 0)) + condition = 1; + else + condition = 0; + + err = 0; + break; + + case V4L2_CID_CAMERA_GPS_ALTITUDE: + tempGPSType = (struct gps_info_common *)ctrl->reserved2[1]; + state->gpsInfo.ce147_altitude_buf[0] = tempGPSType->direction; + state->gpsInfo.ce147_altitude_buf[1] = (tempGPSType->dgree) + & 0x00ff; + state->gpsInfo.ce147_altitude_buf[2] = ((tempGPSType->dgree) + & 0xff00) >> 8; + state->gpsInfo.ce147_altitude_buf[3] = tempGPSType->minute; + + err = 0; + break; + + case V4L2_CID_CAMERA_GPS_TIMESTAMP: + /* state->gpsInfo.gps_timeStamp = + (struct tm*)ctrl->reserved2[1]; */ + temp = *((unsigned long *)ctrl->reserved2[1]); + state->gpsInfo.gps_timeStamp = temp; + err = 0; + break; + + case V4L2_CID_CAMERA_EXIF_TIME_INFO: + state->exifTimeInfo = (struct tm *)ctrl->reserved2[1]; + err = 0; + break; + + case V4L2_CID_CAMERA_GPS_PROCESSINGMETHOD: + temp2 = ((char *)ctrl->reserved2[1]); + strcpy(state->gpsInfo.gps_processingmethod, temp2); + err = 0; + break; + } + + if (condition) + state->exif_ctrl = 1; + + if (err < 0) + dev_err(&client->dev, "%s: vidioc_s_ext_ctrl failed %d\n", + __func__, err); + + return err; +} + +#ifdef FACTORY_CHECK +ssize_t camtype_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + printk("%s \n", __func__); + char * sensorname = "NG"; + sensorname = "SONY_IMX072ES_CE147"; + return sprintf(buf,"%s\n", sensorname); +} + + +ssize_t camtype_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + printk(KERN_NOTICE "%s:%s\n", __func__, buf); + + return size; +} + +static DEVICE_ATTR(camtype,0644, camtype_show, camtype_store); + +extern struct class *sec_class; +struct device *sec_cam_dev = NULL; +#endif + +static int ce147_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ce147_state *state = to_state(sd); + int err = -EINVAL; + + err = ce147_load_fw(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Camera Initialization\n", + __func__); + return -EIO; + } + + ce147_init_parameters(sd); + + err = ce147_get_fw_version(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading firmware version\n", + __func__); + return -EIO; + } + + err = ce147_get_dateinfo(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading dateinfo\n", + __func__); + return -EIO; + } + + err = ce147_get_sensor_version(sd); + if (err < 0) { + dev_err(&client->dev, "%s: Failed: Reading sensor info\n", + __func__); + return -EIO; + } + pr_debug("fw M:%d m:%d |prm M:%d m:%d\n", + MAIN_SW_FW[0], MAIN_SW_FW[1], + MAIN_SW_FW[2], MAIN_SW_FW[3]); + pr_debug("y. m. d = %d.%d.%d\n", + MAIN_SW_DATE_INFO[0], MAIN_SW_DATE_INFO[1], + MAIN_SW_DATE_INFO[2]); + + err = ce147_get_main_sw_fw_version(sd); + if (err < 0) { + /*dev_err(&client->dev, "%s: Failed: Reading Main SW Version\n", + __func__);*/ + return -EIO; + } + + pr_debug("FW Version: %d.%d\n", state->fw.major, state->fw.minor); + pr_debug("PRM Version: %d.%d\n", state->prm.major, state->prm.minor); + pr_debug("Date(y.m.d): %d.%d.%d\n", state->dateinfo.year, + state->dateinfo.month, state->dateinfo.date); + pr_debug("Sensor version: %d\n", state->sensor_version); + + return 0; +} + +static const struct v4l2_subdev_core_ops ce147_core_ops = { + .init = ce147_init, /* initializing API */ + .queryctrl = ce147_queryctrl, + .querymenu = ce147_querymenu, + .g_ctrl = ce147_g_ctrl, + .s_ctrl = ce147_s_ctrl, + .s_ext_ctrls = ce147_s_ext_ctrls, +}; + +static const struct v4l2_subdev_video_ops ce147_video_ops = { + .s_crystal_freq = ce147_s_crystal_freq, + .g_mbus_fmt = ce147_g_mbus_fmt, + .s_mbus_fmt = ce147_s_mbus_fmt, + .enum_framesizes = ce147_enum_framesizes, + .enum_frameintervals = ce147_enum_frameintervals, + .enum_mbus_fmt = ce147_enum_mbus_fmt, + .try_mbus_fmt = ce147_try_mbus_fmt, + .g_parm = ce147_g_parm, + .s_parm = ce147_s_parm, +}; + +static const struct v4l2_subdev_ops ce147_ops = { + .core = &ce147_core_ops, + .video = &ce147_video_ops, +}; + +/* + * ce147_probe + * Fetching platform data is being done with s_config subdev call. + * In probe routine, we just register subdev device + */ +static int ce147_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ce147_state *state; + struct v4l2_subdev *sd; + struct ce147_platform_data *pdata = client->dev.platform_data; + + state = kzalloc(sizeof(struct ce147_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + mutex_init(&state->ctrl_lock); + + state->runmode = CE147_RUNMODE_NOTREADY; + state->pre_focus_mode = -1; + state->af_status = -2; + + sd = &state->sd; + strcpy(sd->name, CE147_DRIVER_NAME); + + /* + * Assign default format and resolution + * Use configured default information in platform data + * or without them, use default information in driver + */ + state->pix.width = pdata->default_width; + state->pix.height = pdata->default_height; + + if (!pdata->pixelformat) + state->pix.pixelformat = DEFAULT_PIX_FMT; + else + state->pix.pixelformat = pdata->pixelformat; + + if (!pdata->freq) + state->freq = DEFAULT_MCLK; /* 24MHz default */ + else + state->freq = pdata->freq; + + /* Registering subdev */ + v4l2_i2c_subdev_init(sd, client, &ce147_ops); + +#ifdef FACTORY_CHECK + { + static bool camtype_init = false; + if (sec_cam_dev == NULL) + { + sec_cam_dev = device_create(sec_class, NULL, 0, NULL, "sec_cam"); + if (IS_ERR(sec_cam_dev)) + pr_err("Failed to create device(sec_lcd_dev)!\n"); + } + + if (sec_cam_dev != NULL && camtype_init == false) + { + camtype_init = true; + if (device_create_file(sec_cam_dev, &dev_attr_camtype) < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr_camtype.attr.name); + } + } +#endif + + ce147_info(&client->dev, "5MP camera CE147 loaded.\n"); + + return 0; +} + +static int ce147_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ce147_state *state = to_state(sd); + + ce147_set_af_softlanding(sd); + + v4l2_device_unregister_subdev(sd); + mutex_destroy(&state->ctrl_lock); + kfree(to_state(sd)); + + ce147_info(&client->dev, "Unloaded camera sensor CE147.\n"); + + return 0; +} + +static const struct i2c_device_id ce147_id[] = { + { CE147_DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ce147_id); + +static struct i2c_driver v4l2_i2c_driver = { + .driver.name = CE147_DRIVER_NAME, + .probe = ce147_probe, + .remove = ce147_remove, + .id_table = ce147_id, +}; + +static int __init v4l2_i2c_drv_init(void) +{ + return i2c_add_driver(&v4l2_i2c_driver); +} + +static void __exit v4l2_i2c_drv_cleanup(void) +{ + i2c_del_driver(&v4l2_i2c_driver); +} + +module_init(v4l2_i2c_drv_init); +module_exit(v4l2_i2c_drv_cleanup); + + +MODULE_DESCRIPTION("NEC CE147-NEC 5MP camera driver"); +MODULE_AUTHOR("Tushar Behera <tushar.b@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/samsung/Kconfig b/drivers/media/video/samsung/Kconfig index 39ef521..15c0eb2 100644 --- a/drivers/media/video/samsung/Kconfig +++ b/drivers/media/video/samsung/Kconfig @@ -17,7 +17,7 @@ if CPU_S5PV210 source "drivers/media/video/samsung/fimc/Kconfig" source "drivers/media/video/samsung/mfc50/Kconfig" source "drivers/media/video/samsung/jpeg_v2/Kconfig" -#source "drivers/media/video/samsung/tv20/Kconfig" +source "drivers/media/video/samsung/tv20/Kconfig" #source "drivers/media/video/samsung/tsi/Kconfig" if CPU_S5PV210_EVT1 #source "drivers/media/video/samsung/rotator/Kconfig" diff --git a/drivers/media/video/samsung/Makefile b/drivers/media/video/samsung/Makefile index b363793..1f99c16 100644 --- a/drivers/media/video/samsung/Makefile +++ b/drivers/media/video/samsung/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_VIDEO_FIMC) += fimc/ obj-$(CONFIG_VIDEO_MFC50) += mfc50/ obj-$(CONFIG_VIDEO_JPEG_V2) += jpeg_v2/ #obj-$(CONFIG_VIDEO_ROTATOR) += rotator/ -#obj-$(CONFIG_VIDEO_TV20) += tv20/ +obj-$(CONFIG_VIDEO_TV20) += tv20/ #obj-$(CONFIG_VIDEO_G2D) += g2d/ #obj-$(CONFIG_VIDEO_TSI) += tsi/ diff --git a/drivers/media/video/samsung/fimc/fimc.h b/drivers/media/video/samsung/fimc/fimc.h index 3e61a98..b3df54d 100644 --- a/drivers/media/video/samsung/fimc/fimc.h +++ b/drivers/media/video/samsung/fimc/fimc.h @@ -65,7 +65,10 @@ #define FIMC_SCLK 1 #define FIMC_OVLY_MODE FIMC_OVLY_DMA_AUTO +#define PINGPONG_2ADDR_MODE +#if defined(PINGPONG_2ADDR_MODE) #define FIMC_PINGPONG 2 +#endif /* * ENUMERATIONS @@ -483,7 +486,7 @@ extern void fimc_dma_free(struct fimc_control *ctrl, extern u32 fimc_mapping_rot_flip(u32 rot, u32 flip); extern int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift); extern void fimc_get_nv12t_size(int img_hres, int img_vres, - int *y_size, int *cb_size); + int *y_size, int *cb_size, int rotate); extern void fimc_clk_en(struct fimc_control *ctrl, bool on); /* camera */ diff --git a/drivers/media/video/samsung/fimc/fimc_capture.c b/drivers/media/video/samsung/fimc/fimc_capture.c index 2367bf6..09a9b22 100644 --- a/drivers/media/video/samsung/fimc/fimc_capture.c +++ b/drivers/media/video/samsung/fimc/fimc_capture.c @@ -40,6 +40,9 @@ #define fimc_dbg fimc_err #endif +static int vtmode = 0; +static int device_id = 0; + static const struct v4l2_fmtdesc capture_fmts[] = { { .index = 0, @@ -257,20 +260,34 @@ static int fimc_camera_start(struct fimc_control *ctrl) struct v4l2_frmsizeenum cam_frmsize; struct v4l2_control cam_ctrl; int ret; - ret = subdev_call(ctrl, video, enum_framesizes, &cam_frmsize); if (ret < 0) { fimc_err("%s: enum_framesizes failed\n", __func__); if (ret != -ENOIOCTLCMD) return ret; } else { - ctrl->cam->width = cam_frmsize.discrete.width; - ctrl->cam->height = cam_frmsize.discrete.height; - - ctrl->cam->window.left = 0; - ctrl->cam->window.top = 0; - ctrl->cam->window.width = ctrl->cam->width; - ctrl->cam->window.height = ctrl->cam->height; + if (vtmode == 1 && device_id != 0 && (ctrl->cap->rotate == 90 || ctrl->cap->rotate == 270)) { + ctrl->cam->window.left = 136; + ctrl->cam->window.top = 0; + ctrl->cam->window.width = 368; + ctrl->cam->window.height = 480; + ctrl->cam->width = cam_frmsize.discrete.width; + ctrl->cam->height = cam_frmsize.discrete.height; + dev_err(ctrl->dev, "vtmode = 1, rotate = %d, device = front, cam->width = %d, cam->height = %d\n", ctrl->cap->rotate, ctrl->cam->width, ctrl->cam->height); + } else if (device_id != 0 && vtmode != 1) { + ctrl->cam->window.left = 136; + ctrl->cam->window.top = 0; + ctrl->cam->window.width = 368; + ctrl->cam->window.height = 480; + ctrl->cam->width = cam_frmsize.discrete.width; + ctrl->cam->height = cam_frmsize.discrete.height; + dev_err(ctrl->dev, "%s, crop(368x480), vtmode = 0, device = front, cam->width = %d, cam->height = %d\n", __func__, ctrl->cam->width, ctrl->cam->height); + } else { + ctrl->cam->window.left = 0; + ctrl->cam->window.top = 0; + ctrl->cam->window.width = ctrl->cam->width; + ctrl->cam->window.height = ctrl->cam->height; + } } cam_ctrl.id = V4L2_CID_CAM_PREVIEW_ONOFF; @@ -389,34 +406,19 @@ static int fimc_add_outqueue(struct fimc_control *ctrl, int i) struct fimc_capinfo *cap = ctrl->cap; struct fimc_buf_set *buf; - unsigned int mask = 0x2; + if (cap->nr_bufs > FIMC_PHYBUFS) { + if (list_empty(&cap->inq)) + return -ENOENT; - /* PINGPONG_2ADDR_MODE Only */ - /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */ - - int pair_buf_index = (i^mask); - - /* FIMC have 4 h/w registers */ - if (i < 0 || i >= FIMC_PHYBUFS) { - fimc_err("%s: invalid queue index : %d\n", __func__, i); - return -ENOENT; + buf = list_first_entry(&cap->inq, struct fimc_buf_set, list); + list_del(&buf->list); + } else { + buf = &cap->bufs[i]; } - if (list_empty(&cap->inq)) - return -ENOENT; - - buf = list_first_entry(&cap->inq, struct fimc_buf_set, list); - - /* pair index buffer should be allocated first */ - cap->outq[pair_buf_index] = buf->id; - fimc_hwset_output_address(ctrl, buf, pair_buf_index); - cap->outq[i] = buf->id; fimc_hwset_output_address(ctrl, buf, i); - if (cap->nr_bufs != 1) - list_del(&buf->list); - return 0; } @@ -424,7 +426,7 @@ static int fimc_update_hwaddr(struct fimc_control *ctrl) { int i; - for (i = 0; i < FIMC_PINGPONG; i++) + for (i = 0; i < FIMC_PHYBUFS; i++) fimc_add_outqueue(ctrl, i); return 0; @@ -705,6 +707,7 @@ int fimc_enum_fmt_vid_capture(struct file *file, void *fh, return ret; } + memset(f, 0, sizeof(*f)); memcpy(f, &capture_fmts[i], sizeof(*f)); return 0; @@ -723,6 +726,7 @@ int fimc_g_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) mutex_lock(&ctrl->v4l2_lock); + memset(&f->fmt.pix, 0, sizeof(f->fmt.pix)); memcpy(&f->fmt.pix, &ctrl->cap->fmt, sizeof(f->fmt.pix)); mutex_unlock(&ctrl->v4l2_lock); @@ -823,20 +827,23 @@ int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) * released at the file close. * Anyone has better idea to do this? */ - mutex_lock(&ctrl->v4l2_lock); - - if (!ctrl->cap) { - ctrl->cap = kmalloc(sizeof(*cap), GFP_KERNEL); - if (!ctrl->cap) { - mutex_unlock(&ctrl->v4l2_lock); + if (!cap) { + cap = kzalloc(sizeof(*cap), GFP_KERNEL); + if (!cap) { fimc_err("%s: no memory for " "capture device info\n", __func__); return -ENOMEM; } + /* assign to ctrl */ + ctrl->cap = cap; + } else { + memset(cap, 0, sizeof(*cap)); } - cap = ctrl->cap; - memset(cap, 0, sizeof(*cap)); + + mutex_lock(&ctrl->v4l2_lock); + + memset(&cap->fmt, 0, sizeof(cap->fmt)); memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt)); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, 0); @@ -936,7 +943,7 @@ static void fimc_free_buffers(struct fimc_control *ctrl) return; - for (i = 0; i < cap->nr_bufs; i++) { + for (i = 0; i < FIMC_PHYBUFS; i++) { memset(&cap->bufs[i], 0, sizeof(cap->bufs[i])); cap->bufs[i].state = VIDEOBUF_NEEDS_INIT; } @@ -1214,6 +1221,11 @@ int fimc_s_ctrl_capture(void *fh, struct v4l2_control *c) ret = 0; break; + case V4L2_CID_CAMERA_VT_MODE: + vtmode = c->value; + ret = subdev_call(ctrl, core, s_ctrl, c); + break; + default: /* try on subdev */ mutex_unlock(&ctrl->v4l2_lock); @@ -1509,7 +1521,7 @@ static void fimc_reset_capture(struct fimc_control *ctrl) fimc_stop_capture(ctrl); - for (i = 0; i < FIMC_PINGPONG; i++) + for (i = 0; i < FIMC_PHYBUFS; i++) fimc_add_inqueue(ctrl, ctrl->cap->outq[i]); fimc_hwset_reset(ctrl); @@ -1525,10 +1537,14 @@ int fimc_streamon_capture(void *fh) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; struct fimc_capinfo *cap = ctrl->cap; + struct v4l2_frmsizeenum cam_frmsize; int rot; int ret; fimc_dbg("%s\n", __func__); + char *ce147 = "CE147 0-003c"; + device_id = strcmp(ctrl->cam->sd->name, ce147); + fimc_dbg("%s, name(%s), device_id(%d), vtmode(%d)\n", __func__, ctrl->cam->sd->name , device_id, vtmode); if (!ctrl->cam || !ctrl->cam->sd) { fimc_err("%s: No capture device.\n", __func__); @@ -1553,6 +1569,36 @@ int fimc_streamon_capture(void *fh) if (!ctrl->cam->initialized) fimc_camera_init(ctrl); + ret = subdev_call(ctrl, video, enum_framesizes, &cam_frmsize); + if (ret < 0) { + dev_err(ctrl->dev, "%s: enum_framesizes failed\n", __func__); + if(ret != -ENOIOCTLCMD) + return ret; + } else { + if (vtmode == 1 && device_id != 0 && (cap->rotate == 90 || cap->rotate == 270)) { + ctrl->cam->window.left = 136; + ctrl->cam->window.top = 0;// + ctrl->cam->window.width = 368; + ctrl->cam->window.height = 480; + ctrl->cam->width = cam_frmsize.discrete.width; + ctrl->cam->height = cam_frmsize.discrete.height; + dev_err(ctrl->dev, "vtmode = 1, rotate = %d, device = front, cam->width = %d, cam->height = %d\n", cap->rotate, ctrl->cam->width, ctrl->cam->height); + } else if (device_id != 0 && vtmode != 1) { + ctrl->cam->window.left = 136; + ctrl->cam->window.top = 0; + ctrl->cam->window.width = 368; + ctrl->cam->window.height = 480; + ctrl->cam->width = cam_frmsize.discrete.width; + ctrl->cam->height =cam_frmsize.discrete.height; + dev_err(ctrl->dev, "%s, crop(368x480), vtmode = 0, device = front, cam->width = %d, cam->height = %d\n", __func__, ctrl->cam->width, ctrl->cam->height); + } else { + ctrl->cam->window.left = 0; + ctrl->cam->window.top = 0; + ctrl->cam->width = ctrl->cam->window.width = cam_frmsize.discrete.width; + ctrl->cam->height = ctrl->cam->window.height = cam_frmsize.discrete.height; + } + } + if (ctrl->id != 2 && ctrl->cap->fmt.colorspace != V4L2_COLORSPACE_JPEG) { ret = fimc_camera_start(ctrl); @@ -1587,6 +1633,11 @@ int fimc_streamon_capture(void *fh) fimc_hwset_output_size(ctrl, cap->fmt.width, cap->fmt.height); + if ((device_id != 0) && (vtmode != 1)) { + ctrl->cap->rotate = 90; + dev_err(ctrl->dev, "%s, rotate 90", __func__); + } + fimc_hwset_output_scan(ctrl, &cap->fmt); fimc_hwset_output_rot_flip(ctrl, cap->rotate, cap->flip); rot = fimc_mapping_rot_flip(cap->rotate, cap->flip); @@ -1654,19 +1705,16 @@ int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; - if (!ctrl->cap || !ctrl->cap->nr_bufs) { - fimc_err("%s: Invalid capture setting.\n", __func__); - return -EINVAL; - } - if (b->memory != V4L2_MEMORY_MMAP) { fimc_err("%s: invalid memory type\n", __func__); return -EINVAL; } - mutex_lock(&ctrl->v4l2_lock); - fimc_add_inqueue(ctrl, b->index); - mutex_unlock(&ctrl->v4l2_lock); + if (ctrl->cap->nr_bufs > FIMC_PHYBUFS) { + mutex_lock(&ctrl->v4l2_lock); + fimc_add_inqueue(ctrl, b->index); + mutex_unlock(&ctrl->v4l2_lock); + } return 0; } @@ -1698,7 +1746,7 @@ int fimc_dqbuf_capture(void *fh, struct v4l2_buffer *b) } /* find out the real index */ - pp = ((fimc_hwget_frame_count(ctrl) + 2) % 4); + pp = ((fimc_hwget_frame_count(ctrl) + 2) % 4) % cap->nr_bufs; /* We have read the latest frame, hence should reset availability * flag @@ -1709,14 +1757,16 @@ int fimc_dqbuf_capture(void *fh, struct v4l2_buffer *b) if (cap->fmt.field == V4L2_FIELD_INTERLACED_TB) pp &= ~0x1; + if (cap->nr_bufs > FIMC_PHYBUFS) { b->index = cap->outq[pp]; - fimc_dbg("%s: buffer(%d) outq[%d]\n", __func__, b->index, pp); - ret = fimc_add_outqueue(ctrl, pp); if (ret) { b->index = -1; fimc_err("%s: no inqueue buffer\n", __func__); } + } else { + b->index = pp; + } mutex_unlock(&ctrl->v4l2_lock); diff --git a/drivers/media/video/samsung/fimc/fimc_dev.c b/drivers/media/video/samsung/fimc/fimc_dev.c index 1441367..2554d7e 100644 --- a/drivers/media/video/samsung/fimc/fimc_dev.c +++ b/drivers/media/video/samsung/fimc/fimc_dev.c @@ -797,7 +797,7 @@ int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) } void fimc_get_nv12t_size(int img_hres, int img_vres, - int *y_size, int *cb_size) + int *y_size, int *cb_size, int rotate) { int remain; int y_hres_byte, y_vres_byte; @@ -805,6 +805,12 @@ void fimc_get_nv12t_size(int img_hres, int img_vres, int y_hres_roundup, y_vres_roundup; int cb_hres_roundup, cb_vres_roundup; + if (rotate == 90 || rotate == 270) { + int tmp = img_hres; + img_hres = img_vres; + img_vres = tmp; + } + /* to make 'img_hres and img_vres' be 16 multiple */ remain = img_hres % 16; if (remain != 0) { diff --git a/drivers/media/video/samsung/fimc/fimc_output.c b/drivers/media/video/samsung/fimc/fimc_output.c index c66f995..98ff74e 100644 --- a/drivers/media/video/samsung/fimc/fimc_output.c +++ b/drivers/media/video/samsung/fimc/fimc_output.c @@ -226,7 +226,7 @@ static int fimc_outdev_set_src_buf(struct fimc_control *ctrl, size = PAGE_ALIGN(y_size + cb_size); break; case V4L2_PIX_FMT_NV12T: - fimc_get_nv12t_size(width, height, &y_size, &cb_size); + fimc_get_nv12t_size(width, height, &y_size, &cb_size, 0); size = PAGE_ALIGN(y_size + cb_size); break; case V4L2_PIX_FMT_NV16: @@ -1774,7 +1774,7 @@ int fimc_output_set_dst_addr(struct fimc_control *ctrl, memset(&buf_set, 0x00, sizeof(buf_set)); if (V4L2_PIX_FMT_NV12T == format) - fimc_get_nv12t_size(width, height, &y_size, &c_size); + fimc_get_nv12t_size(width, height, &y_size, &c_size, ctx->rotate); switch (format) { case V4L2_PIX_FMT_RGB32: diff --git a/drivers/media/video/samsung/fimc/fimc_v4l2.c b/drivers/media/video/samsung/fimc/fimc_v4l2.c index 3632ded..73202f4 100644 --- a/drivers/media/video/samsung/fimc/fimc_v4l2.c +++ b/drivers/media/video/samsung/fimc/fimc_v4l2.c @@ -81,8 +81,15 @@ static int fimc_querybuf(struct file *filp, void *fh, struct v4l2_buffer *b) static int fimc_g_ctrl(struct file *filp, void *fh, struct v4l2_control *c) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); int ret = -1; + /* can get hw version at any time */ + if (c->id == V4L2_CID_FIMC_VERSION) { + c->value = pdata->hw_ver; + return 0; + } + if (ctrl->cap != NULL) { ret = fimc_g_ctrl_capture(fh, c); } else if (ctrl->out != NULL) { diff --git a/drivers/media/video/samsung/mfc50/mfc.c b/drivers/media/video/samsung/mfc50/mfc.c index 17a9da8..5472c9d 100755 --- a/drivers/media/video/samsung/mfc50/mfc.c +++ b/drivers/media/video/samsung/mfc50/mfc.c @@ -49,6 +49,9 @@ #include <plat/media.h> #include <mach/media.h> #include <plat/mfc.h> +#ifdef CONFIG_DVFS_LIMIT +#include <mach/cpu-freq-v210.h> +#endif #include "mfc_interface.h" #include "mfc_logmsg.h" @@ -81,6 +84,9 @@ static int mfc_open(struct inode *inode, struct file *file) goto err_open; } +#ifdef CONFIG_DVFS_LIMIT + s5pv210_lock_dvfs_high_level(DVFS_LOCK_TOKEN_1, L2); +#endif clk_enable(mfc_sclk); mfc_load_firmware(mfc_fw_info->data, mfc_fw_info->size); @@ -133,6 +139,9 @@ err_mem_inst: kfree(mfc_ctx); err_regulator: if (!mfc_is_running()) { +#ifdef CONFIG_DVFS_LIMIT + s5pv210_unlock_dvfs_high_level(DVFS_LOCK_TOKEN_1); +#endif /* Turn off mfc power domain regulator */ ret = regulator_disable(mfc_pd_regulator); if (ret < 0) @@ -175,6 +184,9 @@ static int mfc_release(struct inode *inode, struct file *file) ret = 0; if (!mfc_is_running()) { +#ifdef CONFIG_DVFS_LIMIT + s5pv210_unlock_dvfs_high_level(DVFS_LOCK_TOKEN_1); +#endif /* Turn off mfc power domain regulator */ ret = regulator_disable(mfc_pd_regulator); if (ret < 0) { diff --git a/drivers/media/video/samsung/tv20/Kconfig b/drivers/media/video/samsung/tv20/Kconfig new file mode 100644 index 0000000..e839ebc --- /dev/null +++ b/drivers/media/video/samsung/tv20/Kconfig @@ -0,0 +1,51 @@ +# +# Configuration for TV-OUT/HDMI +# + +config VIDEO_TV20 + bool "Samsung TV Driver" + depends on VIDEO_SAMSUNG + default y + ---help--- + This is a TV driver for Samsung S5P platform + +config HDMI_CEC + bool "HDMI CEC driver support." + depends on VIDEO_TV20 && CPU_S5PV210 + default n + ---help--- + This is a HDMI CEC driver for Samsung SMDK_S5PV210 + Check dev node (major 10, minor 242) + +config HDMI_HPD + bool "HDMI HPD driver support." + depends on VIDEO_TV20 && CPU_S5PV210 + default n + ---help--- + This is a HDMI HPD driver for Samsung SMDK_S5PV210 + Check dev node (major 10, minor 243) + +config TV_FB + bool "TV frame buffer driver support." + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + + depends on VIDEO_TV20 && FB && CPU_S5PV210 + default n + ---help--- + +config USER_ALLOC_TVOUT + bool "Support pre allocated frame buffer memory." + depends on VIDEO_TV20 && TV_FB + default n + ---help--- + TV Driver doesn't allocate memory for frame buffer. + So, before enabling TV out, the frame buffer should be allocated. + +config TV_FB_NUM + int "Index of TV frame buffer" + depends on VIDEO_TV20 && TV_FB && !USER_ALLOC_TVOUT + default 5 + ---help--- + diff --git a/drivers/media/video/samsung/tv20/Makefile b/drivers/media/video/samsung/tv20/Makefile new file mode 100644 index 0000000..3cd0c92 --- /dev/null +++ b/drivers/media/video/samsung/tv20/Makefile @@ -0,0 +1,50 @@ +################################################# +# Makefile for TVOut for S5PC100 +# 2010 (C) Samsung Electronics +# Author : sangpil moon <sangpil.moon@samsung.com> +################################################# + +obj-$(CONFIG_VIDEO_TV20) += s5p_tvout.o + +s5p_tvout-y += ddc.o + +ifeq ($(CONFIG_HDMI_HPD), y) +s5p_tvout-y += hpd.o +endif + +ifeq ($(CONFIG_HDMI_CEC), y) +s5p_tvout-y += cec.o \ + s5pv210/cec_s5pv210.o +endif + +ifeq ($(CONFIG_CPU_S5PC100), y) +s5p_tvout-y += s5pc100/hdcp_s5pc100.o \ + s5pc100/hdmi_s5pc100.o \ + s5pc100/sdout_s5pc100.o \ + s5pc100/tv_power_s5pc100.o \ + s5pc100/vmixer_s5pc100.o \ + s5pc100/vprocessor_s5pc100.o \ + s5pc100/tv_clock_s5pc100.o +endif + + +ifeq ($(CONFIG_CPU_S5PV210), y) +s5p_tvout-y += s5pv210/hdcp_s5pv210.o \ + s5pv210/hdmi_s5pv210.o \ + s5pv210/sdout_s5pv210.o \ + s5pv210/tv_power_s5pv210.o \ + s5pv210/vmixer_s5pv210.o \ + s5pv210/vprocessor_s5pv210.o +endif + + +s5p_tvout-y += s5p_stda_tvout_if.o \ + s5p_stda_grp.o \ + s5p_stda_hdmi.o \ + s5p_stda_video_layer.o \ + s5p_tv_v4l2.o \ + s5p_tv_base.o + +ifeq ($(CONFIG_VIDEO_TV20_DEBUG), y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/media/video/samsung/tv20/cec.c b/drivers/media/video/samsung/tv20/cec.c new file mode 100644 index 0000000..1422823 --- /dev/null +++ b/drivers/media/video/samsung/tv20/cec.c @@ -0,0 +1,426 @@ +/* linux/drivers/media/video/samsung/tv20/cec.c + * + * cec interface file for Samsung TVOut driver (only s5pv210) + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/errno.h> +#include <linux/wait.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/uaccess.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/regs-gpio.h> + +#include "s5p_tv.h" +#include "cec.h" + +/*#define CECDEBUG*/ +#ifdef CECDEBUG +#define CECIFPRINTK(fmt, args...) \ + printk(KERN_INFO "\t[CEC_IF] %s: " fmt, __func__ , ## args) +#else +#define CECIFPRINTK(fmt, args...) +#endif + +static struct cec_rx_struct cec_rx_struct; +static struct cec_tx_struct cec_tx_struct; + +static bool hdmi_on; + +/** + * Change CEC Tx state to state + * @param state [in] new CEC Tx state. + */ +void __s5p_cec_set_tx_state(enum cec_state state) +{ + atomic_set(&cec_tx_struct.state, state); +} + +/** + * Change CEC Rx state to @c state. + * @param state [in] new CEC Rx state. + */ +void __s5p_cec_set_rx_state(enum cec_state state) +{ + atomic_set(&cec_rx_struct.state, state); +} + + +int s5p_cec_open(struct inode *inode, struct file *file) +{ + s5p_tv_clk_gate(true); + + hdmi_on = true; + + __s5p_cec_reset(); + + __s5p_cec_set_divider(); + + __s5p_cec_threshold(); + + __s5p_cec_unmask_tx_interrupts(); + + __s5p_cec_set_rx_state(STATE_RX); + __s5p_cec_unmask_rx_interrupts(); + __s5p_cec_enable_rx(); + + return 0; +} + +int s5p_cec_release(struct inode *inode, struct file *file) +{ + s5p_tv_clk_gate(false); + + hdmi_on = false; + + __s5p_cec_mask_tx_interrupts(); + __s5p_cec_mask_rx_interrupts(); + + + return 0; +} + +ssize_t s5p_cec_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) +{ + ssize_t retval; + + if (wait_event_interruptible(cec_rx_struct.waitq, + atomic_read(&cec_rx_struct.state) + == STATE_DONE)) { + return -ERESTARTSYS; + } + + spin_lock_irq(&cec_rx_struct.lock); + + if (cec_rx_struct.size > count) { + spin_unlock_irq(&cec_rx_struct.lock); + return -1; + } + + if (copy_to_user(buffer, cec_rx_struct.buffer, cec_rx_struct.size)) { + spin_unlock_irq(&cec_rx_struct.lock); + printk(KERN_ERR " copy_to_user() failed!\n"); + return -EFAULT; + } + + retval = cec_rx_struct.size; + + __s5p_cec_set_rx_state(STATE_RX); + spin_unlock_irq(&cec_rx_struct.lock); + + return retval; +} + +ssize_t s5p_cec_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char *data; + + /* check data size */ + + if (count > CEC_TX_BUFF_SIZE || count == 0) + return -1; + + data = kmalloc(count, GFP_KERNEL); + + if (!data) { + printk(KERN_ERR " kmalloc() failed!\n"); + return -1; + } + + if (copy_from_user(data, buffer, count)) { + printk(KERN_ERR " copy_from_user() failed!\n"); + kfree(data); + return -EFAULT; + } + + __s5p_cec_copy_packet(data, count); + + kfree(data); + + /* wait for interrupt */ + if (wait_event_interruptible(cec_tx_struct.waitq, + atomic_read(&cec_tx_struct.state) + != STATE_TX)) { + return -ERESTARTSYS; + } + + if (atomic_read(&cec_tx_struct.state) == STATE_ERROR) + return -1; + + return count; +} + +int s5p_cec_ioctl(struct inode *inode, struct file *file, u32 cmd, + unsigned long arg) +{ + u32 laddr; + + switch (cmd) { + + case CEC_IOC_SETLADDR: + CECIFPRINTK("ioctl(CEC_IOC_SETLADDR)\n"); + + if (get_user(laddr, (u32 __user *) arg)) + return -EFAULT; + + CECIFPRINTK("logical address = 0x%02x\n", laddr); + + __s5p_cec_set_addr(laddr); + + break; + + default: + return -EINVAL; + } + + return 0; +} + +u32 s5p_cec_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &cec_rx_struct.waitq, wait); + + if (atomic_read(&cec_rx_struct.state) == STATE_DONE) + return POLLIN | POLLRDNORM; + + return 0; +} + +static const struct file_operations cec_fops = { + .owner = THIS_MODULE, + .open = s5p_cec_open, + .release = s5p_cec_release, + .read = s5p_cec_read, + .write = s5p_cec_write, + .ioctl = s5p_cec_ioctl, + .poll = s5p_cec_poll, +}; + +static struct miscdevice cec_misc_device = { + .minor = CEC_MINOR, + .name = "CEC", + .fops = &cec_fops, +}; + + +/** + * @brief CEC interrupt handler + * + * Handles interrupt requests from CEC hardware. \n + * Action depends on current state of CEC hardware. + */ +irqreturn_t s5p_cec_irq_handler(int irq, void *dev_id) +{ + + u32 status = 0; + + /* read flag register */ + + + /* is this our interrupt? */ +/* + if (!(flag & (1 << HDMI_IRQ_CEC))) { + return IRQ_NONE; + } +*/ + status = __s5p_cec_get_status(); + + if (status & CEC_STATUS_TX_DONE) { + if (status & CEC_STATUS_TX_ERROR) { + CECIFPRINTK(" CEC_STATUS_TX_ERROR!\n"); + __s5p_cec_set_tx_state(STATE_ERROR); + } else { + CECIFPRINTK(" CEC_STATUS_TX_DONE!\n"); + __s5p_cec_set_tx_state(STATE_DONE); + } + + __s5p_clr_pending_tx(); + + + wake_up_interruptible(&cec_tx_struct.waitq); + } + + if (status & CEC_STATUS_RX_DONE) { + if (status & CEC_STATUS_RX_ERROR) { + CECIFPRINTK(" CEC_STATUS_RX_ERROR!\n"); + __s5p_cec_rx_reset(); + + } else { + u32 size; + + CECIFPRINTK(" CEC_STATUS_RX_DONE!\n"); + + /* copy data from internal buffer */ + size = status >> 24; + + spin_lock(&cec_rx_struct.lock); + + __s5p_cec_get_rx_buf(size, cec_rx_struct.buffer); + + cec_rx_struct.size = size; + + __s5p_cec_set_rx_state(STATE_DONE); + + spin_unlock(&cec_rx_struct.lock); + + __s5p_cec_enable_rx(); + } + + /* clear interrupt pending bit */ + __s5p_clr_pending_rx(); + + + wake_up_interruptible(&cec_rx_struct.waitq); + } + + return IRQ_HANDLED; +} + +static int __init s5p_cec_probe(struct platform_device *pdev) +{ + u8 *buffer; + int irq_num; + int ret; + + s3c_gpio_cfgpin(S5PV210_GPH1(4), S3C_GPIO_SFN(0x4)); + s3c_gpio_setpull(S5PV210_GPH1(4), S3C_GPIO_PULL_NONE); + + /* get ioremap addr */ + __s5p_cec_probe(pdev); + + if (misc_register(&cec_misc_device)) { + printk(KERN_WARNING " Couldn't register device 10, %d.\n", + CEC_MINOR); + return -EBUSY; + } + + irq_num = platform_get_irq(pdev, 0); + if (irq_num < 0) { + printk(KERN_ERR "failed to get %s irq resource\n", "cec"); + ret = -ENOENT; + return ret; + } + + ret = request_irq(irq_num, s5p_cec_irq_handler, IRQF_DISABLED, + pdev->name, &pdev->id); + if (ret != 0) { + printk(KERN_ERR "failed to install %s irq (%d)\n", "cec", ret); + return ret; + } + + + init_waitqueue_head(&cec_rx_struct.waitq); + spin_lock_init(&cec_rx_struct.lock); + init_waitqueue_head(&cec_tx_struct.waitq); + + buffer = kmalloc(CEC_TX_BUFF_SIZE, GFP_KERNEL); + + if (!buffer) { + printk(KERN_ERR " kmalloc() failed!\n"); + misc_deregister(&cec_misc_device); + return -EIO; + } + + cec_rx_struct.buffer = buffer; + + cec_rx_struct.size = 0; + + return 0; +} + +/* + * Remove + */ +static int s5p_cec_remove(struct platform_device *pdev) +{ + return 0; +} + +#ifdef CONFIG_PM +/* + * Suspend + */ +int s5p_cec_suspend(struct platform_device *dev, pm_message_t state) +{ + if (hdmi_on) + s5p_tv_clk_gate(false); + + return 0; +} + +/* + * Resume + */ +int s5p_cec_resume(struct platform_device *dev) +{ + if (hdmi_on) + s5p_tv_clk_gate(true); + + return 0; +} +#else +#define s5p_cec_suspend NULL +#define s5p_cec_resume NULL +#endif + +static struct platform_driver s5p_cec_driver = { + .probe = s5p_cec_probe, + .remove = s5p_cec_remove, + .suspend = s5p_cec_suspend, + .resume = s5p_cec_resume, + .driver = { + .name = "s5p-cec", + .owner = THIS_MODULE, + }, +}; + +static char banner[] __initdata = + "S5P CEC Driver, (c) 2010 Samsung Electronics\n"; + +int __init s5p_cec_init(void) +{ + int ret; + + printk(banner); + + ret = platform_driver_register(&s5p_cec_driver); + + if (ret) { + printk(KERN_ERR "Platform Device Register Failed %d\n", ret); + return -1; + } + + return 0; +} + +static void __exit s5p_cec_exit(void) +{ + kfree(cec_rx_struct.buffer); + + platform_driver_unregister(&s5p_cec_driver); + +} + +module_init(s5p_cec_init); +module_exit(s5p_cec_exit); + +MODULE_AUTHOR("SangPil Moon"); +MODULE_DESCRIPTION("SS5PC11X CEC driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/video/samsung/tv20/cec.h b/drivers/media/video/samsung/tv20/cec.h new file mode 100644 index 0000000..58bcc6b --- /dev/null +++ b/drivers/media/video/samsung/tv20/cec.h @@ -0,0 +1,104 @@ +/* linux/drivers/media/video/samsung/tv20/cec.h + * + * cec interface header for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +/*#define CECDEBUG 1*/ + +#include <linux/platform_device.h> + +#define VERSION "1.0" /* Driver version number */ +#define CEC_MINOR 242 /* Major 10, Minor 242, /dev/cec */ + +#define CEC_MESSAGE_BROADCAST_MASK 0x0F +#define CEC_MESSAGE_BROADCAST 0x0F + +#define CEC_FILTER_THRESHOLD 0x15 + +/* + * @enum cec_state + * Defines all possible states of CEC software state machine + */ +enum cec_state { + STATE_RX, + STATE_TX, + STATE_DONE, + STATE_ERROR +}; + +/* + * @struct cec_rx_struct + * Holds CEC Rx state and data + */ + +struct cec_rx_struct { + spinlock_t lock; + wait_queue_head_t waitq; + atomic_t state; + u8 *buffer; + unsigned int size; +}; + +/* + * @struct cec_tx_struct + * Holds CEC Tx state and data + */ + +struct cec_tx_struct { + wait_queue_head_t waitq; + atomic_t state; +}; + +#define CEC_STATUS_TX_RUNNING (1<<0) +#define CEC_STATUS_TX_TRANSFERRING (1<<1) +#define CEC_STATUS_TX_DONE (1<<2) +#define CEC_STATUS_TX_ERROR (1<<3) +#define CEC_STATUS_TX_BYTES (0xFF<<8) +#define CEC_STATUS_RX_RUNNING (1<<16) +#define CEC_STATUS_RX_RECEIVING (1<<17) +#define CEC_STATUS_RX_DONE (1<<18) +#define CEC_STATUS_RX_ERROR (1<<19) +#define CEC_STATUS_RX_BCAST (1<<20) +#define CEC_STATUS_RX_BYTES (0xFF<<24) + + +#define CEC_IOC_MAGIC 'c' + +/* + * CEC device request code to set logical address. + */ +#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int) + + +/* CEC Rx buffer size */ +#define CEC_RX_BUFF_SIZE 16 +/* CEC Tx buffer size */ +#define CEC_TX_BUFF_SIZE 16 + +extern void __s5p_cec_set_divider(void); +extern void __s5p_cec_enable_rx(void); +extern void __s5p_cec_mask_rx_interrupts(void); +extern void __s5p_cec_unmask_rx_interrupts(void); +extern void __s5p_cec_mask_tx_interrupts(void); +extern void __s5p_cec_unmask_tx_interrupts(void); +extern void __s5p_cec_set_tx_state(enum cec_state state); +extern void __s5p_cec_set_rx_state(enum cec_state state); +extern void __s5p_cec_reset(void); +extern void __s5p_cec_tx_reset(void); +extern void __s5p_cec_rx_reset(void); +extern void __s5p_cec_threshold(void); +extern void __s5p_cec_copy_packet(char *data, size_t count); +extern void __s5p_cec_set_addr(u32 addr); +extern u32 __s5p_cec_get_status(void); +extern void __s5p_clr_pending_tx(void); +extern void __s5p_clr_pending_rx(void); +extern void __s5p_cec_get_rx_buf(u32 size, u8 *buffer); +extern void __init __s5p_cec_probe(struct platform_device *pdev); + diff --git a/drivers/media/video/samsung/tv20/ddc.c b/drivers/media/video/samsung/tv20/ddc.c new file mode 100644 index 0000000..2f949bc --- /dev/null +++ b/drivers/media/video/samsung/tv20/ddc.c @@ -0,0 +1,133 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> + +#define I2C_DRIVERID_S5P_HDCP 510 +#define S5P_HDCP_I2C_ADDR 0x74 + +const static u16 ignore[] = { I2C_CLIENT_END }; +const static u16 normal_addr[] = { + (S5P_HDCP_I2C_ADDR >> 1), + I2C_CLIENT_END +}; + +struct i2c_client *ddc_port; + +/* + * DDC read ftn. + */ +int ddc_read(u8 subaddr, u8 *data, u16 len) +{ + u8 addr = subaddr; + int ret = 0; + + struct i2c_msg msg[] = { + [0] = { + .addr = ddc_port->addr, + .flags = 0, + .len = 1, + .buf = &addr + }, + [1] = { + .addr = ddc_port->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data + } + }; + + if (i2c_transfer(ddc_port->adapter, msg, 2) != 2) + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(ddc_read); + + +/* + * DDC_write ftn. + */ +int ddc_write(u8 *data, u16 len) +{ + int ret = 0; + + if (i2c_master_send(ddc_port, (const char *) data, len) != len) + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(ddc_write); + +/* + * i2c client ftn. + */ +static int __devinit ddc_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int ret = 0; + + ddc_port = client; + + dev_info(&client->adapter->dev, "attached s5p_ddc " + "into i2c adapter successfully\n"); + + return ret; +} + +static int ddc_remove(struct i2c_client *client) +{ + dev_info(&client->adapter->dev, "detached s5p_ddc " + "from i2c adapter successfully\n"); + + return 0; +} + +static int ddc_suspend(struct i2c_client *cl, pm_message_t mesg) +{ + return 0; +}; + +static int ddc_resume(struct i2c_client *cl) +{ + return 0; +}; + + +static struct i2c_device_id ddc_idtable[] = { + {"s5p_ddc", 0}, +}; + +MODULE_DEVICE_TABLE(i2c, ddc_idtable); + +static struct i2c_driver ddc_driver = { + .driver = { + .name = "s5p_ddc", + }, + .id_table = ddc_idtable, + .probe = ddc_probe, + .remove = __devexit_p(ddc_remove), + .address_list = &normal_addr, + .suspend = ddc_suspend, + .resume = ddc_resume, +}; + +static int __init ddc_init(void) +{ + return i2c_add_driver(&ddc_driver); +} + +static void __exit ddc_exit(void) +{ + i2c_del_driver(&ddc_driver); +} + + +MODULE_AUTHOR("SangPil Moon <sangpil.moon@samsung.com>"); +MODULE_DESCRIPTION("Driver for SMDKV210 I2C DDC devices"); + +MODULE_LICENSE("GPL"); + +module_init(ddc_init); +module_exit(ddc_exit); + + diff --git a/drivers/media/video/samsung/tv20/ddc.h b/drivers/media/video/samsung/tv20/ddc.h new file mode 100644 index 0000000..8e6982b --- /dev/null +++ b/drivers/media/video/samsung/tv20/ddc.h @@ -0,0 +1,7 @@ +/* + * i2c ddc port + */ + + +extern int ddc_read(u8 subaddr, u8 *data, u16 len); +extern int ddc_write(u8 *data, u16 len); diff --git a/drivers/media/video/samsung/tv20/hpd.c b/drivers/media/video/samsung/tv20/hpd.c new file mode 100644 index 0000000..0edb72c --- /dev/null +++ b/drivers/media/video/samsung/tv20/hpd.c @@ -0,0 +1,394 @@ +/* linux/drivers/media/video/samsung/tv20/hpd.c + * + * hpd interface ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/errno.h> +#include <linux/wait.h> +#include <linux/poll.h> +#include <linux/irq.h> +#include <linux/kobject.h> +#include <linux/io.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/gpio-p1.h> +#include <mach/regs-gpio.h> +#include <mach/gpio.h> +#include "s5p_tv.h" +#include "hpd.h" + +/*#define HPDDEBUG*/ +#ifdef HPDDEBUG +#define HPDIFPRINTK(fmt, args...) \ + printk(KERN_INFO "[HPD_IF] %s: " fmt, __func__ , ## args) +#else +#define HPDIFPRINTK(fmt, args...) +#endif + +static struct hpd_struct hpd_struct; + +static int last_hpd_state; +atomic_t hdmi_status; +atomic_t poll_state; + +static DECLARE_WORK(hpd_work, (void *)s5p_handle_cable); + +int s5p_hpd_get_state(void) +{ + return atomic_read(&hpd_struct.state); +} + +int s5p_hpd_open(struct inode *inode, struct file *file) +{ + atomic_set(&poll_state, 1); + + return 0; +} + +int s5p_hpd_release(struct inode *inode, struct file *file) +{ + return 0; +} + +ssize_t s5p_hpd_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) +{ + ssize_t retval; + + spin_lock_irq(&hpd_struct.lock); + + retval = put_user(atomic_read(&hpd_struct.state), + (unsigned int __user *) buffer); + + atomic_set(&poll_state, -1); + + spin_unlock_irq(&hpd_struct.lock); + + return retval; +} + +unsigned int s5p_hpd_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &hpd_struct.waitq, wait); + + if (atomic_read(&poll_state) != -1) + return POLLIN | POLLRDNORM; + + return 0; +} + +static const struct file_operations hpd_fops = { + .owner = THIS_MODULE, + .open = s5p_hpd_open, + .release = s5p_hpd_release, + .read = s5p_hpd_read, + .poll = s5p_hpd_poll, +}; + +static struct miscdevice hpd_misc_device = { + HPD_MINOR, + "HPD", + &hpd_fops, +}; + +int s5p_hpd_set_hdmiint(void) +{ + /* EINT -> HDMI */ + + set_irq_type(IRQ_EINT13, IRQ_TYPE_NONE); + + if (last_hpd_state) + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG); + else + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG); + + atomic_set(&hdmi_status, HDMI_ON); + + s3c_gpio_cfgpin(S5PV210_GPH1(5), S5PV210_GPH1_5_HDMI_HPD); + s3c_gpio_setpull(S5PV210_GPH1(5), S3C_GPIO_PULL_DOWN); + s3c_gpio_set_drvstrength(S5PV210_GPH1(5), S3C_GPIO_DRVSTR_4X); + + s5p_hdmi_hpd_gen(); + + if (s5p_hdmi_get_hpd_status()) + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG); + else { + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG); + printk("\n++ %d", __LINE__); + } + return 0; +} +EXPORT_SYMBOL(s5p_hpd_set_hdmiint); + +int s5p_hpd_set_eint(void) +{ + /* HDMI -> EINT */ + atomic_set(&hdmi_status, HDMI_OFF); + + s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG); + s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG); + + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG); + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG); + + s3c_gpio_cfgpin(S5PV210_GPH1(5), S5PV210_GPH1_5_EXT_INT31_5); + s3c_gpio_setpull(S5PV210_GPH1(5), S3C_GPIO_PULL_DOWN); + s3c_gpio_set_drvstrength(S5PV210_GPH1(5), S3C_GPIO_DRVSTR_4X); + + printk(KERN_INFO "\n++ s5p_hpd_set_eint\n"); + return 0; +} +EXPORT_SYMBOL(s5p_hpd_set_eint); + +int irq_eint(int irq) +{ + if (gpio_get_value(S5PV210_GPH1(5))) { + atomic_set(&hpd_struct.state, HPD_HI); + atomic_set(&poll_state, 1); + + last_hpd_state = HPD_HI; + wake_up_interruptible(&hpd_struct.waitq); + } else { + atomic_set(&hpd_struct.state, HPD_LO); + atomic_set(&poll_state, 1); + + last_hpd_state = HPD_LO; + wake_up_interruptible(&hpd_struct.waitq); + } + + if (atomic_read(&hpd_struct.state)) + set_irq_type(IRQ_EINT13, IRQ_TYPE_EDGE_FALLING); + else + set_irq_type(IRQ_EINT13, IRQ_TYPE_EDGE_RISING); + + schedule_work(&hpd_work); + + HPDIFPRINTK("%s\n", atomic_read(&hpd_struct.state) == HPD_HI ? + "HPD HI" : "HPD LO"); + + return IRQ_HANDLED; + +} + +int irq_hdmi(int irq) +{ + u8 flag; + int ret = IRQ_HANDLED; + + /* read flag register */ + flag = s5p_hdmi_get_interrupts(); + + if (s5p_hdmi_get_hpd_status()) + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG); + else + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG); + + s5p_hdmi_clear_pending(HDMI_IRQ_HPD_PLUG); + s5p_hdmi_clear_pending(HDMI_IRQ_HPD_UNPLUG); + + + /* is this our interrupt? */ + + if (!(flag & (1 << HDMI_IRQ_HPD_PLUG | 1 << HDMI_IRQ_HPD_UNPLUG))) { + ret = IRQ_NONE; + goto out; + } + + if (flag == (1 << HDMI_IRQ_HPD_PLUG | 1 << HDMI_IRQ_HPD_UNPLUG)) { + + HPDIFPRINTK("HPD_HI && HPD_LO\n"); + + if (last_hpd_state == HPD_HI && s5p_hdmi_get_hpd_status()) + flag = 1 << HDMI_IRQ_HPD_UNPLUG; + else + flag = 1 << HDMI_IRQ_HPD_PLUG; + } + + if (flag & (1 << HDMI_IRQ_HPD_PLUG)) { + + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG); + + atomic_set(&hpd_struct.state, HPD_HI); + atomic_set(&poll_state, 1); + + last_hpd_state = HPD_HI; + wake_up_interruptible(&hpd_struct.waitq); + + s5p_hdcp_encrypt_stop(true); + + HPDIFPRINTK("HPD_HI\n"); + + } else if (flag & (1 << HDMI_IRQ_HPD_UNPLUG)) { + + s5p_hdcp_encrypt_stop(false); + + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG); + + atomic_set(&hpd_struct.state, HPD_LO); + atomic_set(&poll_state, 1); + + last_hpd_state = HPD_LO; + wake_up_interruptible(&hpd_struct.waitq); + + HPDIFPRINTK("HPD_LO\n"); + } + + schedule_work(&hpd_work); + +out: + return IRQ_HANDLED; +} + +/* + * HPD interrupt handler + * + * Handles interrupt requests from HPD hardware. + * Handler changes value of internal variable and notifies waiting thread. + */ +irqreturn_t s5p_hpd_irq_handler(int irq, void *dev_id) +{ + int ret = IRQ_HANDLED; + + spin_lock_irq(&hpd_struct.lock); + + /* check HDMI status */ + if (atomic_read(&hdmi_status)) { + /* HDMI on */ + ret = irq_hdmi(irq); + HPDIFPRINTK("HDMI HPD interrupt\n"); + } else { + /* HDMI off */ + ret = irq_eint(irq); + HPDIFPRINTK("EINT HPD interrupt\n"); + } + + spin_unlock_irq(&hpd_struct.lock); + + return ret; +} + +static int __init s5p_hpd_probe(struct platform_device *pdev) +{ + if (misc_register(&hpd_misc_device)) { + printk(KERN_WARNING " Couldn't register device 10, %d.\n", + HPD_MINOR); + return -EBUSY; + } + + init_waitqueue_head(&hpd_struct.waitq); + + spin_lock_init(&hpd_struct.lock); + + atomic_set(&hpd_struct.state, -1); + + atomic_set(&hdmi_status, HDMI_OFF); + + s3c_gpio_cfgpin(S5PV210_GPH1(5), S5PV210_GPH1_5_EXT_INT31_5); + s3c_gpio_setpull(S5PV210_GPH1(5), S3C_GPIO_PULL_DOWN); + s3c_gpio_set_drvstrength(S5PV210_GPH1(5), S3C_GPIO_DRVSTR_4X); + + if (gpio_get_value(S5PV210_GPH1(5))) { + atomic_set(&hpd_struct.state, HPD_HI); + last_hpd_state = HPD_HI; + } else { + atomic_set(&hpd_struct.state, HPD_LO); + last_hpd_state = HPD_LO; + } + + set_irq_type(IRQ_EINT13, IRQ_TYPE_EDGE_BOTH); + + if (request_irq(IRQ_EINT13, s5p_hpd_irq_handler, IRQF_DISABLED, + "hpd", s5p_hpd_irq_handler)) { + printk(KERN_ERR "failed to install %s irq\n", "hpd"); + misc_deregister(&hpd_misc_device); + return -EIO; + } + + s5p_hdmi_register_isr((void *) s5p_hpd_irq_handler, (u8)HDMI_IRQ_HPD_PLUG); + s5p_hdmi_register_isr((void *) s5p_hpd_irq_handler, (u8)HDMI_IRQ_HPD_UNPLUG); + + return 0; +} + +/* + * Remove + */ +static int s5p_hpd_remove(struct platform_device *pdev) +{ + return 0; +} + + +#ifdef CONFIG_PM +/* + * Suspend + */ +int s5p_hpd_suspend(struct platform_device *dev, pm_message_t state) +{ + return 0; +} + +/* + * Resume + */ +int s5p_hpd_resume(struct platform_device *dev) +{ + return 0; +} +#else +#define s5p_hpd_suspend NULL +#define s5p_hpd_resume NULL +#endif + +static struct platform_driver s5p_hpd_driver = { + .probe = s5p_hpd_probe, + .remove = s5p_hpd_remove, + .suspend = s5p_hpd_suspend, + .resume = s5p_hpd_resume, + .driver = { + .name = "s5p-hpd", + .owner = THIS_MODULE, + }, +}; + +static char banner[] __initdata = + "S5P HPD Driver, (c) 2010 Samsung Electronics\n"; + +int __init s5p_hpd_init(void) +{ + int ret; + + printk(banner); + + ret = platform_driver_register(&s5p_hpd_driver); + + if (ret) { + printk(KERN_ERR "Platform Device Register Failed %d\n", ret); + return -1; + } + + return 0; +} + +static void __exit s5p_hpd_exit(void) +{ + misc_deregister(&hpd_misc_device); +} + +module_init(s5p_hpd_init); +module_exit(s5p_hpd_exit); + + diff --git a/drivers/media/video/samsung/tv20/hpd.h b/drivers/media/video/samsung/tv20/hpd.h new file mode 100644 index 0000000..4fa4d27 --- /dev/null +++ b/drivers/media/video/samsung/tv20/hpd.h @@ -0,0 +1,36 @@ +/* linux/drivers/media/video/samsung/tv20/hpd.h + * + * hpd interface header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#define VERSION "1.2" /* Driver version number */ +#define HPD_MINOR 243 /* Major 10, Minor 243, /dev/hpd */ + +#define HPD_LO 0 +#define HPD_HI 1 + +#define HDMI_ON 1 +#define HDMI_OFF 0 + +struct hpd_struct { + spinlock_t lock; + wait_queue_head_t waitq; + atomic_t state; +}; + +extern int s5p_hpd_set_eint(void); +extern int s5p_hpd_set_hdmiint(void); + +#define S5PV210_GPH1_4_HDMI_CEC (0x4 << 16) +#define S5PV210_GPH1_4_EXT_INT31_4 (0xf << 16) + +#define S5PV210_GPH1_5_HDMI_HPD (0x4 << 20) +#define S5PV210_GPH1_5_EXT_INT31_5 (0xf << 20) + diff --git a/drivers/media/video/samsung/tv20/s5p_stda_grp.c b/drivers/media/video/samsung/tv20/s5p_stda_grp.c new file mode 100644 index 0000000..61bfba0 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_stda_grp.c @@ -0,0 +1,1103 @@ +/* linux/drivers/media/video/samsung/tv20/s5p_stda_grp.c + * + * Graphic Layer ftn. file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/ioctl.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/uaccess.h> + +#include "s5p_tv.h" + +#ifdef COFIG_TVOUT_DBG +#define S5P_GRP_DEBUG 1 +#endif + +#ifdef S5P_GRP_DEBUG +#define GRPPRINTK(fmt, args...) \ + printk(KERN_INFO "\t[GRP] %s: " fmt, __func__ , ## args) +#else +#define GRPPRINTK(fmt, args...) +#endif + + +bool _s5p_grp_start(enum s5p_tv_vmx_layer vm_layer) +{ + enum s5p_tv_vmx_err merr; + struct s5p_tv_status *st = &s5ptv_status; + + if (!(st->grp_layer_enable[0] || st->grp_layer_enable[1])) { + + merr = __s5p_vm_init_status_reg(st->grp_burst, + st->grp_endian); + + if (merr != VMIXER_NO_ERROR) + return false; + } + +#ifdef CONFIG_CPU_S5PC100 + merr = __s5p_vm_init_layer(vm_layer, + true, + s5ptv_overlay[vm_layer].win_blending, + s5ptv_overlay[vm_layer].win.global_alpha, + s5ptv_overlay[vm_layer].priority, + s5ptv_overlay[vm_layer].fb.fmt.pixelformat, + s5ptv_overlay[vm_layer].blank_change, + s5ptv_overlay[vm_layer].pixel_blending, + s5ptv_overlay[vm_layer].pre_mul, + s5ptv_overlay[vm_layer].blank_color, + s5ptv_overlay[vm_layer].base_addr, + s5ptv_overlay[vm_layer].fb.fmt.bytesperline, + s5ptv_overlay[vm_layer].win.w.width, + s5ptv_overlay[vm_layer].win.w.height, + s5ptv_overlay[vm_layer].win.w.left, + s5ptv_overlay[vm_layer].win.w.top, + s5ptv_overlay[vm_layer].dst_rect.left, + s5ptv_overlay[vm_layer].dst_rect.top); +#endif + +#ifdef CONFIG_CPU_S5PV210 + merr = __s5p_vm_init_layer(s5ptv_status.tvout_param.disp_mode, + vm_layer, + true, + s5ptv_overlay[vm_layer].win_blending, + s5ptv_overlay[vm_layer].win.global_alpha, + s5ptv_overlay[vm_layer].priority, + s5ptv_overlay[vm_layer].fb.fmt.pixelformat, + s5ptv_overlay[vm_layer].blank_change, + s5ptv_overlay[vm_layer].pixel_blending, + s5ptv_overlay[vm_layer].pre_mul, + s5ptv_overlay[vm_layer].blank_color, + s5ptv_overlay[vm_layer].base_addr, + s5ptv_overlay[vm_layer].fb.fmt.bytesperline, + s5ptv_overlay[vm_layer].win.w.width, + s5ptv_overlay[vm_layer].win.w.height, + s5ptv_overlay[vm_layer].win.w.left, + s5ptv_overlay[vm_layer].win.w.top, + s5ptv_overlay[vm_layer].dst_rect.left, + s5ptv_overlay[vm_layer].dst_rect.top, + s5ptv_overlay[vm_layer].dst_rect.width, + s5ptv_overlay[vm_layer].dst_rect.height); +#endif + + + if (merr != VMIXER_NO_ERROR) { + GRPPRINTK("can't initialize layer(%d)\n\r", merr); + return false; + } + + __s5p_vm_start(); + + + st->grp_layer_enable[vm_layer] = true; + + GRPPRINTK("()\n\r"); + + return true; +} + +bool _s5p_grp_stop(enum s5p_tv_vmx_layer vm_layer) +{ + enum s5p_tv_vmx_err merr; + struct s5p_tv_status *st = &s5ptv_status; + + GRPPRINTK("()\n\r"); + + merr = __s5p_vm_set_layer_show(vm_layer, false); + + if (merr != VMIXER_NO_ERROR) + return false; + + merr = __s5p_vm_set_layer_priority(vm_layer, 0); + + if (merr != VMIXER_NO_ERROR) + return false; + + __s5p_vm_start(); + + + st->grp_layer_enable[vm_layer] = false; + + GRPPRINTK("()\n\r"); + + return true; +} + +int s5ptvfb_set_output(struct s5p_tv_status *ctrl) { return 0; } + +int s5ptvfb_set_display_mode(struct s5p_tv_status *ctrl) +{ + enum s5p_tv_vmx_layer layer = VM_GPR0_LAYER; + bool premul = false; + bool pixel_blending = false; + bool blank_change = false; + bool win_blending = false; + u32 blank_color = 0x0; + enum s5p_tv_vmx_color_fmt color; + u32 bpp; + u32 alpha = 0; + + bpp = ((struct fb_var_screeninfo)(ctrl->fb->var)).bits_per_pixel; + + if (bpp == 32) + color = VM_DIRECT_RGB8888; + else + color = VM_DIRECT_RGB565; + + __s5p_vm_set_ctrl(layer, premul, pixel_blending, blank_change, + win_blending, color, alpha, blank_color); + + return 0; +} + +int s5ptvfb_display_on(struct s5p_tv_status *ctrl) +{ + __s5p_vm_set_layer_priority(VM_GPR0_LAYER, 10); + __s5p_vm_set_layer_show(VM_GPR0_LAYER, true); + + return 0; +} + +int s5ptvfb_display_off(struct s5p_tv_status *ctrl) +{ + __s5p_vm_set_layer_priority(VM_GPR0_LAYER, 10); + __s5p_vm_set_layer_show(VM_GPR0_LAYER, false); + + return 0; +} + +int s5ptvfb_frame_off(struct s5p_tv_status *ctrl) { return 0; } +int s5ptvfb_set_clock(struct s5p_tv_status *ctrl) { return 0; } +int s5ptvfb_set_polarity(struct s5p_tv_status *ctrl) { return 0; } +int s5ptvfb_set_timing(struct s5p_tv_status *ctrl) { return 0; } +int s5ptvfb_set_lcd_size(struct s5p_tv_status *ctrl) { return 0; } +int s5ptvfb_window_on(struct s5p_tv_status *ctrl, int id) +{ + __s5p_vm_set_layer_show(VM_GPR0_LAYER, true); + + return 0; +} + +int s5ptvfb_window_off(struct s5p_tv_status *ctrl, int id) +{ + __s5p_vm_set_layer_show(VM_GPR0_LAYER, false); + return 0; +} + +int s5ptvfb_set_window_control(struct s5p_tv_status *ctrl, int id) { return 0; } +int s5ptvfb_set_alpha_blending(struct s5p_tv_status *ctrl, int id) { return 0; } +int s5ptvfb_set_window_position(struct s5p_tv_status *ctrl, int id) +{ + u32 off_x, off_y; + u32 w_t, h_t; + u32 w, h; + + struct fb_var_screeninfo *var = &ctrl->fb->var; + struct s5ptvfb_window *win = ctrl->fb->par; + + off_x = (u32)win->x; + off_y = (u32)win->y; + + w = var->xres; + h = var->yres; + + /* + * When tvout resolution was overscanned, there is no + * adjust method in H/W. So, framebuffer should be resized. + * In this case - TV w/h is greater than FB w/h, grp layer's + * dst offset must be changed to fix tv screen. + */ + + switch (ctrl->tvout_param.disp_mode) { + + case TVOUT_NTSC_M: + case TVOUT_480P_60_16_9: + case TVOUT_480P_60_4_3: + case TVOUT_480P_59: + w_t = 720; + h_t = 480; + break; + + case TVOUT_576P_50_16_9: + case TVOUT_576P_50_4_3: + w_t = 720; + h_t = 576; + break; + + case TVOUT_720P_60: + case TVOUT_720P_59: + case TVOUT_720P_50: + w_t = 1280; + h_t = 720; + break; + + case TVOUT_1080I_60: + case TVOUT_1080I_59: + case TVOUT_1080I_50: + case TVOUT_1080P_60: + case TVOUT_1080P_59: + case TVOUT_1080P_50: + case TVOUT_1080P_30: + w_t = 1920; + h_t = 1080; + break; + + default: + w_t = 0; + h_t = 0; + break; + } + + if (w_t > w) + off_x = (w_t - w) / 2; + + if (h_t > h) + off_y = (h_t - h) / 2; + + __s5p_vm_set_grp_layer_position(VM_GPR0_LAYER, off_x, off_y); + + return 0; +} + +int s5ptvfb_set_window_size(struct s5p_tv_status *ctrl, int id) +{ + struct fb_var_screeninfo *var = &ctrl->fb->var; + int w, h, xo, yo; + + w = var->xres; + h = var->yres; + xo = var->xoffset; + yo = var->yoffset; + + __s5p_vm_set_grp_layer_size(VM_GPR0_LAYER, w, w, h, xo, yo); + + + dev_dbg(ctrl->dev_fb, "[fb%d] resolution: %d x %d\n", id, + var->xres, var->yres); + + return 0; +} +int s5ptvfb_set_buffer_address(struct s5p_tv_status *ctrl, int id) +{ + struct fb_fix_screeninfo *fix = &ctrl->fb->fix; + struct fb_var_screeninfo *var = &ctrl->fb->var; + dma_addr_t start_addr = 0, end_addr = 0; + + if (fix->smem_start) { + start_addr = fix->smem_start + (var->xres_virtual * + (var->bits_per_pixel / 8) * var->yoffset); + + end_addr = start_addr + (var->xres_virtual * + (var->bits_per_pixel / 8) * var->yres); + } + + __s5p_vm_set_grp_base_address(VM_GPR0_LAYER, start_addr); + return 0; +} + +int s5ptvfb_set_buffer_size(struct s5p_tv_status *ctrl, int id) { return 0; } + +int s5ptvfb_set_chroma_key(struct s5p_tv_status *ctrl, int id) +{ + struct s5ptvfb_window *win = ctrl->fb->par; + struct s5ptvfb_chroma *chroma = &win->chroma; + + enum s5p_tv_vmx_layer layer = VM_GPR0_LAYER; + + bool blank_change = (chroma->enabled) ? true : false; + u32 blank_color = chroma->key; + + bool win_blending = (chroma->blended) ? true : false; + bool alpha = chroma->alpha; + + enum s5p_tv_vmx_color_fmt color = VM_DIRECT_RGB8888; + + __s5p_vm_set_ctrl(layer, false, false, blank_change, + win_blending, color, alpha, blank_color); + + return 0; +} + + + + +static inline unsigned int __chan_to_field(unsigned int chan, + struct fb_bitfield bf) +{ + chan &= 0xffff; + chan >>= 16 - bf.length; + + return chan << bf.offset; +} + +static int s5ptvfb_set_alpha_info(struct fb_var_screeninfo *var, + struct s5ptvfb_window *win) +{ + if (var->transp.length > 0) + win->alpha.mode = PIXEL_BLENDING; + else { + win->alpha.mode = PLANE_BLENDING; + win->alpha.channel = 0; + win->alpha.value = S5PTVFB_AVALUE(0xf, 0xf, 0xf); + } + + return 0; +} + + +static int s5ptvfb_enable_window(int id) +{ + struct s5ptvfb_window *win = s5ptv_status.fb->par; + + if (s5ptvfb_window_on(&s5ptv_status, id)) { + win->enabled = 0; + return -EFAULT; + } else { + win->enabled = 1; + return 0; + } +} + + +static int s5ptvfb_disable_window(int id) +{ + struct s5ptvfb_window *win = s5ptv_status.fb->par; + + if (s5ptvfb_window_off(&s5ptv_status, id)) { + win->enabled = 1; + return -EFAULT; + } else { + win->enabled = 0; + return 0; + } +} + +int s5ptvfb_unmap_video_memory(struct fb_info *fb) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct s5ptvfb_window *win = fb->par; + + if (fix->smem_start) { + dma_free_writecombine(s5ptv_status.dev_fb, fix->smem_len, + fb->screen_base, fix->smem_start); + fix->smem_start = 0; + fix->smem_len = 0; + dev_info(s5ptv_status.dev_fb, + "[fb%d] video memory released\n", win->id); + } + + return 0; +} + +static int s5ptvfb_release_window(struct fb_info *fb) +{ + struct s5ptvfb_window *win = fb->par; + + win->x = 0; + win->y = 0; + + return 0; +} + +int s5ptvfb_map_video_memory(struct fb_info *fb) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct s5ptvfb_window *win = fb->par; + + if (win->path == DATA_PATH_FIFO) + return 0; + + fb->screen_base = dma_alloc_writecombine(s5ptv_status.dev_fb, + PAGE_ALIGN(fix->smem_len), + (unsigned int *) &fix->smem_start, GFP_KERNEL); + if (!fb->screen_base) + return -ENOMEM; + else + dev_info(s5ptv_status.dev_fb, + "[fb%d] dma: 0x%08x, cpu: 0x%08x,size: 0x%08x\n", + win->id, (unsigned int) fix->smem_start, + (unsigned int) fb->screen_base, + fix->smem_len); + + memset(fb->screen_base, 0, fix->smem_len); + + return 0; +} + + +static int s5ptvfb_set_bitfield(struct fb_var_screeninfo *var) +{ + switch (var->bits_per_pixel) { + case 16: + if (var->transp.length == 1) { + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + } else if (var->transp.length == 4) { + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + var->transp.offset = 12; + } else { + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + } + break; + + case 24: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + + case 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + break; + } + + return 0; +} + +#define TV_LOGO_W 800 +#define TV_LOGO_H 480 + +int s5ptvfb_draw_logo(struct fb_info *fb) +{ +#if 0 + struct fb_fix_screeninfo *fix = &fb->fix; + int i; + +/* memcpy(s5ptv_status.fb->screen_base, + TV_LOGO_RGB24, fix->line_length * var->yres); + */ + char *base = s5ptv_status.fb->screen_base; + + for (i = 0; i < TV_LOGO_H; i++) { + memcpy(base, &TV_LOGO_RGB24[i*TV_LOGO_W], TV_LOGO_W * 4); + base += fix->line_length; + } +#endif + return 0; +} + +static int s5ptvfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + /* nothing to do for removing cursor */ + return 0; +} + + +static int s5ptvfb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *fb) +{ + unsigned int *pal = (unsigned int *) fb->pseudo_palette; + unsigned int val = 0; + + if (regno < 16) { + /* fake palette of 16 colors */ + val |= __chan_to_field(red, fb->var.red); + val |= __chan_to_field(green, fb->var.green); + val |= __chan_to_field(blue, fb->var.blue); + val |= __chan_to_field(transp, fb->var.transp); + + pal[regno] = val; + } + + return 0; +} + + +static int s5ptvfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fb) +{ + struct s5ptvfb_window *win = fb->par; + + if (var->yoffset + var->yres > var->yres_virtual) { + dev_err(s5ptv_status.dev_fb, "invalid yoffset value\n"); + return -EINVAL; + } + + fb->var.yoffset = var->yoffset; + + dev_dbg(s5ptv_status.dev_fb, "[fb%d] yoffset for pan display: %d\n", + win->id, + var->yoffset); + + s5ptvfb_set_buffer_address(&s5ptv_status, win->id); + + return 0; +} + + +static int s5ptvfb_blank(int blank_mode, struct fb_info *fb) +{ + struct s5ptvfb_window *win = fb->par; + + dev_dbg(s5ptv_status.dev_fb, "change blank mode\n"); + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + if (fb->fix.smem_start) { + s5ptvfb_display_on(&s5ptv_status); + s5ptvfb_enable_window(win->id); + } else + dev_info(s5ptv_status.dev_fb, + "[fb%d] no allocated memory for unblank\n", + win->id); + break; + + case FB_BLANK_POWERDOWN: + s5ptvfb_display_off(&s5ptv_status); + s5ptvfb_disable_window(win->id); + break; + + default: + dev_dbg(s5ptv_status.dev_fb, "unsupported blank mode\n"); + /* return -EINVAL; */ + } + + return 0; +} + +int s5ptvfb_set_par(struct fb_info *fb) +{ + struct s5ptvfb_window *win = fb->par; + + dev_dbg(s5ptv_status.dev_fb, "[fb%d] set_par\n", win->id); + + if (!fb->fix.smem_start) { +#ifndef CONFIG_USER_ALLOC_TVOUT + GRPPRINTK(" The frame buffer is allocated here\n"); + s5ptvfb_map_video_memory(fb); +#else + printk(KERN_ERR + "[Warning] The frame buffer should be allocated by ioctl\n"); +#endif + } + + ((struct fb_var_screeninfo) (s5ptv_status.fb->var)).bits_per_pixel = + ((struct fb_var_screeninfo) (fb->var)).bits_per_pixel; + + s5ptvfb_set_display_mode(&s5ptv_status); + + s5ptvfb_set_window_control(&s5ptv_status, win->id); + s5ptvfb_set_window_position(&s5ptv_status, win->id); + s5ptvfb_set_window_size(&s5ptv_status, win->id); + s5ptvfb_set_buffer_address(&s5ptv_status, win->id); + s5ptvfb_set_buffer_size(&s5ptv_status, win->id); + + if (win->id > 0) + s5ptvfb_set_alpha_blending(&s5ptv_status, win->id); + + return 0; +} + +int s5ptvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb) +{ + struct fb_fix_screeninfo *fix = &fb->fix; + struct s5ptvfb_window *win = fb->par; + struct s5ptvfb_lcd *lcd = s5ptv_status.lcd; + + dev_dbg(s5ptv_status.dev_fb, "[fb%d] check_var\n", win->id); + + if (var->bits_per_pixel != 16 && var->bits_per_pixel != 24 && + var->bits_per_pixel != 32) { + dev_err(s5ptv_status.dev_fb, "invalid bits per pixel\n"); + return -EINVAL; + } + + if (var->xres > lcd->width) + var->xres = lcd->width; + + if (var->yres > lcd->height) + var->yres = lcd->height; + + if (var->xres_virtual != var->xres) + var->xres_virtual = var->xres; + + if (var->yres_virtual > var->yres * (fb->fix.ypanstep + 1)) + var->yres_virtual = var->yres * (fb->fix.ypanstep + 1); + + if (var->xoffset != 0) + var->xoffset = 0; + + if (var->yoffset + var->yres > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + + if (win->x + var->xres > lcd->width) + win->x = lcd->width - var->xres; + + if (win->y + var->yres > lcd->height) + win->y = lcd->height - var->yres; + + /* modify the fix info */ + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->smem_len = fix->line_length * var->yres_virtual; + + + s5ptvfb_set_bitfield(var); + s5ptvfb_set_alpha_info(var, win); + + return 0; +} + +static int s5ptvfb_release(struct fb_info *fb, int user) +{ +/* + * Following block is deleted for enabling multiple open of TV frame buffer + * + * struct s5ptvfb_window *win = fb->par; + */ + int ret; + struct s5ptvfb_window *win = fb->par; + + s5ptvfb_release_window(fb); + +/* + * Following block is deleted for enabling multiple open of TV frame buffer + * + * mutex_lock(&s5ptv_status.fb_lock); + * atomic_dec(&win->in_use); + * mutex_unlock(&s5ptv_status.fb_lock); + */ + + _s5p_vlayer_stop(); + _s5p_tv_if_stop(); + + s5ptv_status.hdcp_en = false; + + s5ptv_status.tvout_output_enable = false; + + /* + * drv. release + * - just check drv. state reg. or not. + */ + + ret = s5p_tv_clk_gate(false); + if (ret < 0) { + printk(KERN_ERR "[Error]Cannot release\n"); + return -1; + } + tv_phy_power(false); + + mutex_lock(&s5ptv_status.fb_lock); + atomic_dec(&win->in_use); + mutex_unlock(&s5ptv_status.fb_lock); + + return 0; +} + +static int s5ptvfb_ioctl(struct fb_info *fb, unsigned int cmd, + unsigned long arg) +{ + struct fb_var_screeninfo *var = &fb->var; + struct s5ptvfb_window *win = fb->par; + struct s5ptvfb_lcd *lcd = s5ptv_status.lcd; + int ret = 0; + void *argp = (void *) arg; + + union { + struct s5ptvfb_user_window user_window; + struct s5ptvfb_user_plane_alpha user_alpha; + struct s5ptvfb_user_chroma user_chroma; + int vsync; + } p; + + switch (cmd) { + + case FBIO_ALLOC: + win->path = (enum s5ptvfb_data_path_t) argp; + break; + + case FBIOGET_FSCREENINFO: + ret = memcpy(argp, &fb->fix, sizeof(fb->fix)) ? 0 : -EFAULT; + break; + + case FBIOGET_VSCREENINFO: + ret = memcpy(argp, &fb->var, sizeof(fb->var)) ? 0 : -EFAULT; + break; + + case FBIOPUT_VSCREENINFO: + ret = s5ptvfb_check_var((struct fb_var_screeninfo *) argp, fb); + if (ret) { + dev_err(s5ptv_status.dev_fb, "invalid vscreeninfo\n"); + break; + } + + ret = memcpy(&fb->var, (struct fb_var_screeninfo *) argp, + sizeof(fb->var)) ? 0 : -EFAULT; + if (ret) { + dev_err(s5ptv_status.dev_fb, + "failed to put new vscreeninfo\n"); + break; + } + + ret = s5ptvfb_set_par(fb); + break; + + case S5PTVFB_WIN_POSITION: + if (copy_from_user(&p.user_window, + (struct s5ptvfb_user_window __user *) arg, + sizeof(p.user_window))) + ret = -EFAULT; + else { + if (p.user_window.x < 0) + p.user_window.x = 0; + + if (p.user_window.y < 0) + p.user_window.y = 0; + + if (p.user_window.x + var->xres > lcd->width) + win->x = lcd->width - var->xres; + else + win->x = p.user_window.x; + + if (p.user_window.y + var->yres > lcd->height) + win->y = lcd->height - var->yres; + else + win->y = p.user_window.y; + + s5ptvfb_set_window_position(&s5ptv_status, win->id); + } + break; + + case S5PTVFB_WIN_SET_PLANE_ALPHA: + if (copy_from_user(&p.user_alpha, + (struct s5ptvfb_user_plane_alpha __user *) arg, + sizeof(p.user_alpha))) + ret = -EFAULT; + else { + win->alpha.mode = PLANE_BLENDING; + win->alpha.channel = p.user_alpha.channel; + win->alpha.value = + S5PTVFB_AVALUE(p.user_alpha.red, + p.user_alpha.green, + p.user_alpha.blue); + + s5ptvfb_set_alpha_blending(&s5ptv_status, win->id); + } + break; + + case S5PTVFB_WIN_SET_CHROMA: + if (copy_from_user(&p.user_chroma, + (struct s5ptvfb_user_chroma __user *) arg, + sizeof(p.user_chroma))) + ret = -EFAULT; + else { + win->chroma.enabled = p.user_chroma.enabled; + win->chroma.key = S5PTVFB_CHROMA(p.user_chroma.red, + p.user_chroma.green, + p.user_chroma.blue); + + s5ptvfb_set_chroma_key(&s5ptv_status, win->id); + } + break; + + case S5PTVFB_WIN_SET_ADDR: + fb->fix.smem_start = (unsigned long)argp; + s5ptvfb_set_buffer_address(&s5ptv_status, win->id); + break; + + case S5PTVFB_SET_WIN_ON: +#ifdef CONFIG_USER_ALLOC_TVOUT + s5ptvfb_display_on(&s5ptv_status); + s5ptvfb_enable_window(0); +#endif + break; + + case S5PTVFB_SET_WIN_OFF: +#ifdef CONFIG_USER_ALLOC_TVOUT + s5ptvfb_display_off(&s5ptv_status); + s5ptvfb_disable_window(0); +#endif + break; + + } + + return 0; +} + +static int s5ptvfb_open(struct fb_info *fb, int user) +{ + struct s5ptvfb_window *win = fb->par; + int ret = 0; + + ret = s5p_tv_clk_gate(true); + if (ret < 0) { + printk(KERN_ERR "[Error]Cannot open it\n"); + return -1; + } + + tv_phy_power(true); + + _s5p_tv_if_init_param(); + + s5p_tv_v4l2_init_param(); + + /* s5ptv_status.tvout_param.disp_mode = TVOUT_720P_60; */ + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI_RGB; + + _s5p_tv_if_set_disp(); + +#ifndef CONFIG_USER_ALLOC_TVOUT + s5ptvfb_display_on(&s5ptv_status); + + s5ptvfb_enable_window(0); +#endif + + mutex_lock(&s5ptv_status.fb_lock); + + if (atomic_read(&win->in_use)) { + dev_dbg(s5ptv_status.dev_fb, + "do not allow multiple open " + "for window\n"); + ret = -EBUSY; + + } else + atomic_inc(&win->in_use); + + mutex_unlock(&s5ptv_status.fb_lock); + + return ret; + +} + +struct fb_ops s5ptvfb_ops = { + .owner = THIS_MODULE, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_check_var = s5ptvfb_check_var, + .fb_set_par = s5ptvfb_set_par, + .fb_blank = s5ptvfb_blank, + .fb_pan_display = s5ptvfb_pan_display, + .fb_setcolreg = s5ptvfb_setcolreg, + .fb_cursor = s5ptvfb_cursor, + .fb_ioctl = s5ptvfb_ioctl, + .fb_open = s5ptvfb_open, + .fb_release = s5ptvfb_release, +}; + +int s5ptvfb_direct_ioctl(int id, unsigned int cmd, unsigned long arg) +{ + struct fb_info *fb = s5ptv_status.fb; + struct fb_fix_screeninfo *fix = &fb->fix; + struct s5ptvfb_window *win = fb->par; + void *argp = (void *) arg; + int ret = 0; + + switch (cmd) { + + case FBIO_ALLOC: + win->path = (enum s5ptvfb_data_path_t) argp; + break; + + case FBIOGET_FSCREENINFO: + ret = memcpy(argp, &fb->fix, sizeof(fb->fix)) ? 0 : -EFAULT; + break; + + case FBIOGET_VSCREENINFO: + ret = memcpy(argp, &fb->var, sizeof(fb->var)) ? 0 : -EFAULT; + break; + + case FBIOPUT_VSCREENINFO: + ret = s5ptvfb_check_var((struct fb_var_screeninfo *) argp, fb); + if (ret) { + dev_err(s5ptv_status.dev_fb, "invalid vscreeninfo\n"); + break; + } + + ret = memcpy(&fb->var, (struct fb_var_screeninfo *) argp, + sizeof(fb->var)) ? 0 : -EFAULT; + if (ret) { + dev_err(s5ptv_status.dev_fb, + "failed to put new vscreeninfo\n"); + break; + } + + ret = s5ptvfb_set_par(fb); + break; + + case S5PTVFB_SET_WIN_ON: +#ifdef CONFIG_USER_ALLOC_TVOUT + s5ptvfb_display_on(&s5ptv_status); + s5ptvfb_enable_window(0); +#endif + break; + + case S5PTVFB_SET_WIN_OFF: +#ifdef CONFIG_USER_ALLOC_TVOUT + s5ptvfb_display_off(&s5ptv_status); + s5ptvfb_disable_window(0); +#endif + break; + + case S5PTVFB_POWER_ON: + s5p_tv_clk_gate(true); + tv_phy_power(true); + + _s5p_tv_if_init_param(); + + s5p_tv_v4l2_init_param(); + + /* s5ptv_status.tvout_param.disp_mode = TVOUT_720P_60; */ + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI; + + _s5p_tv_if_set_disp(); + + break; + + case S5PTVFB_POWER_OFF: + _s5p_vlayer_stop(); + _s5p_tv_if_stop(); + + s5p_tv_clk_gate(false); + tv_phy_power(false); + break; + + case S5PTVFB_WIN_SET_ADDR: + fix->smem_start = (unsigned long)argp; + s5ptvfb_set_buffer_address(&s5ptv_status, win->id); + break; + + default: + ret = s5ptvfb_ioctl(fb, cmd, arg); + break; + } + + return ret; +} +EXPORT_SYMBOL(s5ptvfb_direct_ioctl); + +int s5ptvfb_init_fbinfo(int id) +{ + struct fb_info *fb = s5ptv_status.fb; + struct fb_fix_screeninfo *fix = &fb->fix; + struct fb_var_screeninfo *var = &fb->var; + struct s5ptvfb_window *win = fb->par; + struct s5ptvfb_alpha *alpha = &win->alpha; + struct s5ptvfb_lcd *lcd = s5ptv_status.lcd; + struct s5ptvfb_lcd_timing *timing = &lcd->timing; + + memset(win, 0, sizeof(struct s5ptvfb_window)); + + platform_set_drvdata(to_platform_device(s5ptv_status.dev_fb), fb); + + strcpy(fix->id, S5PTVFB_NAME); + + /* fimd specific */ + win->id = id; + win->path = DATA_PATH_DMA; + win->dma_burst = 16; + alpha->mode = PLANE_BLENDING; + + /* fbinfo */ + fb->fbops = &s5ptvfb_ops; + fb->flags = FBINFO_FLAG_DEFAULT; + fb->pseudo_palette = &win->pseudo_pal; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->accel = FB_ACCEL_NONE; + fix->visual = FB_VISUAL_TRUECOLOR; + var->xres = lcd->width; + var->yres = lcd->height; + var->xres_virtual = var->xres; + var->yres_virtual = var->yres + (var->yres * fix->ypanstep); + var->bits_per_pixel = 32; + var->xoffset = 0; + var->yoffset = 0; + var->width = 0; + var->height = 0; + var->transp.length = 0; + + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->smem_len = fix->line_length * var->yres_virtual; + + var->nonstd = 0; + var->activate = FB_ACTIVATE_NOW; + var->vmode = FB_VMODE_NONINTERLACED; + var->hsync_len = timing->h_sw; + var->vsync_len = timing->v_sw; + var->left_margin = timing->h_fp; + var->right_margin = timing->h_bp; + var->upper_margin = timing->v_fp; + var->lower_margin = timing->v_bp; + + var->pixclock = lcd->freq * (var->left_margin + var->right_margin + + var->hsync_len + var->xres) * + (var->upper_margin + var->lower_margin + + var->vsync_len + var->yres); + + dev_dbg(s5ptv_status.dev_fb, "pixclock: %d\n", var->pixclock); + + s5ptvfb_set_bitfield(var); + s5ptvfb_set_alpha_info(var, win); + + return 0; +} + +static struct s5ptvfb_lcd max_tvfb = { + .width = 1920, + .height = 1080, + .bpp = 32, + .freq = 60, + + .timing = { + .h_fp = 49, + .h_bp = 17, + .h_sw = 33, + .v_fp = 4, + .v_fpe = 1, + .v_bp = 15, + .v_bpe = 1, + .v_sw = 6, + }, + + .polarity = { + .rise_vclk = 0, + .inv_hsync = 1, + .inv_vsync = 1, + .inv_vden = 0, + }, +}; + +void s5ptvfb_set_lcd_info(struct s5p_tv_status *ctrl) +{ + ctrl->lcd = &max_tvfb; +} diff --git a/drivers/media/video/samsung/tv20/s5p_stda_hdmi.c b/drivers/media/video/samsung/tv20/s5p_stda_hdmi.c new file mode 100644 index 0000000..15e90ad --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_stda_hdmi.c @@ -0,0 +1,242 @@ +/* linux/drivers/media/video/samsung/tv20/s5p_stda_hdmi.c + * + * HDMI ftn. file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/ioctl.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include "s5p_tv.h" + +#include <mach/map.h> +#include <mach/regs-clock.h> + +#ifdef COFIG_TVOUT_DBG +#define S5P_STDA_HDMI_DEBUG 1 +#endif + +#ifdef S5P_STDA_HDMI_DEBUG +#define STHDPRINTK(fmt, args...) \ + printk(KERN_INFO "\t[STDA_HDMI] %s: " fmt, __func__ , ## args) +#else +#define STHDPRINTK(fmt, args...) +#endif + +/* +static bool _s5p_hdmi_spd_infoframe(unsigned long p_buf_in) +{ + STHDPRINTK("(0x%x)\n\r", (unsigned int)p_buf_in); + + if (!p_buf_in) + { + STHDPRINTK("(ERR) p_buf_in is NULL\n\r"); + return false; + } + + memcpy((void *)(&(s5ptv_status.hdmi_spd_info_frame)), + (const void *)p_buf_in, sizeof(s5p_hdmi_spd_infoframe)); + + memcpy((void *)(s5ptv_status.spd_header), + (const void *)(s5ptv_status.hdmi_spd_info_frame.spd_header), 3); + s5ptv_status.hdmi_spd_info_frame.spd_header = s5ptv_status.spd_header; + + memcpy((void *)(s5ptv_status.spd_data), + (const void *)(s5ptv_status.hdmi_spd_info_frame.spd_data), 28); + s5ptv_status.hdmi_spd_info_frame.spd_data = s5ptv_status.spd_data; + + STHDPRINTK("(0x%08x)\n\r", + (unsigned int)&s5ptv_status.hdmi_spd_info_frame); + + return true; +} +*/ + +#if 0 +static bool _s5p_hdmi_init_hdcp_en(unsigned long p_buf_in) +{ + if (!p_buf_in) { + STHDPRINTK("(ERR) p_buf_in is NULL\n\r"); + return false; + } + + STHDPRINTK("(%d)\n\r", (bool)p_buf_in); + + s5ptv_status.hdcp_en = (bool)p_buf_in; + + STHDPRINTK("(%d)\n\r", s5ptv_status.hdcp_en); + + return true; +} + +static bool _s5p_hdmi_init_audio(unsigned long p_buf_in) +{ + STHDPRINTK("(%d)\n\r", (bool)p_buf_in); + + if (!p_buf_in) { + STHDPRINTK("(ERR) p_buf_in is NULL\n\r"); + return false; + } + + s5ptv_status.hdmi_audio_type = (enum s5p_hdmi_audio_type)p_buf_in; + + STHDPRINTK("(%d)\n\r", s5ptv_status.hdmi_audio_type); + + return true; +} + +static bool _s5p_hdmi_get_hpd_status(unsigned long p_buf_out) +{ + bool *pOut; + + STHDPRINTK("()\n\r"); + + if (!p_buf_out) { + STHDPRINTK("(ERR) p_buf_out is NULL\n\r"); + return false; + } + + pOut = (bool *)p_buf_out; + + *pOut = s5ptv_status.hpd_status; + + STHDPRINTK("()\n\r"); + + return true; +} + +static bool _s5p_hdmi_wait_hpd_status_change(unsigned long p_buf_out) +{ + unsigned int *pOut; + + STHDPRINTK("()\n\r"); + + if (!p_buf_out) { + STHDPRINTK("(ERR) p_buf_out is NULL\n\r"); + return false; + } + + pOut = (unsigned int *)p_buf_out; + + + /* + if (*pOut == WAIT_TIMEOUT) + { + STHDPRINTK("(ERR) TIMEOUT~\n\r"); + } + else if (*pOut == WAIT_FAILED) + { + STHDPRINTK("(ERR) WAIT_FAILED\n\r"); + } + */ + + return true; +} + +#endif + +/*============================================================================*/ + +/* +static bool _s5p_hdmi_video_init_bluescreen(unsigned long p_buf_in) +{ + + STHDPRINTK("(0x%x)\n\r", (unsigned int)p_buf_in); + + if (!p_buf_in) + { + STHDPRINTK("(ERR) p_buf_in is NULL\n\r"); + return false; + } + + memcpy((void *)(&(s5ptv_status.hdmi_video_blue_screen)), + (const void *)p_buf_in, sizeof(s5p_hdmi_bluescreen)); + + STHDPRINTK("(0x%08x)\n\r", + (unsigned int)&s5ptv_status.hdmi_video_blue_screen); + + return true; +} + +static bool _s5p_hdmi_video_init_avi_infoframe(unsigned long p_buf_in) +{ + STHDPRINTK("(0x%x)\n\r", (unsigned int)p_buf_in); + + if (!p_buf_in) + { + STHDPRINTK("(ERR) p_buf_in is NULL\n\r"); + return false; + } + + memcpy((void *)(&(s5ptv_status.hdmi_av_info_frame)), + (const void *)p_buf_in, sizeof(s5p_hdmi_video_infoframe)); + + memcpy((void *)(s5ptv_status.avi_byte), + (const void *)(s5ptv_status.hdmi_av_info_frame.data), 13); + s5ptv_status.hdmi_av_info_frame.data = s5ptv_status.avi_byte; + + STHDPRINTK("(0x%08x)\n\r", + (unsigned int)&s5ptv_status.hdmi_av_info_frame); + + return true; +} + +static bool _s5p_hdmi_video_init_mpg_infoframe(unsigned long p_buf_in) +{ + STHDPRINTK("(0x%x)\n\r", (unsigned int)p_buf_in); + + if (!p_buf_in) + { + STHDPRINTK("(ERR) p_buf_in is NULL\n\r"); + return false; + } + + memcpy((void *)(&(s5ptv_status.hdmi_mpg_info_frame)), + (const void *)p_buf_in, sizeof(s5p_hdmi_video_infoframe)); + + memcpy((void *)(s5ptv_status.mpg_byte), + (const void *)(s5ptv_status.hdmi_mpg_info_frame.data), 5); + s5ptv_status.hdmi_mpg_info_frame.data = s5ptv_status.avi_byte; + + STHDPRINTK("(0x%08x)\n\r", + (unsigned int)&s5ptv_status.hdmi_mpg_info_frame); + + return true; +} + +static bool _s5p_hdmi_video_set_bluescreen(unsigned long p_buf_in) +{ + STHDPRINTK("(0x%x)\n\r", (unsigned int)p_buf_in); + + if (!p_buf_in) + { + STHDPRINTK("(ERR) p_buf_in is NULL\n\r"); + return false; + } + + memcpy((void *)(&(s5ptv_status.hdmi_video_blue_screen)), + (const void *)p_buf_in, sizeof(s5p_hdmi_bluescreen)); + + __s5p_hdmi_video_set_bluescreen(s5ptv_status.hdmi_video_blue_screen.en, + s5ptv_status.hdmi_video_blue_screen.cb_b, + s5ptv_status.hdmi_video_blue_screen.y_g, + s5ptv_status.hdmi_video_blue_screen.cr_r); + + STHDPRINTK("(0x%08x)\n\r", + (unsigned int)&s5ptv_status.hdmi_video_blue_screen); + + return true; +} + +*/ + diff --git a/drivers/media/video/samsung/tv20/s5p_stda_tvout_if.c b/drivers/media/video/samsung/tv20/s5p_stda_tvout_if.c new file mode 100644 index 0000000..2d22d9e --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_stda_tvout_if.c @@ -0,0 +1,1261 @@ +/* linux/drivers/media/video/samsung/tv20/s5p_stda_tvout_if.c + * + * TVOut interface ftn. file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/ioctl.h> +#include <linux/fs.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/delay.h> + +#include <plat/clock.h> + +#include "s5p_tv.h" + +#ifdef COFIG_TVOUT_DBG +#define S5P_STDA_TVOUTIF_DEBUG 1 +#endif + +#ifdef S5P_STDA_TVOUTIF_DEBUG +#define TVOUTIFPRINTK(fmt, args...) \ + printk(KERN_INFO "\t[TVOUT_IF] %s: " fmt, __func__ , ## args) +#else +#define TVOUTIFPRINTK(fmt, args...) +#endif + +bool _s5p_tv_if_init_param(void) +{ + struct s5p_tv_status *st = &s5ptv_status; + + /* Initialize GRPx Layer Parameters to Default Values */ + st->grp_burst = VM_BURST_16; + st->grp_endian = TVOUT_LITTLE_ENDIAN_MODE; + + /* Initialize BG Layer Parameters to Default Values */ + st->bg_dither.cr_dither_en = false; + st->bg_dither.cb_dither_en = false; + st->bg_dither.y_dither_en = false; + + st->bg_color[0].color_y = 0; + st->bg_color[0].color_cb = 128; + st->bg_color[0].color_cr = 128; + st->bg_color[1].color_y = 0; + st->bg_color[1].color_cb = 128; + st->bg_color[1].color_cr = 128; + st->bg_color[2].color_y = 0; + st->bg_color[2].color_cb = 128; + st->bg_color[2].color_cr = 128; + + /* Initialize Video Mixer Parameters to Default Values */ + st->vm_csc_coeff_default = true; + + /* Initialize SDout Parameters to Default Values */ + st->sdout_sync_pin = SDOUT_SYNC_SIG_YG; + st->sdout_vbi.wss_cvbs = true; + st->sdout_vbi.caption_cvbs = SDOUT_INS_OTHERS; + st->sdout_vbi.wss_y_svideo = true; + st->sdout_vbi.caption_y_svideo = SDOUT_INS_OTHERS; + st->sdout_vbi.cgmsa_rgb = true; + st->sdout_vbi.wss_rgb = true; + st->sdout_vbi.caption_rgb = SDOUT_INS_OTHERS; + st->sdout_vbi.cgmsa_y_pb_pr = true; + st->sdout_vbi.wss_y_pb_pr = true; + st->sdout_vbi.caption_y_pb_pr = SDOUT_INS_OTHERS; + st->sdout_offset_gain[0].channel = SDOUT_CHANNEL_0; + st->sdout_offset_gain[0].offset = 0; + st->sdout_offset_gain[0].gain = 0x800; + st->sdout_offset_gain[1].channel = SDOUT_CHANNEL_1; + st->sdout_offset_gain[1].offset = 0; + st->sdout_offset_gain[1].gain = 0x800; + st->sdout_offset_gain[2].channel = SDOUT_CHANNEL_2; + st->sdout_offset_gain[2].offset = 0; + st->sdout_offset_gain[2].gain = 0x800; + st->sdout_delay.delay_y = 0x00; + st->sdout_delay.offset_video_start = 0xfa; + st->sdout_delay.offset_video_end = 0x00; + st->sdout_color_sub_carrier_phase_adj = false; + st->sdout_bri_hue_set.bright_hue_sat_adj = false; + st->sdout_bri_hue_set.gain_brightness = 0x80; + st->sdout_bri_hue_set.offset_brightness = 0x00; + st->sdout_bri_hue_set.gain0_cb_hue_saturation = 0x00; + st->sdout_bri_hue_set.gain1_cb_hue_saturation = 0x00; + st->sdout_bri_hue_set.gain0_cr_hue_saturation = 0x00; + st->sdout_bri_hue_set.gain1_cr_hue_saturation = 0x00; + st->sdout_bri_hue_set.offset_cb_hue_saturation = 0x00; + st->sdout_bri_hue_set.offset_cr_hue_saturation = 0x00; + st->sdout_y_pb_pr_comp = false; + st->sdout_rgb_compen.rgb_color_compensation = false; + st->sdout_rgb_compen.max_rgb_cube = 0xeb; + st->sdout_rgb_compen.min_rgb_cube = 0x10; + st->sdout_cvbs_compen.cvbs_color_compensation = false; + st->sdout_cvbs_compen.y_lower_mid = 0x200; + st->sdout_cvbs_compen.y_bottom = 0x000; + st->sdout_cvbs_compen.y_top = 0x3ff; + st->sdout_cvbs_compen.y_upper_mid = 0x200; + st->sdout_cvbs_compen.radius = 0x1ff; + st->sdout_svideo_compen.y_color_compensation = false; + st->sdout_svideo_compen.y_top = 0x3ff; + st->sdout_svideo_compen.y_bottom = 0x000; + st->sdout_svideo_compen.yc_cylinder = 0x1ff; + st->sdout_comp_porch.back_525 = 0x8a; + st->sdout_comp_porch.front_525 = 0x359; + st->sdout_comp_porch.back_625 = 0x96; + st->sdout_comp_porch.front_625 = 0x35c; + st->sdout_rgb_sync.sync_type = SDOUT_VESA_RGB_SYNC_COMPOSITE; + st->sdout_rgb_sync.vsync_active = TVOUT_POL_ACTIVE_HIGH; + st->sdout_rgb_sync.hsync_active = TVOUT_POL_ACTIVE_HIGH; + st->sdout_xtalk_cc[0].channel = SDOUT_CHANNEL_0; + st->sdout_xtalk_cc[0].coeff2 = 0; + st->sdout_xtalk_cc[0].coeff1 = 0; + st->sdout_xtalk_cc[1].channel = SDOUT_CHANNEL_1; + st->sdout_xtalk_cc[1].coeff2 = 0; + st->sdout_xtalk_cc[1].coeff1 = 0; + st->sdout_xtalk_cc[2].channel = SDOUT_CHANNEL_2; + st->sdout_xtalk_cc[2].coeff2 = 0; + st->sdout_xtalk_cc[2].coeff1 = 0; + st->sdout_closed_capt.display_cc = 0; + st->sdout_closed_capt.nondisplay_cc = 0; + st->sdout_wss_525.copy_permit = SDO_525_COPY_PERMIT; + st->sdout_wss_525.mv_psp = SDO_525_MV_PSP_OFF; + st->sdout_wss_525.copy_info = SDO_525_COPY_INFO; + st->sdout_wss_525.analog_on = false; + st->sdout_wss_525.display_ratio = SDO_525_4_3_NORMAL; + st->sdout_wss_625.surroun_f_sound = false; + st->sdout_wss_625.copyright = false; + st->sdout_wss_625.copy_protection = false; + st->sdout_wss_625.text_subtitles = false; + st->sdout_wss_625.open_subtitles = SDO_625_NO_OPEN_SUBTITLES; + st->sdout_wss_625.camera_film = SDO_625_CAMERA; + st->sdout_wss_625.color_encoding = SDO_625_NORMAL_PAL; + st->sdout_wss_625.helper_signal = false; + st->sdout_wss_625.display_ratio = SDO_625_4_3_FULL_576; + st->sdout_cgms_525.copy_permit = SDO_525_COPY_PERMIT; + st->sdout_cgms_525.mv_psp = SDO_525_MV_PSP_OFF; + st->sdout_cgms_525.copy_info = SDO_525_COPY_INFO; + st->sdout_cgms_525.analog_on = false; + st->sdout_cgms_525.display_ratio = SDO_525_4_3_NORMAL; + st->sdout_cgms_625.surroun_f_sound = false; + st->sdout_cgms_625.copyright = false; + st->sdout_cgms_625.copy_protection = false; + st->sdout_cgms_625.text_subtitles = false; + st->sdout_cgms_625.open_subtitles = SDO_625_NO_OPEN_SUBTITLES; + st->sdout_cgms_625.camera_film = SDO_625_CAMERA; + st->sdout_cgms_625.color_encoding = SDO_625_NORMAL_PAL; + st->sdout_cgms_625.helper_signal = false; + st->sdout_cgms_625.display_ratio = SDO_625_4_3_FULL_576; + + /* Initialize HDMI video Parameters to Default Values */ + st->hdmi_video_blue_screen.enable = false; + st->hdmi_color_range.y_min = 1; + st->hdmi_color_range.y_max = 254; + st->hdmi_color_range.c_min = 1; + st->hdmi_color_range.c_max = 254; + st->hdmi_av_info_frame.trans_type = HDMI_DO_NOT_TANS; + st->hdmi_av_info_frame.check_sum = 0; + st->hdmi_av_info_frame.data = st->avi_byte; + st->hdmi_mpg_info_frame.trans_type = HDMI_DO_NOT_TANS; + st->hdmi_mpg_info_frame.check_sum = 0; + st->hdmi_mpg_info_frame.data = st->mpg_byte; + memset((void *)(st->avi_byte), 0, 13); + memset((void *)(st->mpg_byte), 0, 5); + st->hdmi_tg_cmd.timing_correction_en = false; + st->hdmi_tg_cmd.bt656_sync_en = false; + st->hdmi_tg_cmd.tg_en = false; + + /* Initialize HDMI Parameters to Default Values */ + st->hdmi_spd_info_frame.trans_type = HDMI_TRANS_EVERY_SYNC; + st->hdmi_spd_info_frame.spd_header = NULL; + st->hdmi_spd_info_frame.spd_data = NULL; + + st->hdcp_en = false; + st->hdmi_audio_type = HDMI_AUDIO_PCM; + + st->tvout_param_available = true; + + return true; +} + + +bool _s5p_tv_if_init_vm_reg(void) +{ + u8 i = 0; + enum s5p_tv_vmx_err merr = 0; + struct s5p_tv_status *st = &s5ptv_status; + enum s5p_tv_o_mode out_mode = st->tvout_param.out_mode; + enum s5p_tv_disp_mode disp_mode = st->tvout_param.disp_mode; + + bool cr_en = st->bg_dither.cr_dither_en; + bool cb_en = st->bg_dither.cr_dither_en; + bool y_en = st->bg_dither.cr_dither_en; + + enum s5p_vmx_burst_mode burst = st->grp_burst; + enum s5p_endian_type endian = st->grp_endian; + + + merr = __s5p_vm_init_status_reg(burst, endian); + + if (merr != VMIXER_NO_ERROR) + return false; + + + merr = __s5p_vm_init_display_mode(disp_mode, out_mode); + + if (merr != VMIXER_NO_ERROR) + return false; + + + __s5p_vm_init_bg_dither_enable(cr_en, cb_en, y_en); + + for (i = VMIXER_BG_COLOR_0; i <= VMIXER_BG_COLOR_2; i++) { + merr = __s5p_vm_init_bg_color(i, + st->bg_color[i].color_y, + st->bg_color[i].color_cb, + st->bg_color[i].color_cr); + + if (merr != VMIXER_NO_ERROR) + return false; + } + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + __s5p_vm_init_csc_coef_default(VMIXER_CSC_RGB_TO_YUV601_FR); + break; + + case TVOUT_OUTPUT_HDMI_RGB: + case TVOUT_OUTPUT_HDMI: + case TVOUT_OUTPUT_DVI: + + switch (disp_mode) { + + case TVOUT_NTSC_M: + + case TVOUT_PAL_BDGHI: + + case TVOUT_PAL_M: + + case TVOUT_PAL_N: + + case TVOUT_PAL_NC: + + case TVOUT_PAL_60: + + case TVOUT_NTSC_443: + break; + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: +#ifdef CONFIG_CPU_S5PV210 + case TVOUT_480P_59: +#endif + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + __s5p_vm_init_csc_coef_default( + VMIXER_CSC_RGB_TO_YUV601_FR); + break; + + case TVOUT_720P_60: + + case TVOUT_720P_50: + +#ifdef CONFIG_CPU_S5PV210 + case TVOUT_720P_59: + + case TVOUT_1080I_60: + + case TVOUT_1080I_59: + + case TVOUT_1080I_50: + + case TVOUT_1080P_60: + + case TVOUT_1080P_30: + + case TVOUT_1080P_59: + + case TVOUT_1080P_50: +#endif + __s5p_vm_init_csc_coef_default( + VMIXER_CSC_RGB_TO_YUV709_FR); + break; + } + + break; + + default: + TVOUTIFPRINTK("invalid tvout_param.out_mode parameter(%d)\n\r", + out_mode); + return false; + break; + } + + __s5p_vm_start(); + + return true; +} + +bool _s5p_tv_if_init_sd_reg(void) +{ + u8 i = 0; + enum s5p_tv_sd_err sderr = 0; + struct s5p_tv_status *st = &s5ptv_status; + enum s5p_tv_o_mode out_mode = st->tvout_param.out_mode; + enum s5p_tv_disp_mode disp_mode = st->tvout_param.disp_mode; + enum s5p_sd_order order = st->sdout_order; + + u32 delay = st->sdout_delay.delay_y; + u32 off_v_start = st->sdout_delay.offset_video_start; + u32 off_v_end = st->sdout_delay.offset_video_end; + + u32 g_bright = st->sdout_bri_hue_set.gain_brightness; + u32 off_bright = st->sdout_bri_hue_set.offset_brightness; + u32 g0_cb_h_sat = st->sdout_bri_hue_set.gain0_cb_hue_saturation; + u32 g1_cb_h_sat = st->sdout_bri_hue_set.gain1_cb_hue_saturation; + u32 g0_cr_h_sat = st->sdout_bri_hue_set.gain0_cr_hue_saturation; + u32 g1_cr_h_sat = st->sdout_bri_hue_set.gain1_cr_hue_saturation; + u32 off_cb_h_sat = st->sdout_bri_hue_set.offset_cb_hue_saturation; + u32 off_cr_h_sat = st->sdout_bri_hue_set.offset_cr_hue_saturation; + + u32 max_rgb_cube = st->sdout_rgb_compen.max_rgb_cube; + u32 min_rgb_cube = st->sdout_rgb_compen.min_rgb_cube; + u32 y_l_m_c = st->sdout_cvbs_compen.y_lower_mid; + u32 y_b_c = st->sdout_cvbs_compen.y_bottom; + u32 y_t_c = st->sdout_cvbs_compen.y_top; + u32 y_u_m_c = st->sdout_cvbs_compen.y_upper_mid; + u32 rad_c = st->sdout_cvbs_compen.radius; + u32 y_t_s = st->sdout_svideo_compen.y_top; + u32 y_b_s = st->sdout_svideo_compen.y_bottom; + u32 y_cylinder_s = st->sdout_svideo_compen.yc_cylinder; + + u32 back_525 = st->sdout_comp_porch.back_525; + u32 front_525 = st->sdout_comp_porch.front_525; + u32 back_625 = st->sdout_comp_porch.back_625; + u32 front_625 = st->sdout_comp_porch.front_625; + + u32 display_cc = st->sdout_closed_capt.display_cc; + u32 nondisplay_cc = st->sdout_closed_capt.nondisplay_cc; + + bool br_hue_sat_adj = st->sdout_bri_hue_set.bright_hue_sat_adj; + bool wss_cvbs = st->sdout_vbi.wss_cvbs; + bool wss_y_svideo = st->sdout_vbi.wss_y_svideo; + bool cgmsa_rgb = st->sdout_vbi.cgmsa_rgb; + bool wss_rgb = st->sdout_vbi.wss_rgb; + bool cgmsa_y = st->sdout_vbi.cgmsa_y_pb_pr; + bool wss_y = st->sdout_vbi.wss_y_pb_pr; + bool phase_adj = st->sdout_color_sub_carrier_phase_adj; + bool ypbpr_comp = st->sdout_y_pb_pr_comp; + bool rgb_compen = st->sdout_rgb_compen.rgb_color_compensation; + bool y_compen = st->sdout_svideo_compen.y_color_compensation; + bool cvbs_compen = st->sdout_cvbs_compen.cvbs_color_compensation; + + bool w5_analog_on = st->sdout_wss_525.analog_on; + bool w6_surroun_f_sound = st->sdout_wss_625.surroun_f_sound; + bool w6_copyright = st->sdout_wss_625.copyright; + bool w6_copy_protection = st->sdout_wss_625.copy_protection; + bool w6_text_subtitles = st->sdout_wss_625.text_subtitles; + bool w6_helper_signal = st->sdout_wss_625.helper_signal; + + bool c5_analog_on = st->sdout_cgms_525.analog_on; + bool c6_surroun_f_sound = st->sdout_cgms_625.surroun_f_sound; + bool c6_copyright = st->sdout_cgms_625.copyright; + bool c6_copy_protection = st->sdout_cgms_625.copy_protection; + bool c6_text_subtitles = st->sdout_cgms_625.text_subtitles; + bool c6_helper_signal = st->sdout_cgms_625.helper_signal; + + enum s5p_sd_level cpn_lev = st->sdout_video_scale_cfg.component_level; + enum s5p_sd_level cps_lev = st->sdout_video_scale_cfg.composite_level; + enum s5p_sd_vsync_ratio cpn_rat = + st->sdout_video_scale_cfg.component_ratio; + enum s5p_sd_vsync_ratio cps_rat = + st->sdout_video_scale_cfg.composite_ratio; + enum s5p_sd_closed_caption_type cap_cvbs = st->sdout_vbi.caption_cvbs; + enum s5p_sd_closed_caption_type cap_y_svideo = + st->sdout_vbi.caption_y_svideo; + enum s5p_sd_closed_caption_type cap_rgb = st->sdout_vbi.caption_rgb; + enum s5p_sd_closed_caption_type cap_y_pb_pr = + st->sdout_vbi.caption_y_pb_pr; + enum s5p_sd_sync_sig_pin sync_pin = st->sdout_sync_pin; + enum s5p_sd_vesa_rgb_sync_type sync_type = + st->sdout_rgb_sync.sync_type; + enum s5p_tv_active_polarity vsync_active = + st->sdout_rgb_sync.vsync_active; + enum s5p_tv_active_polarity hsync_active = + st->sdout_rgb_sync.hsync_active; + + enum s5p_sd_525_copy_permit w5_copy_permit = + st->sdout_wss_525.copy_permit; + enum s5p_sd_525_mv_psp w5_mv_psp = st->sdout_wss_525.mv_psp; + enum s5p_sd_525_copy_info w5_copy_info = st->sdout_wss_525.copy_info; + enum s5p_sd_525_aspect_ratio w5_display_ratio = + st->sdout_wss_525.display_ratio; + enum s5p_sd_625_subtitles w6_open_subtitles = + st->sdout_wss_625.open_subtitles; + enum s5p_sd_625_camera_film w6_camera_film = + st->sdout_wss_625.camera_film; + enum s5p_sd_625_color_encoding w6_color_encoding = + st->sdout_wss_625.color_encoding; + enum s5p_sd_625_aspect_ratio w6_display_ratio = + st->sdout_wss_625.display_ratio; + + enum s5p_sd_525_copy_permit c5_copy_permit = + st->sdout_cgms_525.copy_permit; + enum s5p_sd_525_mv_psp c5_mv_psp = st->sdout_cgms_525.mv_psp; + enum s5p_sd_525_copy_info c5_copy_info = + st->sdout_cgms_525.copy_info; + enum s5p_sd_525_aspect_ratio c5_display_ratio = + st->sdout_cgms_525.display_ratio; + enum s5p_sd_625_subtitles c6_open_subtitles = + st->sdout_cgms_625.open_subtitles; + enum s5p_sd_625_camera_film c6_camera_film = + st->sdout_cgms_625.camera_film; + enum s5p_sd_625_color_encoding c6_color_encoding = + st->sdout_cgms_625.color_encoding; + enum s5p_sd_625_aspect_ratio c6_display_ratio = + st->sdout_cgms_625.display_ratio; + + __s5p_sdout_sw_reset(true); + + sderr = __s5p_sdout_init_display_mode(disp_mode, out_mode, order); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + sderr = __s5p_sdout_init_video_scale_cfg(cpn_lev, cpn_rat, + cps_lev, cps_rat); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + sderr = __s5p_sdout_init_sync_signal_pin(sync_pin); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + sderr = __s5p_sdout_init_vbi(wss_cvbs, cap_cvbs, wss_y_svideo, + cap_y_svideo, cgmsa_rgb, wss_rgb, cap_rgb, cgmsa_y, + wss_y, cap_y_pb_pr); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + for (i = SDOUT_CHANNEL_0; i <= SDOUT_CHANNEL_2; i++) { + + u32 offset = st->sdout_offset_gain[i].offset; + u32 gain = st->sdout_offset_gain[i].gain; + + sderr = __s5p_sdout_init_offset_gain(i, offset, gain); + + if (sderr != SDOUT_NO_ERROR) + return false; + } + + + __s5p_sdout_init_delay(delay, off_v_start, off_v_end); + + __s5p_sdout_init_schlock(phase_adj); + + __s5p_sdout_init_color_compensaton_onoff(br_hue_sat_adj, ypbpr_comp, + rgb_compen, y_compen, cvbs_compen); + + __s5p_sdout_init_brightness_hue_saturation(g_bright, off_bright, + g0_cb_h_sat, g1_cb_h_sat, g0_cr_h_sat, + g1_cr_h_sat, off_cb_h_sat, + off_cr_h_sat); + + __s5p_sdout_init_rgb_color_compensation(max_rgb_cube, min_rgb_cube); + + __s5p_sdout_init_cvbs_color_compensation(y_l_m_c, y_b_c, y_t_c, + y_u_m_c, rad_c); + + __s5p_sdout_init_svideo_color_compensation(y_t_s, y_b_s, y_cylinder_s); + + __s5p_sdout_init_component_porch(back_525, front_525, back_625, + front_625); + + sderr = __s5p_sdout_init_vesa_rgb_sync(sync_type, vsync_active, + hsync_active); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + for (i = SDOUT_CHANNEL_0; i <= SDOUT_CHANNEL_2; i++) { + enum s5p_sd_channel_sel channel = st->sdout_xtalk_cc[i].channel; + u32 coeff1 = st->sdout_xtalk_cc[i].coeff1; + u32 coeff2 = st->sdout_xtalk_cc[i].coeff2; + + sderr = __s5p_sdout_init_ch_xtalk_cancel_coef(channel, + coeff2, coeff1); + + if (sderr != SDOUT_NO_ERROR) + return false; + } + + __s5p_sdout_init_closed_caption(display_cc, nondisplay_cc); + + sderr = __s5p_sdout_init_wss525_data(w5_copy_permit, w5_mv_psp, + w5_copy_info, w5_analog_on, w5_display_ratio); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + sderr = __s5p_sdout_init_wss625_data(w6_surroun_f_sound, w6_copyright, + w6_copy_protection, w6_text_subtitles, + w6_open_subtitles, w6_camera_film, + w6_color_encoding, w6_helper_signal, + w6_display_ratio); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + sderr = __s5p_sdout_init_cgmsa525_data(c5_copy_permit, c5_mv_psp, + c5_copy_info, c5_analog_on, + c5_display_ratio); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + sderr = __s5p_sdout_init_cgmsa625_data(c6_surroun_f_sound, c6_copyright, + c6_copy_protection, c6_text_subtitles, + c6_open_subtitles, c6_camera_film, + c6_color_encoding, c6_helper_signal, + c6_display_ratio); + + if (sderr != SDOUT_NO_ERROR) + return false; + + + /* Disable All Interrupt */ + __s5p_sdout_set_interrupt_enable(false); + + /* Clear All Interrupt Pending */ + __s5p_sdout_clear_interrupt_pending(); + + __s5p_sdout_start(); + + __s5p_tv_powerset_dac_onoff(true); + + for (i = SDOUT_CHANNEL_0; i <= SDOUT_CHANNEL_2; i++) { + + bool dac = st->sdout_dac_on[i]; + + sderr = __s5p_sdout_init_dac_power_onoff(i, dac); + + if (sderr != SDOUT_NO_ERROR) + return false; + } + + return true; +} + +unsigned char _s5p_tv_if_video_avi_checksum(void) +{ + u8 i; + u32 sum = 0; + struct s5p_tv_status *st = &s5ptv_status; + + for (i = 0; i < 13; i++) + sum += (u32)(st->avi_byte[i]); + + + return (u8)(0x100 - ((0x91 + sum) & 0xff)); +} + +bool _s5p_tv_if_init_avi_frame(struct tvout_output_if *tvout_if) +{ + struct s5p_tv_status *st = &s5ptv_status; + TVOUTIFPRINTK("(%d, %d)\n\r", tvout_if->disp_mode, + tvout_if->out_mode); + + st->hdmi_av_info_frame.trans_type = HDMI_TRANS_EVERY_SYNC; + st->avi_byte[1] = AVI_ITU709; + st->avi_byte[4] = AVI_NO_PIXEL_REPEAT; + + switch (tvout_if->disp_mode) { + +#ifdef CONFIG_CPU_S5PV210 + case TVOUT_480P_59: +#endif + case TVOUT_480P_60_16_9: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU601; + st->avi_byte[3] = AVI_VIC_3; + break; + + case TVOUT_480P_60_4_3: + st->avi_byte[1] = AVI_PAR_4_3 | AVI_ITU601; + st->avi_byte[3] = AVI_VIC_2; + break; + + case TVOUT_576P_50_16_9: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU601; + st->avi_byte[3] = AVI_VIC_18; + break; + + case TVOUT_576P_50_4_3: + st->avi_byte[1] = AVI_PAR_4_3 | AVI_ITU601; + st->avi_byte[3] = AVI_VIC_17; + break; + + case TVOUT_720P_50: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU709; + st->avi_byte[3] = AVI_VIC_19; + break; + + case TVOUT_720P_60: +#ifdef CONFIG_CPU_S5PV210 + case TVOUT_720P_59: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU709; + st->avi_byte[3] = AVI_VIC_4; + break; + + case TVOUT_1080I_50: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU709; + st->avi_byte[3] = AVI_VIC_20; + break; + + case TVOUT_1080I_59: + case TVOUT_1080I_60: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU709; + st->avi_byte[3] = AVI_VIC_5; + break; + + case TVOUT_1080P_50: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU709; + st->avi_byte[3] = AVI_VIC_31; + break; + + case TVOUT_1080P_30: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU709; + st->avi_byte[3] = AVI_VIC_34; + + case TVOUT_1080P_59: + case TVOUT_1080P_60: + st->avi_byte[1] = AVI_PAR_16_9 | AVI_ITU709; + st->avi_byte[3] = AVI_VIC_16; + break; +#endif + default: + TVOUTIFPRINTK("invalid disp_mode parameter(%d)\n\r", + tvout_if->out_mode); + return false; + break; + } + + switch (tvout_if->out_mode) { + + case TVOUT_OUTPUT_DVI: + st->hdmi_av_info_frame.trans_type = HDMI_DO_NOT_TANS; + st->avi_byte[0] = AVI_RGB_IF; + break; + + case TVOUT_OUTPUT_HDMI_RGB: + st->hdmi_av_info_frame.trans_type = HDMI_TRANS_EVERY_SYNC; + st->avi_byte[0] = AVI_RGB_IF; + break; + + case TVOUT_OUTPUT_HDMI: + st->hdmi_av_info_frame.trans_type = HDMI_TRANS_EVERY_SYNC; + st->avi_byte[0] = AVI_YCBCR444_IF; + break; + + default: + TVOUTIFPRINTK("invalid out_mode parameter(%d)\n\r", + tvout_if->out_mode); + return false; + break; + } + + st->avi_byte[1] |= AVI_SAME_WITH_PICTURE_AR; + + TVOUTIFPRINTK("()\n\r"); + return true; +} + +bool _s5p_tv_if_init_hd_video_reg(void) +{ + enum s5p_tv_hdmi_err herr = 0; + enum s5p_tv_hdmi_csc_type cscType; + struct s5p_tv_status *st = &s5ptv_status; + + u8 cb_b = st->hdmi_video_blue_screen.cb_b; + u8 y_g = st->hdmi_video_blue_screen.y_g; + u8 cr_r = st->hdmi_video_blue_screen.cr_r; + + u8 y_min = st->hdmi_color_range.y_min; + u8 y_max = st->hdmi_color_range.y_max; + u8 c_min = st->hdmi_color_range.c_min; + u8 c_max = st->hdmi_color_range.c_max; + + enum s5p_tv_disp_mode disp_mode = st->tvout_param.disp_mode; + enum s5p_tv_o_mode out_mode = st->tvout_param.out_mode; + + enum s5p_hdmi_transmit *a_trans_type = + &st->hdmi_av_info_frame.trans_type; + u8 *a_check_sum = &st->hdmi_av_info_frame.check_sum; + u8 *a_data = st->hdmi_av_info_frame.data; + + enum s5p_hdmi_transmit m_trans_type = + st->hdmi_mpg_info_frame.trans_type; + u8 m_check_sum = st->hdmi_mpg_info_frame.check_sum; + u8 *m_data = st->hdmi_mpg_info_frame.data; + + enum s5p_hdmi_transmit s_trans_type = + st->hdmi_spd_info_frame.trans_type; + u8 *spd_header = st->hdmi_spd_info_frame.spd_header; + u8 *spd_data = st->hdmi_spd_info_frame.spd_data; + + if (!_s5p_tv_if_init_avi_frame(&st->tvout_param)) { + st->tvout_param_available = false; + return false; + } + + herr = __s5p_hdmi_video_init_display_mode(disp_mode, out_mode, a_data); + + if (herr != HDMI_NO_ERROR) + return false; + + st->hdmi_av_info_frame.check_sum = _s5p_tv_if_video_avi_checksum(); + + if (!st->hdcp_en) + __s5p_hdmi_video_init_bluescreen( + st->hdmi_video_blue_screen.enable, + cb_b, y_g, cr_r); + + __s5p_hdmi_video_init_color_range(y_min, y_max, c_min, c_max); + + switch (out_mode) { + + case TVOUT_OUTPUT_HDMI_RGB: + case TVOUT_OUTPUT_HDMI: + cscType = HDMI_BYPASS; + break; + + case TVOUT_OUTPUT_DVI: + cscType = HDMI_CSC_YUV601_TO_RGB_LR; + s_trans_type = HDMI_DO_NOT_TANS; + break; + + default: + TVOUTIFPRINTK("invalid out_mode parameter(%d)\n\r", + out_mode); + return false; + break; + } + + herr = __s5p_hdmi_video_init_csc(cscType); + + if (herr != HDMI_NO_ERROR) + return false; + + + herr = __s5p_hdmi_video_init_avi_infoframe(*a_trans_type, + *a_check_sum, a_data); + + if (herr != HDMI_NO_ERROR) + return false; + + + herr = __s5p_hdmi_video_init_mpg_infoframe(m_trans_type, + m_check_sum, m_data); + + if (herr != HDMI_NO_ERROR) + return false; + + + herr = __s5p_hdmi_init_spd_infoframe(s_trans_type, + spd_header, spd_data); + + if (herr != HDMI_NO_ERROR) + return false; + + return true; +} + +bool _s5p_tv_if_init_hd_reg(void) +{ + struct s5p_tv_status *st = &s5ptv_status; + bool timing_correction_en = st->hdmi_tg_cmd.timing_correction_en; + bool bt656_sync_en = st->hdmi_tg_cmd.bt656_sync_en; + bool tg_en; + + TVOUTIFPRINTK("audio type : %d, hdcp : %s)\n\r", + st->hdmi_audio_type, st->hdcp_en ? "enabled" : "disabled"); + +/* C110_HDCP: + if (st->hdcp_en) { + if (!(st->hpd_status)) { + TVOUTIFPRINTK("HPD is not detected\n\r"); + return false; + } + } +*/ + + if (!_s5p_tv_if_init_hd_video_reg()) + return false; + + switch (st->hdmi_audio_type) { + + case HDMI_AUDIO_PCM: + /* + * PCM, Samplingrate 44100, 16bit, + * ignore framesize cuz stream is PCM. + */ + __s5p_hdmi_audio_init(PCM, 44100, 16, 0); + break; + + case HDMI_AUDIO_NO: + break; + + default: + TVOUTIFPRINTK("invalid hdmi_audio_type(%d)\n\r", + st->hdmi_audio_type); + return false; + break; + } + + if (!__s5p_hdmi_start(st->hdmi_audio_type, + st->hdcp_en, + st->hdcp_i2c_client)) { + return false; + } + + st->hdmi_tg_cmd.tg_en = true; + tg_en = st->hdmi_tg_cmd.tg_en; + + __s5p_hdmi_video_init_tg_cmd(timing_correction_en, + bt656_sync_en, tg_en); + + return true; +} + +bool _s5p_tv_if_start(void) +{ + struct s5p_tv_status *st = &s5ptv_status; + +#ifdef CONFIG_CPU_S5PC100 + enum s5p_tv_clk_err cerr = HDMI_NO_ERROR; +#endif + + enum s5p_tv_o_mode out_mode = st->tvout_param.out_mode; + +#if 0 + __s5p_vm_set_underflow_interrupt_enable(VM_VIDEO_LAYER, + false); + __s5p_vm_set_underflow_interrupt_enable(VM_GPR0_LAYER, + false); + __s5p_vm_set_underflow_interrupt_enable(VM_GPR1_LAYER, + false); + + _s5p_tv_if_stop(); + + if (st->vp_layer_enable) { + _s5p_vlayer_stop(); + /* In order to start video layer on the s5p_tv_resume() + * or handle_calbe() function*/ + st->vp_layer_enable = true; + } + + /* Clear All Interrupt Pending*/ + __s5p_vm_clear_pend_all(); + +#endif + /* + * have not to call + * another request function simultaneously + */ +#ifdef CONFIG_CPU_S5PC100 + + enum s5p_tv_disp_mode disp_mode = st->tvout_param.disp_mode; + + if (!__s5p_tv_power_get_power_status()) + __s5p_tv_poweron(); + +#endif +#ifdef CONFIG_CPU_S5PV210 + /* move to tv_phy_power()*/ + /*__s5p_tv_poweron();*/ +#endif + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + +#ifdef CONFIG_CPU_S5PC100 + __s5p_tv_clk_init_video_mixer(TVOUT_CLK_VMIXER_SRCCLK_VCLK_54); + + __s5p_tv_clk_init_hpll(0xffff, 96, 6, 3); +#endif + +#ifdef CONFIG_CPU_S5PV210 + clk_set_parent(st->sclk_mixer, st->sclk_dac); +#endif + break; + + case TVOUT_OUTPUT_HDMI: + case TVOUT_OUTPUT_HDMI_RGB: + case TVOUT_OUTPUT_DVI: + +#ifdef CONFIG_CPU_S5PC100 + __s5p_tv_clk_init_video_mixer( + TVOUT_CLK_VMIXER_SRCCLK_MOUT_HPLL); + + cerr = __s5p_tv_clk_init_mout_hpll( + S5P_TV_CLK_MOUT_HPLL_FOUT_HPLL); + if (cerr != S5P_TV_CLK_ERR_NO_ERROR) + return false; +#endif + +#ifdef CONFIG_CPU_S5PV210 + clk_set_parent(st->sclk_mixer, st->sclk_hdmi); + clk_set_parent(st->sclk_hdmi, st->sclk_hdmiphy); +#endif + +#ifdef CONFIG_CPU_S5PC100 + + __s5p_tv_clk_init_hdmi_ratio(2); + + switch (disp_mode) { + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + __s5p_tv_clk_init_hpll(0xffff, 96, 6, 3); + break; + + + case TVOUT_720P_50: + + case TVOUT_720P_60: + __s5p_tv_clk_init_hpll(0xffff, 132, 6, 2); + break; + + default: + _s5p_tv_if_stop(); + TVOUTIFPRINTK("invalid out_mode parameter(%d)\n\r", + out_mode); + st->tvout_param_available = false; + return false; + break; + } +#endif + +#ifdef CONFIG_CPU_S5PC100 + __s5p_tv_poweroff(); + __s5p_tv_poweron(); +#endif + break; + + default: + _s5p_tv_if_stop(); + TVOUTIFPRINTK("invalid out_mode parameter(%d)\n\r", + st->tvout_param.out_mode); + st->tvout_param_available = false; + return false; + break; + } + + if (!_s5p_tv_if_init_vm_reg()) + return false; + + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + + if (!_s5p_tv_if_init_sd_reg()) + return false; + + + break; + + case TVOUT_OUTPUT_DVI: + st->hdmi_audio_type = HDMI_AUDIO_NO; + + case TVOUT_OUTPUT_HDMI: + case TVOUT_OUTPUT_HDMI_RGB: + if (!_s5p_tv_if_init_hd_reg()) + return false; + + + break; + + default: + _s5p_tv_if_stop(); + TVOUTIFPRINTK("invalid out_mode parameter(%d)\n\r", + out_mode); + return false; + break; + } + + st->tvout_output_enable = true; +#if 0 + __s5p_vm_set_underflow_interrupt_enable(VM_VIDEO_LAYER, + true); + __s5p_vm_set_underflow_interrupt_enable(VM_GPR0_LAYER, + true); + __s5p_vm_set_underflow_interrupt_enable(VM_GPR1_LAYER, + true); + + /* Clear All Interrupt Pending */ + __s5p_vm_clear_pend_all(); +#endif + TVOUTIFPRINTK("()\n\r"); + + return true; +} + +/* + * TV cut off sequence + * VP stop -> Mixer stop -> HDMI stop -> HDMI TG stop + * Above sequence should be satisfied. + */ +bool _s5p_tv_if_stop(void) +{ + struct s5p_tv_status *st = &s5ptv_status; + + bool t_corr_en = st->hdmi_tg_cmd.timing_correction_en; + bool sync_en = st->hdmi_tg_cmd.bt656_sync_en; + enum s5p_tv_o_mode out_mode = st->tvout_param.out_mode; + + TVOUTIFPRINTK("tvout sub sys. stopped!!\n"); + + __s5p_vm_stop(); + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + if (st->tvout_output_enable) + __s5p_sdout_stop(); + break; + + case TVOUT_OUTPUT_HDMI: + case TVOUT_OUTPUT_HDMI_RGB: + case TVOUT_OUTPUT_DVI: + if (st->tvout_output_enable) { + __s5p_hdmi_stop(); + __s5p_hdmi_video_init_tg_cmd(t_corr_en, sync_en, + false); + } + break; + + default: + TVOUTIFPRINTK("invalid out_mode parameter(%d)\n\r", out_mode); + return false; + break; + } + + +#ifdef CONFIG_CPU_S5PC100 + if (__s5p_tv_power_get_power_status()) { + __s5p_tv_clk_stop(); + __s5p_tv_poweroff(); + } +#endif + + st->tvout_output_enable = false; + st->tvout_param_available = false; + + return true; +} + +/* +* before call this ftn. set the status data!! +*/ +bool _s5p_tv_if_set_disp(void) +{ + struct s5p_tv_status *st = &s5ptv_status; + + enum s5p_tv_disp_mode disp_mode = st->tvout_param.disp_mode; + enum s5p_tv_o_mode out_mode = st->tvout_param.out_mode; + + TVOUTIFPRINTK("(%d, %d)\n\r", disp_mode, out_mode); + + switch (disp_mode) { + + case TVOUT_NTSC_M: + + case TVOUT_NTSC_443: + st->sdout_video_scale_cfg.component_level = + S5P_TV_SD_LEVEL_0IRE; + st->sdout_video_scale_cfg.component_ratio = + SDOUT_VTOS_RATIO_7_3; + st->sdout_video_scale_cfg.composite_level = + S5P_TV_SD_LEVEL_75IRE; + st->sdout_video_scale_cfg.composite_ratio = + SDOUT_VTOS_RATIO_10_4; + break; + + case TVOUT_PAL_BDGHI: + + case TVOUT_PAL_M: + + case TVOUT_PAL_N: + + case TVOUT_PAL_NC: + + case TVOUT_PAL_60: + st->sdout_video_scale_cfg.component_level = + S5P_TV_SD_LEVEL_0IRE; + st->sdout_video_scale_cfg.component_ratio = + SDOUT_VTOS_RATIO_7_3; + st->sdout_video_scale_cfg.composite_level = + S5P_TV_SD_LEVEL_0IRE; + st->sdout_video_scale_cfg.composite_ratio = + SDOUT_VTOS_RATIO_7_3; + break; + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + + case TVOUT_720P_50: + + case TVOUT_720P_60: + +#ifdef CONFIG_CPU_S5PV210 + + case TVOUT_1080I_50: + + case TVOUT_1080I_60: + + case TVOUT_1080P_50: + + case TVOUT_1080P_60: + + case TVOUT_1080P_30: + + case TVOUT_480P_59: + + case TVOUT_720P_59: + + case TVOUT_1080I_59: + + case TVOUT_1080P_59: +#endif + break; + default: + TVOUTIFPRINTK("invalid disp_mode parameter(%d)\n\r", + disp_mode); + st->tvout_param_available = false; + return false; + break; + } + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + st->sdout_order = S5P_TV_SD_O_ORDER_COMPOSITE_Y_C_CVBS; + st->sdout_dac_on[2] = false; + st->sdout_dac_on[1] = false; + st->sdout_dac_on[0] = true; + break; + + case TVOUT_OUTPUT_SVIDEO: + st->sdout_order = S5P_TV_SD_O_ORDER_COMPOSITE_C_Y_CVBS; + st->sdout_dac_on[2] = true; + st->sdout_dac_on[1] = true; + st->sdout_dac_on[0] = false; + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + st->sdout_order = S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY; + st->sdout_dac_on[2] = true; + st->sdout_dac_on[1] = true; + st->sdout_dac_on[0] = true; + break; + + case TVOUT_OUTPUT_HDMI_RGB: + case TVOUT_OUTPUT_HDMI: + case TVOUT_OUTPUT_DVI: + st->hdmi_video_blue_screen.cb_b = 0;/* 128 */; + st->hdmi_video_blue_screen.y_g = 0; + st->hdmi_video_blue_screen.cr_r = 0;/* 128 */; + break; + + default: + TVOUTIFPRINTK("invalid out_mode parameter(%d)\n\r", + out_mode); + st->tvout_param_available = false; + return false; + break; + } +#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_PM) + if ((st->hpd_status) && st->suspend_status == false) { +#endif + _s5p_tv_if_start(); +#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_PM) + } + /* If the cable is not inserted or system is on suspend mode + Just set variable, _s5p_tv_if_start() function will be called + in resume or handle_cable function according to this variable*/ + else + st->tvout_output_enable = true; +#endif + return true; +} + diff --git a/drivers/media/video/samsung/tv20/s5p_stda_video_layer.c b/drivers/media/video/samsung/tv20/s5p_stda_video_layer.c new file mode 100644 index 0000000..05a937d --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_stda_video_layer.c @@ -0,0 +1,924 @@ +/* linux/drivers/media/video/samsung/tv20/s5p_stda_video_layer.c + * + * Video Layer ftn. file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/delay.h> +#include <linux/ioctl.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/uaccess.h> + +#include "s5p_tv.h" + +#ifdef COFIG_TVOUT_DBG +#define S5P_VLAYER_DEBUG 1 +#endif + +#ifdef S5P_VLAYER_DEBUG +#define VLAYERPRINTK(fmt, args...) \ + printk(KERN_INFO "\t[VLAYER] %s: " fmt, __func__ , ## args) +#else +#define VLAYERPRINTK(fmt, args...) +#endif + +#define INTERLACED 0 +#define PROGRESSIVE 1 + +u8 check_input_mode(enum s5p_vp_src_color color) +{ + u8 ret = PROGRESSIVE; + + /* check i_mode */ + if (color == VPROC_SRC_COLOR_NV12IW || + color == VPROC_SRC_COLOR_TILE_NV12IW) + ret = INTERLACED; /* interlaced */ + else + ret = PROGRESSIVE; /* progressive */ + + return ret; +} + +u8 check_output_mode(enum s5p_tv_disp_mode display, + enum s5p_tv_o_mode out) +{ + u8 ret = PROGRESSIVE; + + switch (out) { + case TVOUT_OUTPUT_COMPOSITE: + case TVOUT_OUTPUT_SVIDEO: + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + ret = INTERLACED; + break; + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + case TVOUT_OUTPUT_HDMI_RGB: + case TVOUT_OUTPUT_HDMI: + case TVOUT_OUTPUT_DVI: +#ifdef CONFIG_CPU_S5PV210 + if (display == TVOUT_1080I_60 || + display == TVOUT_1080I_59 || + display == TVOUT_1080I_50) + + ret = INTERLACED; + else +#endif + ret = PROGRESSIVE; + break; + default: + break; + } + + return ret; + +} + + +static bool _s5p_vlayer_wait_previous_update(void) +{ + __s5p_vp_get_update_status(); + return false; +} + + +static void _s5p_vlayer_calc_inner_values(void) +{ + struct s5p_tv_status *st = &s5ptv_status; + struct s5p_vl_param *video = &(s5ptv_status.vl_basic_param); + u8 o_mode, i_mode; + + u32 t_y_addr = video->top_y_address; + u32 t_c_addr = video->top_c_address; + u32 img_w = video->img_width; + u32 s_ox = video->src_offset_x; + u32 s_oy = video->src_offset_y; + u32 d_ox = video->dest_offset_x; + u32 d_oy = video->dest_offset_y; + u32 s_w = video->src_width; + u32 s_h = video->src_height; + u32 d_w = video->dest_width; + u32 d_h = video->dest_height; + + i_mode = check_input_mode(st->src_color); + o_mode = check_output_mode(st->tvout_param.disp_mode, + st->tvout_param.out_mode); + + st->vl_top_y_address = t_y_addr; + st->vl_top_c_address = t_c_addr; + + if (st->src_color == VPROC_SRC_COLOR_NV12IW) { + st->vl_bottom_y_address = t_y_addr + img_w; + st->vl_bottom_c_address = t_c_addr + img_w; + } else if (st->src_color == VPROC_SRC_COLOR_TILE_NV12IW) { + st->vl_bottom_y_address = t_y_addr + 0x40; + st->vl_bottom_c_address = t_c_addr + 0x40; + } + + st->vl_src_offset_x = s_ox; + st->vl_src_offset_y = s_oy; + st->vl_src_width = s_w; + st->vl_src_height = s_h; + st->vl_dest_offset_x = d_ox; + st->vl_dest_offset_y = d_oy; + st->vl_dest_width = d_w; + st->vl_dest_height = d_h; + + + if (o_mode == INTERLACED) { + st->vl_src_height = s_h / 2; + st->vl_src_offset_y = s_oy / 2; + st->vl_dest_height = d_h / 2; + st->vl_dest_offset_y = d_oy / 2; + } else { + if (i_mode == INTERLACED) { + st->vl_src_height = s_h / 2; + st->vl_src_offset_y = s_oy / 2; + } + } +} + +bool _s5p_vlayer_start(void) +{ + int i; + + enum s5p_tv_vp_err verr; + enum s5p_tv_vmx_err merr; + struct s5p_video_img_address temp_addr; + struct s5p_img_size img_size; + + struct s5p_vl_param param = s5ptv_status.vl_basic_param; + + u8 contrast = s5ptv_status.vl_contrast; + + u32 ty_addr = s5ptv_status.vl_top_y_address; + u32 tc_addr = s5ptv_status.vl_top_c_address; + u32 by_addr = s5ptv_status.vl_bottom_y_address; + u32 bc_addr = s5ptv_status.vl_bottom_c_address; + u32 endian = param.src_img_endian; + u32 i_w = param.img_width; + u32 i_h = param.img_height; + u32 s_ox = s5ptv_status.vl_src_offset_x; + u32 s_xf = s5ptv_status.vl_src_x_fact_step; + u32 s_oy = s5ptv_status.vl_src_offset_y; + u32 s_w = s5ptv_status.vl_src_width; + u32 s_h = s5ptv_status.vl_src_height; + u32 d_ox = s5ptv_status.vl_dest_offset_x; + u32 d_oy = s5ptv_status.vl_dest_offset_y; + u32 d_w = s5ptv_status.vl_dest_width; + u32 d_h = s5ptv_status.vl_dest_height; + u32 noise = s5ptv_status.vl_sharpness.th_noise; + u32 saturation = s5ptv_status.vl_saturation; + u32 alpha = param.alpha; + u32 priority = param.priority; + u32 br_offset = s5ptv_status.vl_bright_offset; + + bool ipc = s5ptv_status.vl2d_ipc; + bool l_skip = s5ptv_status.vl_op_mode.line_skip; + bool bypass = s5ptv_status.vl_bypass_post_process; + bool po_def = s5ptv_status.vl_poly_filter_default; + bool bright = s5ptv_status.us_vl_brightness; + bool w_blend = param.win_blending; + bool csc_en = s5ptv_status.vl_csc_control.csc_en; + bool s_off_en = s5ptv_status.vl_csc_control.sub_y_offset_en; + bool csc_coef_def = s5ptv_status.vl_csc_coef_default; + + enum s5p_vp_field f_id = s5ptv_status.field_id; + enum s5p_vp_mem_mode m_mode = s5ptv_status.vl_op_mode.mem_mode; + enum s5p_vp_chroma_expansion cro_ex = + s5ptv_status.vl_op_mode.chroma_exp; + enum s5p_vp_filed_id_toggle f_id_tog = + s5ptv_status.vl_op_mode.toggle_id; + enum s5p_vp_pxl_rate p_rate = s5ptv_status.vl_rate; + enum s5p_vp_sharpness_control sharp = + s5ptv_status.vl_sharpness.sharpness; + enum s5p_vp_csc_type csc_type = s5ptv_status.vl_csc_type; + +#ifdef CONFIG_CPU_S5PC100 + __s5p_tv_clk_set_vp_clk_onoff(true); +#endif + __s5p_vp_sw_reset(); + __s5p_vp_init_field_id(f_id); + __s5p_vp_init_op_mode(l_skip, m_mode, cro_ex, f_id_tog); + __s5p_vp_init_pixel_rate_control(p_rate); + + temp_addr.y_address = param.top_y_address; + temp_addr.c_address = param.top_c_address; + img_size.img_width = param.img_width; + img_size.img_height = param.img_height; + + _s5p_vlayer_set_top_address((unsigned long)&temp_addr); + _s5p_vlayer_set_img_size((unsigned long)&img_size); + + img_size.img_width = param.src_width; + img_size.img_height = param.src_height; + _s5p_vlayer_set_src_size((unsigned long)&img_size); + + if (po_def) + verr = __s5p_vp_init_layer_def_poly_filter_coef(ty_addr, + tc_addr, by_addr, bc_addr, endian, i_w, i_h, s_ox, + s_xf, s_oy, s_w, s_h, d_ox, d_oy, d_w, d_h, ipc); + else + verr = __s5p_vp_init_layer(ty_addr, tc_addr, by_addr, bc_addr, + endian, i_w, i_h, s_ox, s_xf, s_oy, s_w, s_h, d_ox, + d_oy, d_w, d_h, ipc); + + if (verr != VPROC_NO_ERROR) + return false; + + __s5p_vp_init_bypass_post_process(bypass); + __s5p_vp_init_sharpness(noise, sharp); + __s5p_vp_init_saturation(saturation); + __s5p_vp_init_brightness(bright); + __s5p_vp_init_contrast(contrast); + + for (i = VProc_LINE_EQ_0; i <= VProc_LINE_EQ_7; i++) { + if (s5ptv_status.vl_bc_control[i].eq_num == i) + verr = __s5p_vp_init_brightness_contrast_control( + s5ptv_status.vl_bc_control[i].eq_num, + s5ptv_status.vl_bc_control[i].intc, + s5ptv_status.vl_bc_control[i].slope); + + if (verr != VPROC_NO_ERROR) + return false; + } + + __s5p_vp_init_brightness_offset(br_offset); + + __s5p_vp_init_csc_control(s_off_en, csc_en); + + if (csc_en && csc_coef_def) { + verr = __s5p_vp_init_csc_coef_default(csc_type); + + if (verr != VPROC_NO_ERROR) + return false; + } + + verr = __s5p_vp_start(); + + if (verr != VPROC_NO_ERROR) + return false; + +#ifdef CONFIG_CPU_S5PC100 + merr = __s5p_vm_init_layer(VM_VIDEO_LAYER, true, w_blend, alpha, + priority, VM_DIRECT_RGB565, false, + false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0); +#endif + +#ifdef CONFIG_CPU_S5PV210 + merr = __s5p_vm_init_layer(s5ptv_status.tvout_param.disp_mode, + VM_VIDEO_LAYER, true, w_blend, alpha, priority, + VM_DIRECT_RGB565, false, false, false, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +#endif + + if (merr != VPROC_NO_ERROR) + return false; + + __s5p_vm_start(); + + s5ptv_status.vp_layer_enable = true; + + return true; +} + +bool _s5p_vlayer_stop(void) +{ + enum s5p_tv_vp_err verr; + + __s5p_vm_set_layer_show(VM_VIDEO_LAYER, false); + + if (_s5p_vlayer_wait_previous_update()) + return false; + + verr = __s5p_vp_stop(); + + if (verr != VPROC_NO_ERROR) + return false; + +#ifdef CONFIG_CPU_S5PC100 + __s5p_tv_clk_set_vp_clk_onoff(false); +#endif + + s5ptv_status.vp_layer_enable = false; + + return true; +} + + +bool _s5p_vlayer_set_priority(unsigned long buf_in) +{ + enum s5p_tv_vmx_err merr; + u32 pri; + + s5ptv_status.vl_basic_param.priority = (unsigned int)(buf_in); + + pri = s5ptv_status.vl_basic_param.priority; + + merr = __s5p_vm_set_layer_priority(VM_VIDEO_LAYER, pri); + + if (merr != VMIXER_NO_ERROR) + return false; + + return true; +} + +bool _s5p_vlayer_set_blending(unsigned long buf_in) +{ + enum s5p_tv_vmx_err merr; + bool blend; + + s5ptv_status.vl_basic_param.win_blending = (bool)(buf_in); + blend = s5ptv_status.vl_basic_param.win_blending; + + merr = __s5p_vm_set_win_blend(VM_VIDEO_LAYER, blend); + + if (merr != VMIXER_NO_ERROR) + return false; + + return true; +} + +bool _s5p_vlayer_set_alpha(unsigned long buf_in) +{ + enum s5p_tv_vmx_err merr; + u32 alpha; + + s5ptv_status.vl_basic_param.alpha = (unsigned int)(buf_in); + alpha = s5ptv_status.vl_basic_param.alpha; + + merr = __s5p_vm_set_layer_alpha(VM_VIDEO_LAYER, alpha); + + if (merr != VMIXER_NO_ERROR) + return false; + + + return true; +} + +bool _s5p_vlayer_set_field_id(unsigned long buf_in) +{ + enum s5p_tv_vp_err verr; + + s5ptv_status.field_id = (enum s5p_vp_field)(buf_in); + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + __s5p_vp_set_field_id(s5ptv_status.field_id); + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + return true; +} + +bool _s5p_vlayer_set_top_address(unsigned long buf_in) +{ + u32 t_y_addr = 0; + u32 t_c_addr = 0; + u32 b_y_addr = 0; + u32 b_c_addr = 0; + + struct s5p_video_img_address *addr = + (struct s5p_video_img_address *)buf_in; + enum s5p_tv_vp_err verr; + + s5ptv_status.vl_basic_param.top_y_address = addr->y_address; + s5ptv_status.vl_basic_param.top_c_address = addr->c_address; + + _s5p_vlayer_calc_inner_values(); + + t_y_addr = s5ptv_status.vl_top_y_address; + t_c_addr = s5ptv_status.vl_top_c_address; + b_y_addr = s5ptv_status.vl_bottom_y_address; + b_c_addr = s5ptv_status.vl_bottom_c_address; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + verr = __s5p_vp_set_top_field_address(t_y_addr, t_c_addr); + + if (verr != VPROC_NO_ERROR) + return false; + + + if (check_input_mode(s5ptv_status.src_color) == INTERLACED) { + __s5p_vp_set_field_id(s5ptv_status.field_id); + verr = __s5p_vp_set_bottom_field_address(b_y_addr, b_c_addr); + + if (verr != VPROC_NO_ERROR) + return false; + } + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + return true; +} + +bool _s5p_vlayer_set_bottom_address(unsigned long buf_in) +{ + u32 t_y_addr = 0; + u32 t_c_addr = 0; + u32 b_y_addr = 0; + u32 b_c_addr = 0; + + u32 img_width = s5ptv_status.vl_basic_param.img_width; + + struct s5p_video_img_address *addr = + (struct s5p_video_img_address *)buf_in; + enum s5p_tv_vp_err verr; + enum s5p_vp_src_color s_color = s5ptv_status.src_color; + + if (s_color == VPROC_SRC_COLOR_NV12IW) { + s5ptv_status.vl_basic_param.top_y_address = + addr->y_address - img_width; + s5ptv_status.vl_basic_param.top_c_address = + addr->c_address - img_width; + } + + _s5p_vlayer_calc_inner_values(); + + t_y_addr = s5ptv_status.vl_top_y_address; + t_c_addr = s5ptv_status.vl_top_c_address; + b_y_addr = s5ptv_status.vl_bottom_y_address; + b_c_addr = s5ptv_status.vl_bottom_c_address; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + verr = __s5p_vp_set_bottom_field_address(b_y_addr, b_c_addr); + + if (verr != VPROC_NO_ERROR) + return false; + + + if (s5ptv_status.src_color == VPROC_SRC_COLOR_NV12IW) { + verr = __s5p_vp_set_top_field_address(t_y_addr, t_c_addr); + + if (verr != VPROC_NO_ERROR) + return false; + + } + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + + return true; +} + +bool _s5p_vlayer_set_img_size(unsigned long buf_in) +{ + struct s5p_img_size *size = (struct s5p_img_size *)buf_in; + enum s5p_tv_vp_err verr; + + s5ptv_status.vl_basic_param.img_width = size->img_width; + s5ptv_status.vl_basic_param.img_height = size->img_height; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + verr = __s5p_vp_set_img_size(size->img_width, size->img_height); + + if (verr != VPROC_NO_ERROR) + return false; + + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + + VLAYERPRINTK("()\n\r"); + + return true; +} + +bool _s5p_vlayer_set_src_position(unsigned long buf_in) +{ + struct s5p_img_offset *offset = (struct s5p_img_offset *)buf_in; + enum s5p_tv_vp_err verr; + + s5ptv_status.vl_basic_param.src_offset_x = offset->offset_x; + s5ptv_status.vl_basic_param.src_offset_y = offset->offset_y; + _s5p_vlayer_calc_inner_values(); + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + __s5p_vp_set_src_position(s5ptv_status.vl_src_offset_x, + s5ptv_status.vl_src_x_fact_step, + s5ptv_status.vl_src_offset_y); + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + + return true; +} + +bool _s5p_vlayer_set_dest_position(unsigned long buf_in) +{ + u32 d_ox = 0; + u32 d_oy = 0; + struct s5p_img_offset *offset = (struct s5p_img_offset *)buf_in; + enum s5p_tv_vp_err verr; + + s5ptv_status.vl_basic_param.dest_offset_x = offset->offset_x; + s5ptv_status.vl_basic_param.dest_offset_y = offset->offset_y; + _s5p_vlayer_calc_inner_values(); + + d_ox = s5ptv_status.vl_dest_offset_x; + d_oy = s5ptv_status.vl_dest_offset_y; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + __s5p_vp_set_dest_position(d_ox, d_oy); + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + return true; +} + +bool _s5p_vlayer_set_src_size(unsigned long buf_in) +{ + u32 s_w = 0; + u32 s_h = 0; + u32 d_w = 0; + u32 d_h = 0; + bool ipc = false; + + struct s5p_img_size *size = (struct s5p_img_size *)buf_in; + enum s5p_tv_vp_err verr; + + s5ptv_status.vl_basic_param.src_width = size->img_width; + s5ptv_status.vl_basic_param.src_height = size->img_height; + _s5p_vlayer_calc_inner_values(); + + s_w = s5ptv_status.vl_src_width; + s_h = s5ptv_status.vl_src_height; + d_w = s5ptv_status.vl_dest_width; + d_h = s5ptv_status.vl_dest_height; + ipc = s5ptv_status.vl2d_ipc; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + __s5p_vp_set_src_dest_size(s_w, s_h, d_w, d_h, ipc); + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + return true; +} + +bool _s5p_vlayer_set_dest_size(unsigned long buf_in) +{ + u32 s_w = 0; + u32 s_h = 0; + u32 d_w = 0; + u32 d_h = 0; + bool ipc = false; + + struct s5p_img_size *size = (struct s5p_img_size *)buf_in; + enum s5p_tv_vp_err verr; + + s5ptv_status.vl_basic_param.dest_width = size->img_width; + s5ptv_status.vl_basic_param.dest_height = size->img_height; + _s5p_vlayer_calc_inner_values(); + + s_w = s5ptv_status.vl_src_width; + s_h = s5ptv_status.vl_src_height; + d_w = s5ptv_status.vl_dest_width; + d_h = s5ptv_status.vl_dest_height; + ipc = s5ptv_status.vl2d_ipc; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + __s5p_vp_set_src_dest_size(s_w, s_h, d_w, d_h, ipc); + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + return true; +} + +bool _s5p_vlayer_set_brightness(unsigned long buf_in) +{ + enum s5p_tv_vp_err verr; + + s5ptv_status.us_vl_brightness = (unsigned short)buf_in; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + __s5p_vp_set_brightness(s5ptv_status.us_vl_brightness); + + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + + return true; +} + +bool _s5p_vlayer_set_contrast(unsigned long buf_in) +{ + enum s5p_tv_vp_err verr; + + s5ptv_status.vl_contrast = (unsigned char)buf_in; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + __s5p_vp_set_contrast(s5ptv_status.vl_contrast); + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + + return true; +} + +void _s5p_vlayer_get_priority(unsigned long buf_out) +{ + unsigned int *id = (unsigned int *)buf_out; + + *id = s5ptv_status.vl_basic_param.priority; +} + +bool _s5p_vlayer_set_brightness_contrast_control(unsigned long buf_in) +{ + u32 intc; + u32 slope; + + enum s5p_vp_line_eq eq_num; + enum s5p_tv_vp_err verr; + struct s5p_vl_bright_contrast_ctrl *ctrl = + (struct s5p_vl_bright_contrast_ctrl *)buf_in; + + if (ctrl->eq_num > VProc_LINE_EQ_7 || + ctrl->eq_num < VProc_LINE_EQ_0) { + VLAYERPRINTK("(ERR) : invalid eq_num(%d)\n\r", ctrl->eq_num); + return false; + } + + memcpy((void *)&(s5ptv_status.vl_bc_control[ctrl->eq_num]), + (const void *)ctrl, sizeof(struct s5p_vl_csc_ctrl)); + + eq_num = s5ptv_status.vl_bc_control[ctrl->eq_num].eq_num; + intc = s5ptv_status.vl_bc_control[ctrl->eq_num].intc; + slope = s5ptv_status.vl_bc_control[ctrl->eq_num].slope; + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + verr = __s5p_vp_set_brightness_contrast_control(eq_num, intc, slope); + + if (verr != VPROC_NO_ERROR) + return false; + + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + + return true; +} + +bool _s5p_vlayer_set_poly_filter_coef(unsigned long buf_in) +{ + struct s5p_video_poly_filter_coef *coef = + (struct s5p_video_poly_filter_coef *)buf_in; + enum s5p_tv_vp_err verr; + + if (coef->poly_coeff < VPROC_POLY8_Y0_LL || + (coef->poly_coeff > VPROC_POLY8_Y3_HH && + coef->poly_coeff < VPROC_POLY4_Y0_LL) || + coef->poly_coeff > VPROC_POLY4_C1_HH) { + VLAYERPRINTK("(ERR) : invalid poly_coeff(%d)\n\r", + coef->poly_coeff); + return false; + } + + if (_s5p_vlayer_wait_previous_update()) + return false; + + + verr = __s5p_vp_init_poly_filter_coef(coef->poly_coeff, + coef->ch0, coef->ch1, + coef->ch2, coef->ch3); + + if (verr != VPROC_NO_ERROR) + return false; + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + s5ptv_status.vl_poly_filter_default = false; + + return true; +} + +bool _s5p_vlayer_set_csc_coef(unsigned long buf_in) +{ + struct s5p_video_csc_coef *coef = (struct s5p_video_csc_coef *)buf_in; + enum s5p_tv_vp_err verr; + + if (coef->csc_coeff < VPROC_CSC_Y2Y_COEF || + coef->csc_coeff > VPROC_CSC_CR2CR_COEF) { + VLAYERPRINTK("(ERR) : invalid csc_coeff(%d)\n\r", + coef->csc_coeff); + return false; + } + + if (_s5p_vlayer_wait_previous_update()) + return false; + + verr = __s5p_vp_init_csc_coef(coef->csc_coeff, coef->coeff); + + if (verr != VPROC_NO_ERROR) + return false; + + + verr = __s5p_vp_update(); + + if (verr != VPROC_NO_ERROR) + return false; + + + s5ptv_status.vl_csc_coef_default = false; + + return true; +} + +bool _s5p_vlayer_init_param(unsigned long buf_in) +{ + struct s5p_tv_status *st = &s5ptv_status; + + bool i_mode, o_mode; /* 0 for interlaced, 1 for progressive */ + + switch (st->tvout_param.disp_mode) { + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + +#ifdef CONFIG_CPU_S5PV210 + case TVOUT_480P_59: + st->vl_csc_type = VPROC_CSC_SD_HD; + break; + + case TVOUT_1080I_50: + + case TVOUT_1080I_60: + + case TVOUT_1080P_50: + + case TVOUT_1080P_30: + + case TVOUT_1080P_60: + + case TVOUT_720P_59: + + case TVOUT_1080I_59: + + case TVOUT_1080P_59: +#endif + case TVOUT_720P_50: + + case TVOUT_720P_60: + st->vl_csc_type = VPROC_CSC_HD_SD; + break; + + default: + break; + } + + st->vl_csc_control.csc_en = false; + + + i_mode = check_input_mode(st->src_color); + o_mode = check_output_mode(st->tvout_param.disp_mode, + st->tvout_param.out_mode); + + /* check o_mode */ + if (i_mode == INTERLACED) { + /* i to i : line skip 1, ipc 0, auto toggle 0 */ + if (o_mode == INTERLACED) { + st->vl_op_mode.line_skip = true; + st->vl2d_ipc = false; + st->vl_op_mode.toggle_id = false; + } else { + /* i to p : line skip 1, ipc 1, auto toggle 0 */ + st->vl_op_mode.line_skip = true; + st->vl2d_ipc = true; + st->vl_op_mode.toggle_id = false; + } + } else { + /* p to i : line skip 1, ipc 0, auto toggle 0 */ + if (o_mode == INTERLACED) { + st->vl_op_mode.line_skip = true; + st->vl2d_ipc = false; + st->vl_op_mode.toggle_id = false; + } else { + /* p to p : line skip 0, ipc 0, auto toggle 0 */ + st->vl_op_mode.line_skip = false; + st->vl2d_ipc = false; + st->vl_op_mode.toggle_id = false; + } + } + + + + st->vl_op_mode.mem_mode = ((st->src_color == VPROC_SRC_COLOR_NV12) || + st->src_color == VPROC_SRC_COLOR_NV12IW) ? + VPROC_LINEAR_MODE : VPROC_2D_TILE_MODE; +/* + st->vl_op_mode.chroma_exp = (pro) ? VPROC_USING_C_TOP + : VPROC_USING_C_TOP_BOTTOM; +*/ + st->vl_op_mode.chroma_exp = 0; /* use only top y addr */ + + _s5p_vlayer_calc_inner_values(); + + if (st->vl_mode) { + VLAYERPRINTK("(ERR) : Default values are already updated\n\r"); + return true; + } + + /* Initialize Video Layer Parameters to Default Values */ + st->vl_src_x_fact_step = 0; + st->field_id = VPROC_TOP_FIELD; + st->vl_rate = VPROC_PIXEL_PER_RATE_1_1; + st->vl_poly_filter_default = true; + st->vl_bypass_post_process = false; + st->vl_saturation = 0x80; + st->vl_sharpness.th_noise = 0; + st->vl_sharpness.sharpness = VPROC_SHARPNESS_NO; + st->us_vl_brightness = 0x00; + st->vl_contrast = 0x80; + st->vl_bright_offset = 0x00; + st->vl_csc_control.sub_y_offset_en = false; + st->vl_csc_coef_default = true; + st->vl_bc_control[0].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_bc_control[1].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_bc_control[2].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_bc_control[3].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_bc_control[4].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_bc_control[5].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_bc_control[6].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_bc_control[7].eq_num = VProc_LINE_EQ_7 + 1; + st->vl_mode = true; + + return true; +} + diff --git a/drivers/media/video/samsung/tv20/s5p_tv.h b/drivers/media/video/samsung/tv20/s5p_tv.h new file mode 100644 index 0000000..ac3eab6 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_tv.h @@ -0,0 +1,1099 @@ +/* linux/drivers/media/video/samsung/tv20/s5p_tv.h + * + * TV out driver header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/videodev2.h> +#include <linux/videodev2_samsung.h> +#include <linux/platform_device.h> +#include <linux/fb.h> + +#ifdef CONFIG_CPU_S5PV210 +#include "s5pv210/tv_out_s5pv210.h" +#endif + +#ifdef CONFIG_CPU_S5PC100 +#include "s5pc100/tv_out_s5pc100.h" +#endif + +/* #define COFIG_TVOUT_DBG */ + +#ifdef CONFIG_CPU_S5PC100 +#define FIX_27M_UNSTABLE_ISSUE +#define S5P_HDCP_I2C_ADDR 0x74 +#define I2C_DRIVERID_S5P_HDCP 510 +#endif + +#define V4L2_STD_ALL_HD ((v4l2_std_id)0xffffffff) + + +#ifdef CONFIG_TV_FB +#define TVOUT_MINOR_TVOUT 14 +#define TVOUT_MINOR_VID 21 +#else +#define TVOUT_MINOR_VIDEO 14 +#define TVOUT_MINOR_GRP0 21 +#define TVOUT_MINOR_GRP1 22 +#endif + +#define USE_VMIXER_INTERRUPT 1 + +#define AVI_SAME_WITH_PICTURE_AR (0x1<<3) + +#define AVI_RGB_IF (0x0<<5) +#define AVI_YCBCR444_IF (0x2<<5) + +#define AVI_ITU601 (0x1<<6) +#define AVI_ITU709 (0x2<<6) + +#define AVI_PAR_4_3 (0x1<<4) +#define AVI_PAR_16_9 (0x2<<4) + +#define AVI_NO_PIXEL_REPEAT (0x0<<0) + +#define AVI_VIC_2 (2<<0) +#define AVI_VIC_3 (3<<0) +#define AVI_VIC_4 (4<<0) +#define AVI_VIC_5 (5<<0) +#define AVI_VIC_16 (16<<0) +#define AVI_VIC_17 (17<<0) +#define AVI_VIC_18 (18<<0) +#define AVI_VIC_19 (19<<0) +#define AVI_VIC_20 (20<<0) +#define AVI_VIC_31 (31<<0) +#define AVI_VIC_34 (34<<0) + + +#define VP_UPDATE_RETRY_MAXIMUM 30 +#define VP_WAIT_UPDATE_SLEEP 3 + +struct tvout_output_if { + enum s5p_tv_disp_mode disp_mode; + enum s5p_tv_o_mode out_mode; +}; + +struct s5p_img_size { + u32 img_width; + u32 img_height; +}; + +struct s5p_img_offset { + u32 offset_x; + u32 offset_y; +}; + +struct s5p_video_img_address { + u32 y_address; + u32 c_address; +}; + +struct s5p_vl_mode { + bool line_skip; + enum s5p_vp_mem_mode mem_mode; + enum s5p_vp_chroma_expansion chroma_exp; + enum s5p_vp_filed_id_toggle toggle_id; +}; + +struct s5p_vl_sharpness { + u32 th_noise; + enum s5p_vp_sharpness_control sharpness; +}; + +struct s5p_vl_csc_ctrl { + bool sub_y_offset_en; + bool csc_en; +}; + +struct s5p_video_poly_filter_coef { + enum s5p_vp_poly_coeff poly_coeff; + signed char ch0; + signed char ch1; + signed char ch2; + signed char ch3; +}; + +struct s5p_vl_bright_contrast_ctrl { + enum s5p_vp_line_eq eq_num; + u32 intc; + u32 slope; +}; + +struct s5p_video_csc_coef { + enum s5p_vp_csc_coeff csc_coeff; + u32 coeff; +}; + +struct s5p_vl_param { + bool win_blending; + u32 alpha; + u32 priority; + u32 top_y_address; + u32 top_c_address; + enum s5p_endian_type src_img_endian; + u32 img_width; + u32 img_height; + u32 src_offset_x; + u32 src_offset_y; + u32 src_width; + u32 src_height; + u32 dest_offset_x; + u32 dest_offset_y; + u32 dest_width; + u32 dest_height; +}; + +struct s5p_tv_vo { + u32 index; + struct v4l2_framebuffer fb; + struct v4l2_window win; + struct v4l2_rect dst_rect; + bool win_blending; + bool blank_change; + bool pixel_blending; + bool pre_mul; + u32 blank_color; + u32 priority; + u32 base_addr; +}; + +struct s5p_bg_dither { + bool cr_dither_en; + bool cb_dither_en; + bool y_dither_en; +}; + + +struct s5p_bg_color { + u32 color_y; + u32 color_cb; + u32 color_cr; +}; + +struct s5p_vm_csc_coef { + enum s5p_yuv_fmt_component component; + enum s5p_tv_coef_y_mode mode; + u32 coeff_0; + u32 coeff_1; + u32 coeff_2; +}; + +struct s5p_sdout_order { + enum s5p_sd_order order; + bool dac[3]; +}; + +struct s5p_sd_vscale_cfg { + enum s5p_sd_level component_level; + enum s5p_sd_vsync_ratio component_ratio; + enum s5p_sd_level composite_level; + enum s5p_sd_vsync_ratio composite_ratio; +}; + +struct s5p_sd_vbi { + bool wss_cvbs; + enum s5p_sd_closed_caption_type caption_cvbs; + bool wss_y_svideo; + enum s5p_sd_closed_caption_type caption_y_svideo; + bool cgmsa_rgb; + bool wss_rgb; + enum s5p_sd_closed_caption_type caption_rgb; + bool cgmsa_y_pb_pr; + bool wss_y_pb_pr; + enum s5p_sd_closed_caption_type caption_y_pb_pr; +}; + +struct s5p_sd_offset_gain { + enum s5p_sd_channel_sel channel; + u32 offset; + u32 gain; +}; + +struct s5p_sd_delay { + u32 delay_y; + u32 offset_video_start; + u32 offset_video_end; +}; + +struct s5p_sd_bright_hue_saturat { + bool bright_hue_sat_adj; + u32 gain_brightness; + u32 offset_brightness; + u32 gain0_cb_hue_saturation; + u32 gain1_cb_hue_saturation; + u32 gain0_cr_hue_saturation; + u32 gain1_cr_hue_saturation; + u32 offset_cb_hue_saturation; + u32 offset_cr_hue_saturation; +}; + +struct s5p_sd_rgb_compensat { + bool rgb_color_compensation; + u32 max_rgb_cube; + u32 min_rgb_cube; +}; + +struct s5p_sd_cvbs_compensat { + bool cvbs_color_compensation; + u32 y_lower_mid; + u32 y_bottom; + u32 y_top; + u32 y_upper_mid; + u32 radius; +}; + +struct s5p_sd_svideo_compensat { + bool y_color_compensation; + u32 y_top; + u32 y_bottom; + u32 yc_cylinder; +}; + +struct s5p_sd_component_porch { + u32 back_525; + u32 front_525; + u32 back_625; + u32 front_625; +}; + +struct s5p_sd_vesa_rgb_sync { + enum s5p_sd_vesa_rgb_sync_type sync_type; + enum s5p_tv_active_polarity vsync_active; + enum s5p_tv_active_polarity hsync_active; +}; + +struct s5p_sd_ch_xtalk_cancellat_coeff { + enum s5p_sd_channel_sel channel; + u32 coeff1; + u32 coeff2; +}; + +struct s5p_sd_closed_caption { + u32 display_cc; + u32 nondisplay_cc; +}; + +struct s5p_sd_525_data { + bool analog_on; + enum s5p_sd_525_copy_permit copy_permit; + enum s5p_sd_525_mv_psp mv_psp; + enum s5p_sd_525_copy_info copy_info; + enum s5p_sd_525_aspect_ratio display_ratio; +}; + +struct s5p_sd_625_data { + bool surroun_f_sound; + bool copyright; + bool copy_protection; + bool text_subtitles; + enum s5p_sd_625_subtitles open_subtitles; + enum s5p_sd_625_camera_film camera_film; + enum s5p_sd_625_color_encoding color_encoding; + bool helper_signal; + enum s5p_sd_625_aspect_ratio display_ratio; +}; + +struct s5p_hdmi_bluescreen { + bool enable; + u8 cb_b; + u8 y_g; + u8 cr_r; +}; + +struct s5p_hdmi_color_range { + u8 y_min; + u8 y_max; + u8 c_min; + u8 c_max; +}; + +struct s5p_hdmi_video_infoframe { + enum s5p_hdmi_transmit trans_type; + u8 check_sum; + u8 *data; +}; + +struct s5p_hdmi_tg_cmd { + bool timing_correction_en; + bool bt656_sync_en; + bool tg_en; +}; + +struct s5p_hdmi_spd_infoframe { + enum s5p_hdmi_transmit trans_type; + u8 *spd_header; + u8 *spd_data; +}; + +struct s5p_tv_v4l2 { + struct v4l2_output *output; + struct v4l2_standard *std; + struct v4l2_format *fmt_v; + struct v4l2_format *fmt_vo_0; + struct v4l2_format *fmt_vo_1; +}; + + +#define S5PTVFB_AVALUE(r, g, b) \ + (((r & 0xf) << 8) | ((g & 0xf) << 4) | ((b & 0xf) << 0)) +#define S5PTVFB_CHROMA(r, g, b) \ + (((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b & 0xff) << 0)) + +#define S5PTVFB_WIN_POSITION \ + _IOW('F', 213, struct s5ptvfb_user_window) +#define S5PTVFB_WIN_SET_PLANE_ALPHA \ + _IOW('F', 214, struct s5ptvfb_user_plane_alpha) +#define S5PTVFB_WIN_SET_CHROMA \ + _IOW('F', 215, struct s5ptvfb_user_chroma) + +enum s5ptvfb_data_path_t { + DATA_PATH_FIFO = 0, + DATA_PATH_DMA = 1, +}; + +enum s5ptvfb_alpha_t { + PLANE_BLENDING, + PIXEL_BLENDING, +}; + +enum s5ptvfb_chroma_dir_t { + CHROMA_FG, + CHROMA_BG, +}; + +struct s5ptvfb_alpha { + enum s5ptvfb_alpha_t mode; + int channel; + unsigned int value; +}; + +struct s5ptvfb_chroma { + int enabled; + int blended; + unsigned int key; + unsigned int comp_key; + unsigned int alpha; + enum s5ptvfb_chroma_dir_t dir; +}; + +struct s5ptvfb_user_window { + int x; + int y; +}; + +struct s5ptvfb_user_plane_alpha { + int channel; + unsigned char red; + unsigned char green; + unsigned char blue; +}; + +struct s5ptvfb_user_chroma { + int enabled; + unsigned char red; + unsigned char green; + unsigned char blue; +}; + + +struct s5ptvfb_window { + int id; + int enabled; + atomic_t in_use; + int x; + int y; + enum s5ptvfb_data_path_t path; + int local_channel; + int dma_burst; + unsigned int pseudo_pal[16]; + struct s5ptvfb_alpha alpha; + struct s5ptvfb_chroma chroma; + int (*suspend_fifo)(void); + int (*resume_fifo)(void); +}; + +struct s5ptvfb_lcd_timing { + int h_fp; + int h_bp; + int h_sw; + int v_fp; + int v_fpe; + int v_bp; + int v_bpe; + int v_sw; +}; + +struct s5ptvfb_lcd_polarity { + int rise_vclk; + int inv_hsync; + int inv_vsync; + int inv_vden; +}; + +struct s5ptvfb_lcd { + int width; + int height; + int bpp; + int freq; + struct s5ptvfb_lcd_timing timing; + struct s5ptvfb_lcd_polarity polarity; + + void (*init_ldi)(void); +}; + +struct s5p_tv_status { + /* TVOUT_SET_INTERFACE_PARAM */ + bool tvout_param_available; + struct tvout_output_if tvout_param; + + /* TVOUT_SET_OUTPUT_ENABLE/DISABLE */ + bool tvout_output_enable; + + /* TVOUT_SET_LAYER_MODE/POSITION */ + bool vl_mode; + bool grp_mode[2]; + + /* Video Layer Parameters */ + struct s5p_vl_param vl_basic_param; + struct s5p_vl_mode vl_op_mode; + struct s5p_vl_sharpness vl_sharpness; + struct s5p_vl_csc_ctrl vl_csc_control; + struct s5p_vl_bright_contrast_ctrl vl_bc_control[8]; + + enum s5p_vp_src_color src_color; + enum s5p_vp_field field_id; + enum s5p_vp_pxl_rate vl_rate; + enum s5p_vp_csc_type vl_csc_type; + + u32 vl_top_y_address; + u32 vl_top_c_address; + u32 vl_bottom_y_address; + u32 vl_bottom_c_address; + u32 vl_src_offset_x; + u32 vl_src_x_fact_step; + u32 vl_src_offset_y; + u32 vl_src_width; + u32 vl_src_height; + u32 vl_dest_offset_x; + u32 vl_dest_offset_y; + u32 vl_dest_width; + u32 vl_dest_height; + bool vl2d_ipc; + + bool vl_poly_filter_default; + bool vl_bypass_post_process; + u32 vl_saturation; + bool us_vl_brightness; + u8 vl_contrast; + u32 vl_bright_offset; + bool vl_csc_coef_default; + + /* GRP Layer Common Parameters */ + enum s5p_vmx_burst_mode grp_burst; + enum s5p_endian_type grp_endian; + + /* BackGroung Layer Parameters */ + struct s5p_bg_dither bg_dither; + struct s5p_bg_color bg_color[3]; + + /* Video Mixer Parameters */ + bool vm_csc_coeff_default; + + /* SDout Parameters */ + struct s5p_sd_vscale_cfg sdout_video_scale_cfg; + struct s5p_sd_vbi sdout_vbi; + struct s5p_sd_offset_gain sdout_offset_gain[3]; + struct s5p_sd_delay sdout_delay; + struct s5p_sd_bright_hue_saturat sdout_bri_hue_set; + struct s5p_sd_rgb_compensat sdout_rgb_compen; + struct s5p_sd_cvbs_compensat sdout_cvbs_compen; + struct s5p_sd_svideo_compensat sdout_svideo_compen; + struct s5p_sd_component_porch sdout_comp_porch; + struct s5p_sd_vesa_rgb_sync sdout_rgb_sync; + struct s5p_sd_ch_xtalk_cancellat_coeff sdout_xtalk_cc[3]; + struct s5p_sd_closed_caption sdout_closed_capt; + struct s5p_sd_525_data sdout_wss_525; + struct s5p_sd_625_data sdout_wss_625; + struct s5p_sd_525_data sdout_cgms_525; + struct s5p_sd_625_data sdout_cgms_625; + + enum s5p_sd_order sdout_order; + enum s5p_sd_sync_sig_pin sdout_sync_pin; + + bool sdout_color_sub_carrier_phase_adj; + bool sdout_dac_on[3]; + bool sdout_y_pb_pr_comp; + + /* HDMI video parameters */ + struct s5p_hdmi_bluescreen hdmi_video_blue_screen; + struct s5p_hdmi_color_range hdmi_color_range; + struct s5p_hdmi_video_infoframe hdmi_av_info_frame; + struct s5p_hdmi_video_infoframe hdmi_mpg_info_frame; + struct s5p_hdmi_tg_cmd hdmi_tg_cmd; + u8 avi_byte[13]; + u8 mpg_byte[5]; + + /* HDMI parameters */ + struct s5p_hdmi_spd_infoframe hdmi_spd_info_frame; + u8 spd_header[3]; + u8 spd_data[28]; + bool hdcp_en; + enum s5p_hdmi_audio_type hdmi_audio_type; + bool hpd_status; + bool suspend_status; + + /* TVOUT_SET_LAYER_ENABLE/DISABLE */ + bool vp_layer_enable; + bool grp_layer_enable[2]; + + /* i2c for hdcp port */ + struct i2c_client *hdcp_i2c_client; + + struct s5p_tv_vo overlay[2]; + + struct video_device *video_dev[3]; + + struct regulator *tv_tv; + struct regulator *tv_tvout; + struct regulator *tv_regulator; + + struct clk *tvenc_clk; + struct clk *vp_clk; + struct clk *mixer_clk; + struct clk *hdmi_clk; + struct clk *i2c_phy_clk; + struct clk *sclk_hdmiphy; + struct clk *sclk_pixel; + struct clk *sclk_dac; + struct clk *sclk_hdmi; + struct clk *sclk_mixer; + + struct s5p_tv_v4l2 v4l2; + + struct s5ptvfb_window win; + struct fb_info *fb; + struct device *dev_fb; + + struct s5ptvfb_lcd *lcd; + struct mutex fb_lock; +}; + +/* F R A M E B U F F E R */ +#define S5PTVFB_NAME "s5ptvfb" + +/* +* V4L2 TVOUT EXTENSIONS +* +*/ +#define V4L2_INPUT_TYPE_MSDMA 3 +#define V4L2_INPUT_TYPE_FIFO 4 + +#define V4L2_OUTPUT_TYPE_MSDMA 4 +#define V4L2_OUTPUT_TYPE_COMPOSITE 5 +#define V4L2_OUTPUT_TYPE_SVIDEO 6 +#define V4L2_OUTPUT_TYPE_YPBPR_INERLACED 7 +#define V4L2_OUTPUT_TYPE_YPBPR_PROGRESSIVE 8 +#define V4L2_OUTPUT_TYPE_RGB_PROGRESSIVE 9 +#define V4L2_OUTPUT_TYPE_DIGITAL 10 +#define V4L2_OUTPUT_TYPE_HDMI V4L2_OUTPUT_TYPE_DIGITAL +#define V4L2_OUTPUT_TYPE_HDMI_RGB 11 +#define V4L2_OUTPUT_TYPE_DVI 12 + +#define V4L2_STD_PAL_BDGHI (V4L2_STD_PAL_B| \ + V4L2_STD_PAL_D| \ + V4L2_STD_PAL_G| \ + V4L2_STD_PAL_H| \ + V4L2_STD_PAL_I) + +#define V4L2_STD_480P_60_16_9 ((v4l2_std_id)0x04000000) +#define V4L2_STD_480P_60_4_3 ((v4l2_std_id)0x05000000) +#define V4L2_STD_576P_50_16_9 ((v4l2_std_id)0x06000000) +#define V4L2_STD_576P_50_4_3 ((v4l2_std_id)0x07000000) +#define V4L2_STD_720P_60 ((v4l2_std_id)0x08000000) +#define V4L2_STD_720P_50 ((v4l2_std_id)0x09000000) +#define V4L2_STD_1080P_60 ((v4l2_std_id)0x0a000000) +#define V4L2_STD_1080P_50 ((v4l2_std_id)0x0b000000) +#define V4L2_STD_1080I_60 ((v4l2_std_id)0x0c000000) +#define V4L2_STD_1080I_50 ((v4l2_std_id)0x0d000000) +#define V4L2_STD_480P_59 ((v4l2_std_id)0x0e000000) +#define V4L2_STD_720P_59 ((v4l2_std_id)0x0f000000) +#define V4L2_STD_1080I_59 ((v4l2_std_id)0x10000000) +#define V4L2_STD_1080P_59 ((v4l2_std_id)0x11000000) +#define V4L2_STD_1080P_30 ((v4l2_std_id)0x12000000) + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define V4L2_FBUF_FLAG_PRE_MULTIPLY 0x0040 +#define V4L2_FBUF_CAP_PRE_MULTIPLY 0x0080 + +struct v4l2_window_s5p_tvout { + u32 capability; + u32 flags; + u32 priority; + + struct v4l2_window win; +}; + +struct v4l2_pix_format_s5p_tvout { + void *base_y; + void *base_c; + bool src_img_endian; + + struct v4l2_pix_format pix_fmt; +}; + +extern const struct v4l2_ioctl_ops s5p_tv_v4l2_v_ops; +extern const struct v4l2_ioctl_ops s5p_tv_v4l2_vo_ops; +extern const struct v4l2_ioctl_ops s5p_tv_v4l2_ops; +extern const struct v4l2_ioctl_ops s5p_tv_v4l2_vid_ops; + + +extern void s5p_tv_v4l2_init_param(void); + +extern long s5p_tv_ioctl(struct file *file, u32 cmd, unsigned long arg); +extern long s5p_tv_vid_ioctl(struct file *file, u32 cmd, unsigned long arg); +extern long s5p_tv_v_ioctl(struct file *file, u32 cmd, unsigned long arg); +extern long s5p_tv_vo_ioctl(struct file *file, u32 cmd, unsigned long arg); + + +#ifdef CONFIG_CPU_S5PC100 +int __init __s5p_hdmi_probe(struct platform_device *pdev, u32 res_num); +#endif + +#ifdef CONFIG_CPU_S5PV210 +int __init __s5p_hdmi_probe(struct platform_device *pdev, + u32 res_num, u32 res_num2); +int __s5p_hdmi_phy_power(bool on); +#endif + +int __init __s5p_sdout_probe(struct platform_device *pdev, u32 res_num); +int __init __s5p_mixer_probe(struct platform_device *pdev, u32 res_num); +int __init __s5p_vp_probe(struct platform_device *pdev, u32 res_num); +int __init __s5p_tvclk_probe(struct platform_device *pdev, u32 res_num); + +int __init __s5p_hdmi_release(struct platform_device *pdev); +int __init __s5p_sdout_release(struct platform_device *pdev); +int __init __s5p_mixer_release(struct platform_device *pdev); +int __init __s5p_vp_release(struct platform_device *pdev); +int __init __s5p_tvclk_release(struct platform_device *pdev); + + +extern bool _s5p_hdmi_api_proc(unsigned long arg, u32 cmd); +extern bool _s5p_hdmi_video_api_proc(unsigned long arg, u32 cmd); + +extern bool _s5p_grp_api_proc(unsigned long arg, u32 cmd); +extern bool _s5p_grp_init_param(enum s5p_tv_vmx_layer vm_layer, + unsigned long p_buf_in); +extern bool _s5p_grp_start(enum s5p_tv_vmx_layer vmLayer); +extern bool _s5p_grp_stop(enum s5p_tv_vmx_layer vmLayer); + +extern bool _s5p_tv_if_api_proc(unsigned long arg, u32 cmd); +extern bool _s5p_tv_if_init_param(void); +extern bool _s5p_tv_if_start(void); +extern bool _s5p_tv_if_stop(void); +extern bool _s5p_tv_if_set_disp(void); + +extern bool _s5p_bg_api_proc(unsigned long arg, u32 cmd); +extern bool _s5p_sdout_api_proc(unsigned long arg, u32 cmd); + +extern bool _s5p_vlayer_set_blending(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_alpha(unsigned long p_buf_in); +extern bool _s5p_vlayer_api_proc(unsigned long arg, u32 cmd); +extern bool _s5p_vlayer_init_param(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_priority(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_field_id(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_top_address(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_bottom_address(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_img_size(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_src_position(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_dest_position(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_src_size(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_dest_size(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_brightness(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_contrast(unsigned long p_buf_in); +extern void _s5p_vlayer_get_priority(unsigned long p_buf_out); +extern bool _s5p_vlayer_set_brightness_contrast_control(unsigned long + p_buf_in); +extern bool _s5p_vlayer_set_poly_filter_coef(unsigned long p_buf_in); +extern bool _s5p_vlayer_set_csc_coef(unsigned long p_buf_in); +extern bool _s5p_vlayer_start(void); +extern bool _s5p_vlayer_stop(void); + +void __s5p_read_hdcp_data(u8 reg_addr, u8 count, u8 *data); +void __s5p_write_hdcp_data(u8 reg_addr, u8 count, u8 *data); +void __s5p_write_ainfo(void); +void __s5p_write_an(void); +void __s5p_write_aksv(void); +void __s5p_read_bcaps(void); +void __s5p_read_bksv(void); +bool __s5p_compare_p_value(void); +bool __s5p_compare_r_value(void); +void __s5p_reset_authentication(void); +void __s5p_make_aes_key(void); +void __s5p_set_av_mute_on_off(u32 on_off); +void __s5p_start_encryption(void); +void __s5p_start_decrypting(const u8 *hdcp_key, u32 hdcp_key_size); +bool __s5p_check_repeater(void); +bool __s5p_is_occurred_hdcp_event(void); +irqreturn_t __s5p_hdmi_irq(int irq, void *dev_id); +bool __s5p_is_decrypting_done(void); +void __s5p_set_hpd_detection(u32 detection_type, bool hdcp_enabled, + struct i2c_client *client); + +#ifdef CONFIG_CPU_S5PC100 +bool __s5p_start_hdcp(void); +void __s5p_stop_hdcp(void); +void __s5p_hdcp_reset(void); +#endif + +void __s5p_hdmi_set_hpd_onoff(bool on_off); +void __s5p_hdmi_audio_set_config(enum s5p_tv_audio_codec_type audio_codec); +void __s5p_hdmi_audio_set_acr(u32 sample_rate); +void __s5p_hdmi_audio_set_asp(void); +void __s5p_hdmi_audio_clock_enable(void); +void __s5p_hdmi_audio_set_repetition_time( + enum s5p_tv_audio_codec_type audio_codec, + u32 bits, u32 frame_size_code); +void __s5p_hdmi_audio_irq_enable(u32 irq_en); +void __s5p_hdmi_audio_set_aui(enum s5p_tv_audio_codec_type audio_codec, + u32 sample_rate, u32 bits); +void __s5p_hdmi_video_set_bluescreen(bool en, u8 cb, u8 y_g, u8 cr_r); +enum s5p_tv_hdmi_err __s5p_hdmi_init_spd_infoframe( + enum s5p_hdmi_transmit trans_type, + u8 *spd_header, u8 *spd_data); +void __s5p_hdmi_init_hpd_onoff(bool on_off); +enum s5p_tv_hdmi_err __s5p_hdmi_audio_init( + enum s5p_tv_audio_codec_type audio_codec, + u32 sample_rate, u32 bits, u32 frame_size_code); +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_display_mode( + enum s5p_tv_disp_mode disp_mode, + enum s5p_tv_o_mode out_mode, u8 *avidata); +void __s5p_hdmi_video_init_bluescreen(bool en, u8 cb, u8 y_g, u8 cr_r); +void __s5p_hdmi_video_init_color_range(u8 y_min, u8 y_max, u8 c_min, u8 c_max); +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_csc( + enum s5p_tv_hdmi_csc_type csc_type); +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_avi_infoframe( + enum s5p_hdmi_transmit trans_type, u8 check_sum, u8 *pavi_data); +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_mpg_infoframe( + enum s5p_hdmi_transmit trans_type, u8 check_sum, u8 *pmpg_data); +void __s5p_hdmi_video_init_tg_cmd(bool t_correction_en, bool BT656_sync_en, + bool tg_en); +bool __s5p_hdmi_start(enum s5p_hdmi_audio_type hdmi_audio_type, bool HDCP_en, + struct i2c_client *ddc_port); +void __s5p_hdmi_stop(void); + +enum s5p_tv_sd_err __s5p_sdout_init_video_scale_cfg( + enum s5p_sd_level component_level, + enum s5p_sd_vsync_ratio component_ratio, + enum s5p_sd_level composite_level, + enum s5p_sd_vsync_ratio composite_ratio); +enum s5p_tv_sd_err __s5p_sdout_init_sync_signal_pin( + enum s5p_sd_sync_sig_pin pin); +enum s5p_tv_sd_err __s5p_sdout_init_vbi(bool wss_cvbs, + enum s5p_sd_closed_caption_type caption_cvbs, bool wss_y_sideo, + enum s5p_sd_closed_caption_type caption_y_sideo, bool cgmsa_rgb, + bool wss_rgb, enum s5p_sd_closed_caption_type caption_rgb, + bool cgmsa_y_ppr, bool wss_y_ppr, + enum s5p_sd_closed_caption_type caption_y_ppr); +enum s5p_tv_sd_err __s5p_sdout_init_offset_gain( + enum s5p_sd_channel_sel channel, + u32 offset, u32 gain); +void __s5p_sdout_init_delay(u32 delay_y, u32 offset_video_start, + u32 offset_video_end); +void __s5p_sdout_init_schlock(bool color_sucarrier_pha_adj); +enum s5p_tv_sd_err __s5p_sdout_init_dac_power_onoff( + enum s5p_sd_channel_sel channel, + bool dac_on); +void __s5p_sdout_init_color_compensaton_onoff(bool bright_hue_saturation_adj, + bool y_ppr_color_compensation, bool rgb_color_compensation, + bool y_c_color_compensation, bool y_cvbs_color_compensation); +void __s5p_sdout_init_brightness_hue_saturation(u32 gain_brightness, + u32 offset_brightness, u32 gain0_cb_hue_saturation, + u32 gain1_cb_hue_saturation, u32 gain0_cr_hue_saturation, + u32 gain1_cr_hue_saturation, u32 offset_cb_hue_saturation, + u32 offset_cr_hue_saturation); +void __s5p_sdout_init_rgb_color_compensation(u32 max_rgb_cube, + u32 min_rgb_cube); +void __s5p_sdout_init_cvbs_color_compensation(u32 y_lower_mid, + u32 y_bottom, u32 y_top, u32 y_upper_mid, u32 radius); +void __s5p_sdout_init_svideo_color_compensation(u32 y_top, u32 y_bottom, + u32 y_c_cylinder); +void __s5p_sdout_init_component_porch(u32 back_525, u32 front_525, + u32 back_625, u32 front_625); +enum s5p_tv_sd_err __s5p_sdout_init_vesa_rgb_sync( + enum s5p_sd_vesa_rgb_sync_type sync_type, + enum s5p_tv_active_polarity v_sync_active, + enum s5p_tv_active_polarity h_sync_active); +void __s5p_sdout_init_oversampling_filter_coeff(u32 size, u32 *pcoeff0, + u32 *pcoeff1, u32 *pcoeff2); +enum s5p_tv_sd_err __s5p_sdout_init_ch_xtalk_cancel_coef( + enum s5p_sd_channel_sel channel, + u32 coeff2, u32 coeff1); +void __s5p_sdout_init_closed_caption(u32 display_cc, u32 non_display_cc); +enum s5p_tv_sd_err __s5p_sdout_init_wss525_data( + enum s5p_sd_525_copy_permit copy_permit, + enum s5p_sd_525_mv_psp mv_psp, enum s5p_sd_525_copy_info copy_info, + bool analog_on, enum s5p_sd_525_aspect_ratio display_ratio); +enum s5p_tv_sd_err __s5p_sdout_init_wss625_data(bool surround_sound, + bool copyright, bool copy_protection, bool text_subtitles, + enum s5p_sd_625_subtitles open_subtitles, + enum s5p_sd_625_camera_film camera_film, + enum s5p_sd_625_color_encoding color_encoding, + bool helper_signal, enum s5p_sd_625_aspect_ratio display_ratio); +enum s5p_tv_sd_err __s5p_sdout_init_cgmsa525_data( + enum s5p_sd_525_copy_permit copy_permit, enum s5p_sd_525_mv_psp mv_psp, + enum s5p_sd_525_copy_info copy_info, bool analog_on, + enum s5p_sd_525_aspect_ratio display_ratio); +enum s5p_tv_sd_err __s5p_sdout_init_cgmsa625_data(bool surround_sound, + bool copyright, bool copy_protection, bool text_subtitles, + enum s5p_sd_625_subtitles open_subtitles, + enum s5p_sd_625_camera_film camera_film, + enum s5p_sd_625_color_encoding color_encoding, bool helper_signal, + enum s5p_sd_625_aspect_ratio display_ratio); +enum s5p_tv_sd_err __s5p_sdout_init_display_mode( + enum s5p_tv_disp_mode disp_mode, + enum s5p_tv_o_mode out_mode, enum s5p_sd_order order); +void __s5p_sdout_start(void); +void __s5p_sdout_stop(void); +void __s5p_sdout_sw_reset(bool active); +void __s5p_sdout_set_interrupt_enable(bool vsync_intr_en); +void __s5p_sdout_clear_interrupt_pending(void); +bool __s5p_sdout_get_interrupt_pending(void); + +enum s5p_tv_vmx_err __s5p_vm_set_win_blend(enum s5p_tv_vmx_layer layer, + bool enable); +enum s5p_tv_vmx_err __s5p_vm_set_layer_alpha(enum s5p_tv_vmx_layer layer, + u32 alpha); +enum s5p_tv_vmx_err __s5p_vm_set_layer_show(enum s5p_tv_vmx_layer layer, + bool show); +enum s5p_tv_vmx_err __s5p_vm_set_layer_priority(enum s5p_tv_vmx_layer layer, + u32 priority); +enum s5p_tv_vmx_err __s5p_vm_set_grp_base_address(enum s5p_tv_vmx_layer layer, + u32 baseaddr); +enum s5p_tv_vmx_err __s5p_vm_set_grp_layer_position( + enum s5p_tv_vmx_layer layer, + u32 dst_offs_x, u32 dst_offs_y); +enum s5p_tv_vmx_err __s5p_vm_set_grp_layer_size(enum s5p_tv_vmx_layer layer, + u32 span, u32 width, u32 height, u32 src_offs_x, u32 src_offs_y); +enum s5p_tv_vmx_err __s5p_vm_set_bg_color( + enum s5p_tv_vmx_bg_color_num colornum, + u32 color_y, u32 color_cb, u32 color_cr); +enum s5p_tv_vmx_err __s5p_vm_init_status_reg(enum s5p_vmx_burst_mode burst, + enum s5p_endian_type endian); +enum s5p_tv_vmx_err __s5p_vm_init_display_mode(enum s5p_tv_disp_mode mode, + enum s5p_tv_o_mode output_mode); + +#ifdef CONFIG_CPU_S5PC100 +enum s5p_tv_vmx_err __s5p_vm_init_layer(enum s5p_tv_vmx_layer layer, bool show, + bool winblending, u32 alpha, u32 priority, + enum s5p_tv_vmx_color_fmt color, bool blankchange, + bool pixelblending, bool premul, u32 blankcolor, + u32 baseaddr, u32 span, u32 width, u32 height, + u32 src_offs_x, u32 src_offs_y, u32 dst_offs_x, u32 dst_offs_y); +#endif + +#ifdef CONFIG_CPU_S5PV210 +enum s5p_tv_vmx_err __s5p_vm_init_layer(enum s5p_tv_disp_mode mode, + enum s5p_tv_vmx_layer layer, bool show, bool winblending, + u32 alpha, u32 priority, enum s5p_tv_vmx_color_fmt color, + bool blankchange, bool pixelblending, bool premul, + u32 blankcolor, u32 baseaddr, u32 span, u32 width, + u32 height, u32 src_offs_x, u32 src_offs_y, u32 dst_offs_x, + u32 dst_offs_y, u32 dst_x, u32 dst_y); +void __s5p_vm_set_ctrl(enum s5p_tv_vmx_layer layer, bool premul, + bool pixel_blending, bool blank_change, bool win_blending, + enum s5p_tv_vmx_color_fmt color, u32 alpha, u32 blank_color); +#endif + +void __s5p_vm_init_bg_dither_enable(bool cr_dither_enable, + bool cdither_enable, bool y_dither_enable); +enum s5p_tv_vmx_err __s5p_vm_init_bg_color( + enum s5p_tv_vmx_bg_color_num color_num, + u32 color_y, u32 color_cb, u32 color_cr); +enum s5p_tv_vmx_err __s5p_vm_init_csc_coef( + enum s5p_yuv_fmt_component component, + enum s5p_tv_coef_y_mode mode, u32 coeff0, u32 coeff1, u32 coeff2); +void __s5p_vm_init_csc_coef_default(enum s5p_tv_vmx_csc_type csc_type); +enum s5p_tv_vmx_err __s5p_vm_get_layer_info(enum s5p_tv_vmx_layer layer, + bool *show, + u32 *priority); +void __s5p_vm_start(void); +void __s5p_vm_stop(void); +enum s5p_tv_vmx_err __s5p_vm_set_underflow_interrupt_enable( + enum s5p_tv_vmx_layer layer, + bool en); +void __s5p_vm_clear_pend_all(void); +irqreturn_t __s5p_mixer_irq(int irq, void *dev_id); + +void __s5p_vp_set_field_id(enum s5p_vp_field mode); +enum s5p_tv_vp_err __s5p_vp_set_top_field_address(u32 top_y_addr, + u32 top_c_addr); +enum s5p_tv_vp_err __s5p_vp_set_bottom_field_address(u32 bottom_y_addr, + u32 bottom_c_addr); +enum s5p_tv_vp_err __s5p_vp_set_img_size(u32 img_width, u32 img_height); +void __s5p_vp_set_src_position(u32 src_off_x, u32 src_x_fract_step, + u32 src_off_y); +void __s5p_vp_set_dest_position(u32 dst_off_x, u32 dst_off_y); +void __s5p_vp_set_src_dest_size(u32 src_width, u32 src_height, + u32 dst_width, u32 dst_height, bool ipc_2d); +enum s5p_tv_vp_err __s5p_vp_set_poly_filter_coef( + enum s5p_vp_poly_coeff poly_coeff, + signed char ch0, signed char ch1, signed char ch2, signed char ch3); +void __s5p_vp_set_poly_filter_coef_default(u32 h_ratio, u32 v_ratio); +void __s5p_vp_set_src_dest_size_with_default_poly_filter_coef(u32 src_width, + u32 src_height, u32 dst_width, u32 dst_height, bool ipc_2d); +enum s5p_tv_vp_err __s5p_vp_set_brightness_contrast_control( + enum s5p_vp_line_eq eq_num, + u32 intc, u32 slope); +void __s5p_vp_set_brightness(bool brightness); +void __s5p_vp_set_contrast(u8 contrast); +enum s5p_tv_vp_err __s5p_vp_update(void); +enum s5p_vp_field __s5p_vp_get_field_id(void); +bool __s5p_vp_get_update_status(void); +void __s5p_vp_init_field_id(enum s5p_vp_field mode); +void __s5p_vp_init_op_mode(bool line_skip, enum s5p_vp_mem_mode mem_mode, + enum s5p_vp_chroma_expansion chroma_exp, + enum s5p_vp_filed_id_toggle toggle_id); +void __s5p_vp_init_pixel_rate_control(enum s5p_vp_pxl_rate rate); +enum s5p_tv_vp_err __s5p_vp_init_layer(u32 top_y_addr, u32 top_c_addr, + u32 bottom_y_addr, u32 bottom_c_addr, + enum s5p_endian_type src_img_endian, + u32 img_width, u32 img_height, u32 src_off_x, u32 src_x_fract_step, + u32 src_off_y, u32 src_width, u32 src_height, u32 dst_off_x, + u32 dst_off_y, u32 dst_width, u32 dst_height, bool ipc_2d); +enum s5p_tv_vp_err __s5p_vp_init_layer_def_poly_filter_coef(u32 top_y_addr, + u32 top_c_addr, u32 bottom_y_addr, u32 bottom_c_addr, + enum s5p_endian_type src_img_endian, u32 img_width, u32 img_height, + u32 src_off_x, u32 src_x_fract_step, u32 src_off_y, u32 src_width, + u32 src_height, u32 dst_off_x, u32 dst_off_y, u32 dst_width, + u32 dst_height, bool ipc_2d); +enum s5p_tv_vp_err __s5p_vp_init_poly_filter_coef( + enum s5p_vp_poly_coeff poly_coeff, + signed char ch0, signed char ch1, signed char ch2, signed char ch3); +void __s5p_vp_init_bypass_post_process(bool bypass); +enum s5p_tv_vp_err __s5p_vp_init_csc_coef(enum s5p_vp_csc_coeff csc_coeff, + u32 coeff); +void __s5p_vp_init_saturation(u32 sat); +void __s5p_vp_init_sharpness(u32 th_h_noise, + enum s5p_vp_sharpness_control sharpness); +enum s5p_tv_vp_err __s5p_vp_init_brightness_contrast_control( + enum s5p_vp_line_eq eq_num, + u32 intc, u32 slope); +void __s5p_vp_init_brightness(bool brightness); +void __s5p_vp_init_contrast(u8 contrast); +void __s5p_vp_init_brightness_offset(u32 offset); +void __s5p_vp_init_csc_control(bool suy_offset_en, bool csc_en); +enum s5p_tv_vp_err __s5p_vp_init_csc_coef_default( + enum s5p_vp_csc_type csc_type); +enum s5p_tv_vp_err __s5p_vp_start(void); +enum s5p_tv_vp_err __s5p_vp_stop(void); +void __s5p_vp_sw_reset(void); + +#ifdef CONFIG_CPU_S5PC100 +void __s5p_tv_clk_init_hpll(u32 lock_time, u32 mdiv, u32 pdiv, u32 sdiv); +#endif + +#ifdef CONFIG_CPU_S5PV210 +int __s5p_tv_clk_change_internal(void); +#endif + +void __s5p_tv_clk_hpll_onoff(bool en); +#ifdef CONFIG_CPU_S5PC100 +enum s5p_tv_clk_err __s5p_tv_clk_init_href( + enum s5p_tv_clk_hpll_ref hpll_ref); +enum s5p_tv_clk_err __s5p_tv_clk_init_mout_hpll( + enum s5p_tv_clk_mout_hpll mout_hpll); +enum s5p_tv_clk_err __s5p_tv_clk_init_video_mixer( + enum s5p_tv_clk_vmiexr_srcclk src_clk); +#endif +void __s5p_tv_clk_init_hdmi_ratio(u32 clk_div); +void __s5p_tv_clk_set_vp_clk_onoff(bool clk_on); +void __s5p_tv_clk_set_vmixer_hclk_onoff(bool clk_on); +void __s5p_tv_clk_set_vmixer_sclk_onoff(bool clk_on); +void __s5p_tv_clk_set_sdout_hclk_onoff(bool clk_on); +void __s5p_tv_clk_set_sdout_sclk_onoff(bool clk_on); +void __s5p_tv_clk_set_hdmi_hclk_onoff(bool clk_on); +void __s5p_tv_clk_set_hdmi_sclk_onoff(bool clk_on); +void __s5p_tv_clk_set_hdmi_i2c_clk_onoff(bool clk_on); +void __s5p_tv_clk_start(bool vp_hclk_on, bool sdout_hclk_on, + bool hdmi_hclk_on); +void __s5p_tv_clk_stop(void); + +void __s5p_tv_power_init_mtc_stable_counter(u32 value); +void __s5p_tv_powerinitialize_dac_onoff(bool on); +void __s5p_tv_powerset_dac_onoff(bool on); +bool __s5p_tv_power_get_power_status(void); +bool __s5p_tv_power_get_dac_power_status(void); +void __s5p_tv_poweron(void); +void __s5p_tv_poweroff(void); + +extern struct s5p_tv_status s5ptv_status; +extern struct s5p_tv_vo s5ptv_overlay[2]; + +#ifdef CONFIG_CPU_S5PV210 +extern void s5p_hdmi_enable_interrupts(enum s5p_tv_hdmi_interrrupt intr); +extern void s5p_hdmi_disable_interrupts(enum s5p_tv_hdmi_interrrupt intr); +extern void s5p_hdmi_clear_pending(enum s5p_tv_hdmi_interrrupt intr); +extern u8 s5p_hdmi_get_interrupts(void); +extern int s5p_hdmi_register_isr(hdmi_isr isr, u8 irq_num); +extern int s5p_hpd_init(void); +extern u8 s5p_hdmi_get_swhpd_status(void); +extern u8 s5p_hdmi_get_hpd_status(void); +extern void s5p_hdmi_swhpd_disable(void); +extern void s5p_hdmi_hpd_gen(void); +extern int __init __s5p_hdcp_init(void); +extern int s5p_tv_clk_gate(bool on); +#endif + +extern int s5ptvfb_init_fbinfo(int id); +extern int s5ptvfb_map_video_memory(struct fb_info *fb); +extern int s5ptvfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *fb); +extern int s5ptvfb_set_par(struct fb_info *fb); +extern int s5ptvfb_draw_logo(struct fb_info *fb); +extern void s5ptvfb_set_lcd_info(struct s5p_tv_status *ctrl); +extern int s5ptvfb_display_on(struct s5p_tv_status *ctrl); +extern int s5p_hpd_get_state(void); +extern void s5p_handle_cable(void); + +#define S5PTVFB_POWER_OFF _IOW('F', 217, u32) +#define S5PTVFB_POWER_ON _IOW('F', 218, u32) +#define S5PTVFB_WIN_SET_ADDR _IOW('F', 219, u32) +#define S5PTVFB_SET_WIN_ON _IOW('F', 220, u32) +#define S5PTVFB_SET_WIN_OFF _IOW('F', 221, u32) + +extern int s5p_tv_clk_gate(bool on); +extern int s5p_hdcp_is_reset(void); +extern int tv_phy_power(bool on); +extern int s5ptvfb_unmap_video_memory(struct fb_info *fb); + +extern struct s5p_tv_status s5ptv_status; +extern bool _s5p_tv_if_set_disp(void); +extern int s5p_hdcp_encrypt_stop(bool on); +extern int s5p_hdmi_set_dvi(bool en); +extern int s5p_hdmi_set_mute(bool en); +extern int s5p_hdmi_get_mute(void); +extern int s5p_hdmi_audio_enable(bool en); +extern void s5p_hdmi_set_audio(bool en); +extern void s5p_hdmi_mute_en(bool en); +extern bool __s5p_start_hdcp(void); +extern bool __s5p_stop_hdcp(void); + +#if defined(CONFIG_MACH_P1) +extern struct i2c_driver SII9234_i2c_driver; +extern struct i2c_driver SII9234A_i2c_driver; +extern struct i2c_driver SII9234B_i2c_driver; +extern struct i2c_driver SII9234C_i2c_driver; +#endif + diff --git a/drivers/media/video/samsung/tv20/s5p_tv_base.c b/drivers/media/video/samsung/tv20/s5p_tv_base.c new file mode 100644 index 0000000..89543d2 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_tv_base.c @@ -0,0 +1,1431 @@ +/* linux/drivers/media/video/samsung/tv20/s5p_tv_base.c + * + * Entry file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/miscdevice.h> +#include <linux/platform_device.h> +#include <linux/workqueue.h> +#include <linux/wait.h> +#include <linux/ioctl.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/regulator/consumer.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <mach/map.h> + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/regs-gpio.h> +/*#include <mach/max8998_function.h>*/ +#include <linux/earlysuspend.h> +#ifdef CONFIG_CPU_FREQ_S5PV210 +#include <mach/cpu-freq-v210.h> +#endif /* CONFIG_CPU_FREQ_S5PV210 */ + +#ifdef CONFIG_S5PV210_PM_LEGACY +#include <mach/pd.h> +#endif + +#include "s5p_tv.h" + +#ifdef COFIG_TVOUT_DBG +#define S5P_TV_BASE_DEBUG 1 +#endif + +#ifdef S5P_TV_BASE_DEBUG +#define BASEPRINTK(fmt, args...) \ + printk(KERN_INFO "[TVBASE] %s: " fmt, __func__ , ## args) +#else +#define BASEPRINTK(fmt, args...) +#endif + +#ifdef CONFIG_CPU_S5PV210 +#define TVOUT_CLK_INIT(dev, clk, name) +#else +#define TVOUT_CLK_INIT(dev, clk, name) \ + do { \ + clk = clk_get(dev, name); \ + if (clk == NULL) { \ + printk(KERN_ERR \ + "failed to find %s clock source\n", name); \ + return -ENOENT; \ + } \ + clk_enable(clk) \ + } while (0); +#endif + +#define TVOUT_IRQ_INIT(x, ret, dev, num, jump, ftn, m_name) \ + do { \ + x = platform_get_irq(dev, num); \ + if (x < 0) { \ + printk(KERN_ERR \ + "failed to get %s irq resource\n", m_name); \ + ret = -ENOENT; \ + goto jump; \ + } \ + ret = request_irq(x, ftn, IRQF_DISABLED, \ + dev->name, dev); \ + if (ret != 0) { \ + printk(KERN_ERR \ + "failed to install %s irq (%d)\n", m_name, ret);\ + goto jump; \ + } \ + } while (0); + + +#ifdef CONFIG_CPU_S5PC100 +#define I2C_BASE +#endif + +static struct mutex *mutex_for_fo; + + +struct s5p_tv_status s5ptv_status; +struct s5p_tv_vo s5ptv_overlay[2]; + +#ifdef I2C_BASE +static struct mutex *mutex_for_i2c; +static struct work_struct ws_hpd; +spinlock_t slock_hpd; + +static struct i2c_driver hdcp_i2c_driver; +static bool hdcp_i2c_drv_state; + +const static u16 ignore[] = { I2C_CLIENT_END }; +const static u16 normal_addr[] = {(S5P_HDCP_I2C_ADDR >> 1), I2C_CLIENT_END }; +const static u16 *forces[] = { NULL }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_addr, + .probe = ignore, + .ignore = ignore, + .forces = forces, +}; + +/* + * i2c client drv. - register client drv + */ +static int hdcp_i2c_attach(struct i2c_adapter *adap, int addr, int kind) +{ + + struct i2c_client *c; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + + if (!c) + return -ENOMEM; + + strcpy(c->name, "s5p_ddc_client"); + + c->addr = addr; + + c->adapter = adap; + + c->driver = &hdcp_i2c_driver; + + s5ptv_status.hdcp_i2c_client = c; + + dev_info(&adap->dev, "s5p_ddc_client attached " + "into s5p_ddc_port successfully\n"); + + return i2c_attach_client(c); +} + +static int hdcp_i2c_attach_adapter(struct i2c_adapter *adap) +{ + int ret = 0; + + ret = i2c_probe(adap, &addr_data, hdcp_i2c_attach); + + if (ret) { + dev_err(&adap->dev, + "failed to attach s5p_hdcp_port driver\n"); + ret = -ENODEV; + } + + return ret; +} + +static int hdcp_i2c_detach(struct i2c_client *client) +{ + dev_info(&client->adapter->dev, "s5p_ddc_client detached " + "from s5p_ddc_port successfully\n"); + + i2c_detach_client(client); + + return 0; +} + +static struct i2c_driver hdcp_i2c_driver = { + .driver = { + .name = "s5p_ddc_port", + }, + .id = I2C_DRIVERID_S5P_HDCP, + .attach_adapter = hdcp_i2c_attach_adapter, + .detach_client = hdcp_i2c_detach, +}; + +static void set_ddc_port(void) +{ + mutex_lock(mutex_for_i2c); + + if (s5ptv_status.hpd_status) { + + if (!hdcp_i2c_drv_state) + /* cable : plugged, drv : unregistered */ + if (i2c_add_driver(&hdcp_i2c_driver)) + printk(KERN_ERR "HDCP port add failed\n"); + + /* changed drv. status */ + hdcp_i2c_drv_state = true; + + + /* cable inserted -> removed */ + __s5p_set_hpd_detection(true, s5ptv_status.hdcp_en, + s5ptv_status.hdcp_i2c_client); + + } else { + + if (hdcp_i2c_drv_state) + /* cable : unplugged, drv : registered */ + i2c_del_driver(&hdcp_i2c_driver); + + /* changed drv. status */ + hdcp_i2c_drv_state = false; + + /* cable removed -> inserted */ + __s5p_set_hpd_detection(false, s5ptv_status.hdcp_en, + s5ptv_status.hdcp_i2c_client); + printk(KERN_INFO "%s cable removed\n", __func__); + } + + mutex_unlock(mutex_for_i2c); +} +#endif + +#ifdef CONFIG_CPU_S5PC100 +static irqreturn_t __s5p_hpd_irq(int irq, void *dev_id) +{ + + spin_lock_irq(&slock_hpd); + + s5ptv_status.hpd_status = gpio_get_value(S5PC1XX_GPH0(5)) + ? false : true; + + if (s5ptv_status.hpd_status) + set_irq_type(IRQ_EINT5, IRQ_TYPE_EDGE_RISING); + else + set_irq_type(IRQ_EINT5, IRQ_TYPE_EDGE_FALLING); + + + if (s5ptv_status.hdcp_en) + schedule_work(&ws_hpd); + + spin_unlock_irq(&slock_hpd); + + BASEPRINTK("hpd_status = %d\n", s5ptv_status.hpd_status); + + return IRQ_HANDLED; +} +#endif + +#ifdef CONFIG_CPU_S5PV210 +int tv_phy_power(bool on) +{ + if (on) { + __s5p_tv_poweron(); + /* on */ + clk_enable(s5ptv_status.i2c_phy_clk); + __s5p_hdmi_phy_power(true); + + } else { + /* + * for preventing hdmi hang up when restart + * switch to internal clk - SCLK_DAC, SCLK_PIXEL + */ + clk_set_parent(s5ptv_status.sclk_mixer, + s5ptv_status.sclk_dac); + clk_set_parent(s5ptv_status.sclk_hdmi, + s5ptv_status.sclk_pixel); + + __s5p_hdmi_phy_power(false); + clk_disable(s5ptv_status.i2c_phy_clk); + __s5p_tv_poweroff(); + } + + return 0; +} + + +int s5p_tv_clk_gate(bool on) +{ + if (on) { +#ifdef CONFIG_S5PV210_PM_LEGACY + if (s5pv210_pd_enable("vp_pd") < 0) { + printk(KERN_ERR "[Error]The power is not on for VP\n"); + goto err_pm; + } +#endif + clk_enable(s5ptv_status.vp_clk); + +#ifdef CONFIG_S5PV210_PM_LEGACY + if (s5pv210_pd_enable("mixer_pd") < 0) { + printk(KERN_ERR "[Error]The power is not on for mixer\n"); + goto err_pm; + } +#endif + clk_enable(s5ptv_status.mixer_clk); + +#ifdef CONFIG_S5PV210_PM_LEGACY + if (s5pv210_pd_enable("tv_enc_pd") < 0) { + printk(KERN_ERR "[Error]The power is not on for TV ENC\n"); + goto err_pm; + } +#endif + clk_enable(s5ptv_status.tvenc_clk); + +#ifdef CONFIG_S5PV210_PM_LEGACY + if (s5pv210_pd_enable("hdmi_pd") < 0) { + printk(KERN_ERR "[Error]The power is not on for HDMI\n"); + goto err_pm; + } +#endif + clk_enable(s5ptv_status.hdmi_clk); + } else { + + /* off */ + clk_disable(s5ptv_status.vp_clk); +#ifdef CONFIG_S5PV210_PM_LEGACY + if (s5pv210_pd_disable("vp_pd") < 0) { + printk(KERN_ERR "[Error]The power is not off for VP\n"); + goto err_pm; + } +#endif + clk_disable(s5ptv_status.mixer_clk); +#ifdef CONFIG_S5PV210_PM_LEGACY + if (0 != s5pv210_pd_disable("mixer_pd")) { + printk(KERN_ERR "[Error]The power is not off for mixer\n"); + goto err_pm; + } +#endif + clk_disable(s5ptv_status.tvenc_clk); +#ifdef CONFIG_S5PV210_PM_LEGACY + if (s5pv210_pd_disable("tv_enc_pd") < 0) { + printk(KERN_ERR "[Error]The power is not off for TV ENC\n"); + goto err_pm; + } +#endif + clk_disable(s5ptv_status.hdmi_clk); +#ifdef CONFIG_S5PV210_PM_LEGACY + if (s5pv210_pd_disable("hdmi_pd") < 0) { + printk(KERN_ERR "[Error]The power is not off for HDMI\n"); + goto err_pm; + } +#endif + } + + return 0; +#ifdef CONFIG_S5PV210_PM_LEGACY +err_pm: + return -1; +#endif +} +EXPORT_SYMBOL(s5p_tv_clk_gate); + +#define TV_CLK_GET_WITH_ERR_CHECK(clk, pdev, clk_name) \ + do { \ + clk = clk_get(&pdev->dev, clk_name); \ + if (IS_ERR(clk)) { \ + printk(KERN_ERR \ + "failed to find clock \"%s\"\n", clk_name); \ + return ENOENT; \ + } \ + } while (0); + +static int __devinit tv_clk_get(struct platform_device *pdev, + struct s5p_tv_status *ctrl) +{ + struct clk *ext_xtal_clk, + *mout_vpll_src, + *fout_vpll, + *mout_vpll; + + TV_CLK_GET_WITH_ERR_CHECK(ctrl->tvenc_clk, pdev, "tvenc"); + TV_CLK_GET_WITH_ERR_CHECK(ctrl->vp_clk, pdev, "vp"); + TV_CLK_GET_WITH_ERR_CHECK(ctrl->mixer_clk, pdev, "mixer"); + TV_CLK_GET_WITH_ERR_CHECK(ctrl->hdmi_clk, pdev, "hdmi"); + TV_CLK_GET_WITH_ERR_CHECK(ctrl->i2c_phy_clk, pdev, "i2c-hdmiphy"); + + TV_CLK_GET_WITH_ERR_CHECK(ctrl->sclk_dac, pdev, "sclk_dac"); + TV_CLK_GET_WITH_ERR_CHECK(ctrl->sclk_mixer, pdev, "sclk_mixer"); + TV_CLK_GET_WITH_ERR_CHECK(ctrl->sclk_hdmi, pdev, "sclk_hdmi"); + + TV_CLK_GET_WITH_ERR_CHECK(ctrl->sclk_pixel, pdev, "sclk_pixel"); + TV_CLK_GET_WITH_ERR_CHECK(ctrl->sclk_hdmiphy, pdev, "sclk_hdmiphy"); + + TV_CLK_GET_WITH_ERR_CHECK(ext_xtal_clk, pdev, "ext_xtal"); + TV_CLK_GET_WITH_ERR_CHECK(mout_vpll_src, pdev, "mout_vpll_src"); + TV_CLK_GET_WITH_ERR_CHECK(fout_vpll, pdev, "fout_vpll"); + TV_CLK_GET_WITH_ERR_CHECK(mout_vpll, pdev, "mout_vpll"); + + clk_set_parent(mout_vpll_src, ext_xtal_clk); + clk_set_parent(mout_vpll, fout_vpll); + + /* sclk_dac's parent is fixed as mout_vpll */ + clk_set_parent(ctrl->sclk_dac, mout_vpll); + + clk_set_rate(fout_vpll, 54000000); + clk_set_rate(ctrl->sclk_pixel, 54000000); + + clk_enable(ctrl->sclk_dac); + clk_enable(ctrl->sclk_mixer); + clk_enable(ctrl->sclk_hdmi); + + clk_enable(mout_vpll_src); + clk_enable(fout_vpll); + clk_enable(mout_vpll); + + clk_put(ext_xtal_clk); + clk_put(mout_vpll_src); + clk_put(fout_vpll); + clk_put(mout_vpll); + + return 0; +} +#else +#define s5p_tv_clk_gate NULL +#define tv_phy_power NULL +#define tv_clk_get NULL +#endif + +/* + * ftn for irq + */ +static irqreturn_t s5p_tvenc_irq(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +#ifdef CONFIG_TV_FB +static int s5p_tv_open(struct file *file) +{ + return 0; +} + +static int s5p_tv_release(struct file *file) +{ + s5ptv_status.hdcp_en = false; + return 0; +} + +static int s5p_tv_vid_open(struct file *file) +{ + int ret = 0; + + mutex_lock(mutex_for_fo); + + if (s5ptv_status.vp_layer_enable) { + printk(KERN_ERR "video layer. already used !!\n"); + ret = -EBUSY; + } + + mutex_unlock(mutex_for_fo); + return ret; +} + +static int s5p_tv_vid_release(struct file *file) +{ + s5ptv_status.vp_layer_enable = false; + + _s5p_vlayer_stop(); + + return 0; +} +#else + +/* + * ftn for video + */ +static int s5p_tv_v_open(struct file *file) +{ + int ret = 0; + + printk(KERN_INFO "%s", __func__); + mutex_lock(mutex_for_fo); + + if (s5ptv_status.tvout_output_enable) { + BASEPRINTK("tvout drv. already used !!\n"); + ret = -EBUSY; + goto drv_used; + } + + s5p_tv_clk_gate(true); + tv_phy_power(true); + +#ifdef CONFIG_CPU_S5PV210 +#ifdef CONFIG_PM + if ((s5ptv_status.hpd_status) && !(s5ptv_status.suspend_status)) { + BASEPRINTK("tv is turned on\n"); +#endif +#ifdef CONFIG_CPU_FREQ_S5PV210 + if ((s5ptv_status.hpd_status)) + s5pv210_set_cpufreq_level(RESTRICT_TABLE); +#endif /* CONFIG_CPU_FREQ_S5PV210 */ +// s5p_tv_clk_gate(true); +/* + if ((s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI)\ + || \ + (s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI_RGB)) +*/ +// tv_phy_power(true); +#ifdef CONFIG_PM + } else + BASEPRINTK("tv is off\n"); +#endif +#endif + _s5p_tv_if_init_param(); + + s5p_tv_v4l2_init_param(); + + mutex_unlock(mutex_for_fo); + +#ifdef I2C_BASE + mutex_lock(mutex_for_i2c); + /* for ddc(hdcp port) */ + if (s5ptv_status.hpd_status) { + if (i2c_add_driver(&hdcp_i2c_driver)) + BASEPRINTK("HDCP port add failed\n"); + hdcp_i2c_drv_state = true; + } else + hdcp_i2c_drv_state = false; + + mutex_unlock(mutex_for_i2c); + /* for i2c probing */ + udelay(100); +#endif + + return 0; + +drv_used: + mutex_unlock(mutex_for_fo); + return ret; +} + +int s5p_tv_v_read(struct file *filp, char *buf, size_t count, + loff_t *f_pos) +{ + return 0; +} + +int s5p_tv_v_write(struct file *filp, const char *buf, size_t + count, loff_t *f_pos) +{ + return 0; +} + +int s5p_tv_v_mmap(struct file *filp, struct vm_area_struct *vma) +{ + return 0; +} + +int s5p_tv_v_release(struct file *filp) +{ + printk(KERN_INFO "%s", __func__); + +#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_PM) + if ((s5ptv_status.hpd_status) && !(s5ptv_status.suspend_status)) { +#endif + if (s5ptv_status.vp_layer_enable) + _s5p_vlayer_stop(); + if (s5ptv_status.tvout_output_enable) + _s5p_tv_if_stop(); +#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_PM) + } else + s5ptv_status.vp_layer_enable = false; +#endif + s5ptv_status.hdcp_en = false; + + s5ptv_status.tvout_output_enable = false; + + /* + * drv. release + * - just check drv. state reg. or not. + */ +#ifdef I2C_BASE + mutex_lock(mutex_for_i2c); + + if (hdcp_i2c_drv_state) { + i2c_del_driver(&hdcp_i2c_driver); + hdcp_i2c_drv_state = false; + } + + mutex_unlock(mutex_for_i2c); +#endif + +#ifdef CONFIG_CPU_S5PV210 +#ifdef CONFIG_PM + if ((s5ptv_status.hpd_status) && !(s5ptv_status.suspend_status)) { +#endif +// s5p_tv_clk_gate(false); +/* if (s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI || \ + s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI_RGB) +*/ +// tv_phy_power(false); +#ifdef CONFIG_CPU_FREQ_S5PV210 + if (s5ptv_status.hpd_status) + s5pv210_set_cpufreq_level(NORMAL_TABLE); +#endif /* CONFIG_CPU_FREQ_S5PV210 */ + +#ifdef CONFIG_PM + } +#endif +#endif + + s5p_tv_clk_gate(false); + tv_phy_power(false); + + return 0; +} + +static int vo_open(int layer, struct file *file) +{ + int ret = 0; + + mutex_lock(mutex_for_fo); + + /* check tvout path available!! */ + if (!s5ptv_status.tvout_output_enable) { + BASEPRINTK("check tvout start !!\n"); + ret = -EACCES; + goto resource_busy; + } + + if (s5ptv_status.grp_layer_enable[layer]) { + BASEPRINTK("grp %d layer is busy!!\n", layer); + ret = -EBUSY; + goto resource_busy; + } + + /* set layer info.!! */ + s5ptv_overlay[layer].index = layer; + + /* set file private data.!! */ + file->private_data = &s5ptv_overlay[layer]; + + mutex_unlock(mutex_for_fo); + + return 0; + +resource_busy: + mutex_unlock(mutex_for_fo); + + return ret; +} + +int vo_release(int layer, struct file *filp) +{ + _s5p_grp_stop(layer); + + return 0; +} + +/* modified for 2.6.29 v4l2-dev.c */ +static int s5p_tv_vo0_open(struct file *file) +{ + vo_open(0, file); + return 0; +} + +static int s5p_tv_vo0_release(struct file *file) +{ + vo_release(0, file); + return 0; +} + +static int s5p_tv_vo1_open(struct file *file) +{ + vo_open(1, file); + return 0; +} + +static int s5p_tv_vo1_release(struct file *file) +{ + vo_release(1, file); + return 0; +} +#endif + +#ifdef CONFIG_TV_FB +static int s5ptvfb_alloc_framebuffer(void) +{ + int ret; + + /* alloc for each framebuffer */ + s5ptv_status.fb = framebuffer_alloc(sizeof(struct s5ptvfb_window), + s5ptv_status.dev_fb); + if (!s5ptv_status.fb) { + dev_err(s5ptv_status.dev_fb, "not enough memory\n"); + ret = -ENOMEM; + goto err_alloc_fb; + } + + ret = s5ptvfb_init_fbinfo(5); + if (ret) { + dev_err(s5ptv_status.dev_fb, + "failed to allocate memory for fb for tv\n"); + ret = -ENOMEM; + goto err_alloc_fb; + } +#ifndef CONFIG_USER_ALLOC_TVOUT + if (s5ptvfb_map_video_memory(s5ptv_status.fb)) { + dev_err(s5ptv_status.dev_fb, + "failed to map video memory " + "for default window \n"); + ret = -ENOMEM; + goto err_alloc_fb; + } +#endif + return 0; + +err_alloc_fb: + if (s5ptv_status.fb) + framebuffer_release(s5ptv_status.fb); + + kfree(s5ptv_status.fb); + + return ret; +} + +int s5ptvfb_free_framebuffer(void) +{ +#ifndef CONFIG_USER_ALLOC_TVOUT + if (s5ptv_status.fb) + s5ptvfb_unmap_video_memory(s5ptv_status.fb); +#endif + + if (s5ptv_status.fb) + framebuffer_release(s5ptv_status.fb); + + return 0; +} + +int s5ptvfb_register_framebuffer(void) +{ + int ret; + + ret = register_framebuffer(s5ptv_status.fb); + if (ret) { + dev_err(s5ptv_status.dev_fb, "failed to register " + "framebuffer device\n"); + return -EINVAL; + } +#ifndef CONFIG_FRAMEBUFFER_CONSOLE +#ifndef CONFIG_USER_ALLOC_TVOUT + s5ptvfb_check_var(&s5ptv_status.fb->var, s5ptv_status.fb); + s5ptvfb_set_par(s5ptv_status.fb); + s5ptvfb_draw_logo(s5ptv_status.fb); +#endif +#endif + + return 0; +} +#endif + +/* + * struct for video + */ +#ifdef CONFIG_TV_FB +static struct v4l2_file_operations s5p_tv_fops = { + .owner = THIS_MODULE, + .open = s5p_tv_open, + .ioctl = s5p_tv_ioctl, + .release = s5p_tv_release +}; +static struct v4l2_file_operations s5p_tv_vid_fops = { + .owner = THIS_MODULE, + .open = s5p_tv_vid_open, + .ioctl = s5p_tv_vid_ioctl, + .release = s5p_tv_vid_release +}; + #else +static struct v4l2_file_operations s5p_tv_v_fops = { + .owner = THIS_MODULE, + .open = s5p_tv_v_open, + .read = s5p_tv_v_read, + .write = s5p_tv_v_write, + .ioctl = s5p_tv_v_ioctl, + .mmap = s5p_tv_v_mmap, + .release = s5p_tv_v_release +}; + +/* + * struct for graphic0 + */ +static struct v4l2_file_operations s5p_tv_vo0_fops = { + .owner = THIS_MODULE, + .open = s5p_tv_vo0_open, + .ioctl = s5p_tv_vo_ioctl, + .release = s5p_tv_vo0_release +}; + +/* + * struct for graphic1 + */ +static struct v4l2_file_operations s5p_tv_vo1_fops = { + .owner = THIS_MODULE, + .open = s5p_tv_vo1_open, + .ioctl = s5p_tv_vo_ioctl, + .release = s5p_tv_vo1_release +}; +#endif + +void s5p_tv_vdev_release(struct video_device *vdev) +{ + kfree(vdev); +} + +struct video_device s5p_tvout[] = { + +#ifdef CONFIG_TV_FB + [0] = { + .name = "S5PC1xx TVOUT ctrl", + .fops = &s5p_tv_fops, + .ioctl_ops = &s5p_tv_v4l2_ops, + .release = s5p_tv_vdev_release, + .minor = TVOUT_MINOR_TVOUT, + .tvnorms = V4L2_STD_ALL_HD, + }, + [1] = { + .name = "S5PC1xx TVOUT for Video", + .fops = &s5p_tv_vid_fops, + .ioctl_ops = &s5p_tv_v4l2_vid_ops, + .release = s5p_tv_vdev_release, + .minor = TVOUT_MINOR_VID, + .tvnorms = V4L2_STD_ALL_HD, + }, +#else + [0] = { + .name = "S5PC1xx TVOUT Video", + .fops = &s5p_tv_v_fops, + .ioctl_ops = &s5p_tv_v4l2_v_ops, + .release = s5p_tv_vdev_release, + .minor = TVOUT_MINOR_VIDEO, + .tvnorms = V4L2_STD_ALL_HD, + }, + [1] = { + .name = "S5PC1xx TVOUT Overlay0", + .fops = &s5p_tv_vo0_fops, + .ioctl_ops = &s5p_tv_v4l2_vo_ops, + .release = s5p_tv_vdev_release, + .minor = TVOUT_MINOR_GRP0, + .tvnorms = V4L2_STD_ALL_HD, + }, + [2] = { + .name = "S5PC1xx TVOUT Overlay1", + .fops = &s5p_tv_vo1_fops, + .ioctl_ops = &s5p_tv_v4l2_vo_ops, + .release = s5p_tv_vdev_release, + .minor = TVOUT_MINOR_GRP1, + .tvnorms = V4L2_STD_ALL_HD, + }, +#endif +}; + +void s5p_handle_cable(void) +{ + char env_buf[120]; + char *envp[2]; + int env_offset = 0; + + printk(KERN_INFO "%s....start", __func__); + + if ((s5ptv_status.tvout_param.out_mode != TVOUT_OUTPUT_HDMI) && \ + (s5ptv_status.tvout_param.out_mode != TVOUT_OUTPUT_HDMI_RGB) && \ + (s5ptv_status.tvout_param.out_mode != TVOUT_OUTPUT_DVI)) + return; + + bool previous_hpd_status = s5ptv_status.hpd_status; +#ifdef CONFIG_HDMI_HPD + s5ptv_status.hpd_status = s5p_hpd_get_state(); +#else + return; +#endif + + memset(env_buf, 0, sizeof(env_buf)); + + if (previous_hpd_status == s5ptv_status.hpd_status) { + BASEPRINTK("same hpd_status value: %d\n", previous_hpd_status); + return; + } + + if (s5ptv_status.hpd_status) { + BASEPRINTK("\n hdmi cable is connected \n"); + + if (s5ptv_status.suspend_status) + return; + +#ifdef CONFIG_CPU_FREQ_S5PV210 + s5pv210_set_cpufreq_level(RESTRICT_TABLE); +#endif /* CONFIG_CPU_FREQ_S5PV210 */ + +#ifdef CONFIG_PM + s5p_tv_clk_gate(true); +/* + if ((s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI)\ + || (s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI_RGB)) +*/ + tv_phy_power(true); +#endif + /* tv on */ + if (s5ptv_status.tvout_output_enable) + _s5p_tv_if_start(); + + /* video layer start */ + if (s5ptv_status.vp_layer_enable) + _s5p_vlayer_start(); + + /* grp0 layer start */ + if (s5ptv_status.grp_layer_enable[0]) + _s5p_grp_start(VM_GPR0_LAYER); + + /* grp1 layer start */ + if (s5ptv_status.grp_layer_enable[1]) + _s5p_grp_start(VM_GPR1_LAYER); + + sprintf(env_buf, "HDMI_STATE=online"); + envp[env_offset++] = env_buf; + envp[env_offset] = NULL; + kobject_uevent_env(&(s5p_tvout[0].dev.kobj), KOBJ_CHANGE, envp); + + } else { + BASEPRINTK("\n hdmi cable is disconnected \n"); + + if (s5ptv_status.suspend_status) + return; + + if (s5ptv_status.vp_layer_enable) { + _s5p_vlayer_stop(); + s5ptv_status.vp_layer_enable = true; + + } + + /* grp0 layer stop */ + if (s5ptv_status.grp_layer_enable[0]) { + _s5p_grp_stop(VM_GPR0_LAYER); + s5ptv_status.grp_layer_enable[VM_GPR0_LAYER] = true; + } + + /* grp1 layer stop */ + if (s5ptv_status.grp_layer_enable[1]) { + _s5p_grp_stop(VM_GPR1_LAYER); + s5ptv_status.grp_layer_enable[VM_GPR0_LAYER] = true; + } + + /* tv off */ + if (s5ptv_status.tvout_output_enable) { + _s5p_tv_if_stop(); + s5ptv_status.tvout_output_enable = true; + s5ptv_status.tvout_param_available = true; + } + +#ifdef CONFIG_PM + /* clk & power off */ + s5p_tv_clk_gate(false); +/* + if ((s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI) ||\ + (s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI_RGB)) +*/ + tv_phy_power(false); +#endif + + sprintf(env_buf, "HDMI_STATE=offline"); + envp[env_offset++] = env_buf; + envp[env_offset] = NULL; + kobject_uevent_env(&(s5p_tvout[0].dev.kobj), KOBJ_CHANGE, envp); + +#ifdef CONFIG_CPU_FREQ_S5PV210 + s5pv210_set_cpufreq_level(NORMAL_TABLE); +#endif /* CONFIG_CPU_FREQ_S5PV210 */ + } +} + +#define S5P_TVMAX_CTRLS ARRAY_SIZE(s5p_tvout) +/* + * Probe + */ + +static int __devinit s5p_tv_probe(struct platform_device *pdev) +{ + int irq_num; + int ret; + int i, retval; + + + /* Get csis power domain regulator */ + s5ptv_status.tv_regulator = regulator_get(&pdev->dev, "pd"); + if (IS_ERR(s5ptv_status.tv_regulator)) { + printk(KERN_ERR "%s %d: failed to get resource %s\n", + __func__, __LINE__, "s3c-tv20 pd"); + return PTR_ERR(s5ptv_status.tv_regulator); + } + + s5ptv_status.tv_tvout = regulator_get(NULL, "tvout"); + if (IS_ERR(s5ptv_status.tv_tvout)) { + printk(KERN_ERR "%s %d: failed to get resource %s\n", + __func__, __LINE__, "s3c-tv20 tvout"); + return PTR_ERR(s5ptv_status.tv_tvout); + } + +#ifdef CONFIG_MACH_P1 + s5ptv_status.tv_tv = regulator_get(NULL, "tv"); + if (IS_ERR(s5ptv_status.tv_tv)) { + printk(KERN_ERR "%s %d: failed to get resource %s\n", + __func__, __LINE__, "s3c-tv20 tv"); + return PTR_ERR(s5ptv_status.tv_tv); + } + regulator_enable(s5ptv_status.tv_tv); +#endif + s5ptv_status.dev_fb = &pdev->dev; + + __s5p_sdout_probe(pdev, 0); + __s5p_vp_probe(pdev, 1); + __s5p_mixer_probe(pdev, 2); + +#ifdef CONFIG_CPU_S5PC100 + __s5p_hdmi_probe(pdev, 3); + __s5p_tvclk_probe(pdev, 4); +#endif + +#ifdef CONFIG_CPU_S5PV210 + tv_clk_get(pdev, &s5ptv_status); + s5p_tv_clk_gate(true); + __s5p_hdmi_probe(pdev, 3, 4); + __s5p_hdcp_init(); +#endif +#if defined(CONFIG_MACH_P1) + retval = i2c_add_driver(&SII9234A_i2c_driver); + if (retval != 0) + printk(KERN_ERR "[MHL SII9234A] can't add i2c driver"); + + retval = i2c_add_driver(&SII9234B_i2c_driver); + if (retval != 0) + printk(KERN_ERR "[MHL SII9234B] can't add i2c driver"); + + retval = i2c_add_driver(&SII9234C_i2c_driver); + if (retval != 0) + printk(KERN_ERR "[MHL SII9234C] can't add i2c driver"); + + retval = i2c_add_driver(&SII9234_i2c_driver); + if (retval != 0) + printk(KERN_ERR "[MHL SII9234] can't add i2c driver"); +#endif + +#ifdef FIX_27M_UNSTABLE_ISSUE /* for smdkc100 pop */ + writel(0x1, S5PC1XX_GPA0_BASE + 0x56c); +#endif + +#ifdef I2C_BASE + /* for dev_dbg err. */ + spin_lock_init(&slock_hpd); + + /* for bh */ + INIT_WORK(&ws_hpd, (void *)set_ddc_port); +#endif + /* check EINT init state */ +#ifdef CONFIG_CPU_S5PC100 + s3c_gpio_cfgpin(S5PC1XX_GPH0(5), S3C_GPIO_SFN(2)); + s3c_gpio_setpull(S5PC1XX_GPH0(5), S3C_GPIO_PULL_UP); + + s5ptv_status.hpd_status = gpio_get_value(S5PC1XX_GPH0(5)) ? \ + false : true; +#endif + +#ifdef CONFIG_CPU_S5PV210 +#ifdef CONFIG_HDMI_HPD + s5ptv_status.hpd_status = 0; +#else + s5ptv_status.hpd_status = 0; +#endif +#endif + dev_info(&pdev->dev, "hpd status: cable %s\n",\ + s5ptv_status.hpd_status ? "inserted":"removed/not connected"); + + /* Interrupt */ + TVOUT_IRQ_INIT(irq_num, ret, pdev, 0, out, __s5p_mixer_irq, "mixer"); + TVOUT_IRQ_INIT(irq_num, ret, pdev, 1, out_hdmi_irq, __s5p_hdmi_irq , \ + "hdmi"); + TVOUT_IRQ_INIT(irq_num, ret, pdev, 2, out_tvenc_irq, s5p_tvenc_irq, \ + "tvenc"); + +#ifdef CONFIG_CPU_S5PC100 + TVOUT_IRQ_INIT(irq_num, ret, pdev, 3, out_hpd_irq, __s5p_hpd_irq, \ + "hpd"); + set_irq_type(IRQ_EINT5, IRQ_TYPE_LEVEL_LOW); +#endif + /* v4l2 video device registration */ + for (i = 0; i < S5P_TVMAX_CTRLS; i++) { + s5ptv_status.video_dev[i] = &s5p_tvout[i]; + + if (video_register_device(s5ptv_status.video_dev[i], + VFL_TYPE_GRABBER, s5p_tvout[i].minor) != 0) { + + dev_err(&pdev->dev, + "Couldn't register tvout driver.\n"); + return 0; + } + } + +#ifdef CONFIG_TV_FB + mutex_init(&s5ptv_status.fb_lock); + + /* for default start up */ + _s5p_tv_if_init_param(); + + s5ptv_status.tvout_param.disp_mode = TVOUT_720P_60; + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI; + +#ifndef CONFIG_USER_ALLOC_TVOUT + s5p_tv_clk_gate(true); +/* + if ((s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI) || + (s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI_RGB)) +*/ + tv_phy_power(true); + _s5p_tv_if_set_disp(); +#endif + s5ptvfb_set_lcd_info(&s5ptv_status); + + /* prepare memory */ + if (s5ptvfb_alloc_framebuffer()) + goto err_alloc; + + if (s5ptvfb_register_framebuffer()) + goto err_alloc; +#ifndef CONFIG_USER_ALLOC_TVOUT + s5ptvfb_display_on(&s5ptv_status); +#endif +#endif + mutex_for_fo = kmalloc(sizeof(struct mutex), + GFP_KERNEL); + + if (mutex_for_fo == NULL) { + dev_err(&pdev->dev, + "failed to create mutex handle\n"); + goto out; + } +#ifdef I2C_BASE + mutex_for_i2c = kmalloc(sizeof(struct mutex), + GFP_KERNEL); + + if (mutex_for_i2c == NULL) { + dev_err(&pdev->dev, + "failed to create mutex handle\n"); + goto out; + } + mutex_init(mutex_for_i2c); +#endif + mutex_init(mutex_for_fo); + +#ifdef CONFIG_CPU_S5PV210 + /* added for phy cut off when boot up */ + clk_enable(s5ptv_status.i2c_phy_clk); + + __s5p_hdmi_phy_power(false); + clk_disable(s5ptv_status.i2c_phy_clk); + + s5p_tv_clk_gate(false); +#endif + printk(KERN_INFO "%s TV Probing is done\n", __func__); + return 0; + +#ifdef CONFIG_TV_FB +err_alloc: +#endif + +#ifdef CONFIG_CPU_S5PC100 +out_hpd_irq: + free_irq(IRQ_TVENC, pdev); +#endif + +out_tvenc_irq: + free_irq(IRQ_HDMI, pdev); + +out_hdmi_irq: + free_irq(IRQ_MIXER, pdev); + +out: + printk(KERN_ERR "not found (%d). \n", ret); + + return ret; +} + +/* + * Remove + */ +static int s5p_tv_remove(struct platform_device *pdev) +{ + __s5p_hdmi_release(pdev); + __s5p_sdout_release(pdev); + __s5p_mixer_release(pdev); + __s5p_vp_release(pdev); +#ifdef CONFIG_CPU_S5PC100 + __s5p_tvclk_release(pdev); +#endif +#ifdef I2C_BASE + i2c_del_driver(&hdcp_i2c_driver); +#endif +#if defined(CONFIG_MACH_P1) + i2c_del_driver(&SII9234A_i2c_driver); + i2c_del_driver(&SII9234B_i2c_driver); + i2c_del_driver(&SII9234C_i2c_driver); + i2c_del_driver(&SII9234_i2c_driver); +#endif + clk_disable(s5ptv_status.tvenc_clk); + clk_disable(s5ptv_status.vp_clk); + clk_disable(s5ptv_status.mixer_clk); + clk_disable(s5ptv_status.hdmi_clk); + clk_disable(s5ptv_status.sclk_hdmi); + clk_disable(s5ptv_status.sclk_mixer); + clk_disable(s5ptv_status.sclk_dac); + + clk_put(s5ptv_status.tvenc_clk); + clk_put(s5ptv_status.vp_clk); + clk_put(s5ptv_status.mixer_clk); + clk_put(s5ptv_status.hdmi_clk); + clk_put(s5ptv_status.sclk_hdmi); + clk_put(s5ptv_status.sclk_mixer); + clk_put(s5ptv_status.sclk_dac); + clk_put(s5ptv_status.sclk_pixel); + clk_put(s5ptv_status.sclk_hdmiphy); + + free_irq(IRQ_MIXER, pdev); + free_irq(IRQ_HDMI, pdev); + free_irq(IRQ_TVENC, pdev); +#ifdef CONFIG_CPU_S5PC100 + free_irq(IRQ_EINT5, pdev); +#endif + + regulator_disable(s5ptv_status.tv_regulator); + regulator_put(s5ptv_status.tv_regulator); + + regulator_disable(s5ptv_status.tv_tvout); + regulator_put(s5ptv_status.tv_tvout); +#ifdef CONFIG_MACH_P1 + regulator_disable(s5ptv_status.tv_tv); + regulator_put(s5ptv_status.tv_tv); +#endif + mutex_destroy(mutex_for_fo); +#ifdef I2C_BASE + mutex_destroy(mutex_for_i2c); +#endif + + return 0; +} + + +#ifdef CONFIG_PM +/* + * Suspend + */ +void s5p_tv_early_suspend(struct early_suspend *h) +{ + BASEPRINTK("%s----------------start \n", __func__); + + mutex_lock(mutex_for_fo); + s5ptv_status.suspend_status = true; + + if (!(s5ptv_status.hpd_status)) { + printk(KERN_INFO "(hpd_status = %d)++\n", \ + s5ptv_status.hpd_status); + mutex_unlock(mutex_for_fo); + return ; + } else { + /* video layer stop */ + if (s5ptv_status.vp_layer_enable) { + _s5p_vlayer_stop(); + s5ptv_status.vp_layer_enable = true; + } + + /* grp0 layer stop */ + if (s5ptv_status.grp_layer_enable[0]) { + _s5p_grp_stop(VM_GPR0_LAYER); + s5ptv_status.grp_layer_enable[VM_GPR0_LAYER] = true; + } + + /* grp1 layer stop */ + if (s5ptv_status.grp_layer_enable[1]) { + _s5p_grp_stop(VM_GPR1_LAYER); + s5ptv_status.grp_layer_enable[VM_GPR0_LAYER] = true; + } + + /* tv off */ + if (s5ptv_status.tvout_output_enable) { + _s5p_tv_if_stop(); + s5ptv_status.tvout_output_enable = true; + s5ptv_status.tvout_param_available = true; + } + + /* clk & power off */ + s5p_tv_clk_gate(false); + if ((s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI) ||\ + (s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI_RGB)) + tv_phy_power(false); + +#ifdef CONFIG_CPU_FREQ_S5PV210 + s5pv210_set_cpufreq_level(NORMAL_TABLE); +#endif /* CONFIG_CPU_FREQ_S5PV210 */ + } + + mutex_unlock(mutex_for_fo); + BASEPRINTK("()--\n"); + return ; +} + +/* + * Resume + */ +void s5p_tv_late_resume(struct early_suspend *h) +{ + BASEPRINTK("%s----------------start \n", __func__); + + mutex_lock(mutex_for_fo); + s5ptv_status.suspend_status = false; + + if (!(s5ptv_status.hpd_status)) { + printk(KERN_INFO "(hpd_status = %d)++\n", \ + s5ptv_status.hpd_status); + mutex_unlock(mutex_for_fo); + return ; + } else { +#ifdef CONFIG_CPU_FREQ_S5PV210 + s5pv210_set_cpufreq_level(RESTRICT_TABLE); +#endif /* CONFIG_CPU_FREQ_S5PV210 */ + + /* clk & power on */ + s5p_tv_clk_gate(true); + if ((s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI) ||\ + (s5ptv_status.tvout_param.out_mode == TVOUT_OUTPUT_HDMI_RGB)) + tv_phy_power(true); + + /* tv on */ + if (s5ptv_status.tvout_output_enable) + _s5p_tv_if_start(); + + /* video layer start */ + if (s5ptv_status.vp_layer_enable) + _s5p_vlayer_start(); + + /* grp0 layer start */ + if (s5ptv_status.grp_layer_enable[0]) + _s5p_grp_start(VM_GPR0_LAYER); + + /* grp1 layer start */ + if (s5ptv_status.grp_layer_enable[1]) + _s5p_grp_start(VM_GPR1_LAYER); + +#ifdef CONFIG_TV_FB + if (s5ptv_status.tvout_output_enable) { + s5ptvfb_display_on(&s5ptv_status); + s5ptvfb_set_par(s5ptv_status.fb); + } +#endif + } + mutex_unlock(mutex_for_fo); + BASEPRINTK("()--\n"); + return ; +} +#else +#define s5p_tv_suspend NULL +#define s5p_tv_resume NULL +#endif + +#ifdef CONFIG_PM +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend s5p_tv_early_suspend_desc = { + .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING, + .suspend = s5p_tv_early_suspend, + .resume = s5p_tv_late_resume, +}; +#endif +#endif + +static struct platform_driver s5p_tv_driver = { + .probe = s5p_tv_probe, + .remove = s5p_tv_remove, +#ifdef CONFIG_PM +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = s5p_tv_early_suspend, + .resume = s5p_tv_late_resume, +#endif +#else + .suspend = NULL, + .resume = NULL, +#endif + .driver = { + .name = "s5p-tvout", + .owner = THIS_MODULE, + }, +}; + +static char banner[] __initdata = + KERN_INFO "S5P TVOUT Driver, (c) 2010 Samsung Electronics\n"; + +int __init s5p_tv_init(void) +{ + int ret; + + printk(banner); + + ret = platform_driver_register(&s5p_tv_driver); + + if (ret) { + printk(KERN_ERR "Platform Device Register Failed %d\n", ret); + return -1; + } + +#ifdef CONFIG_PM +#ifdef CONFIG_HAS_EARLYSUSPEND + register_early_suspend(&s5p_tv_early_suspend_desc); +#endif +#endif + return 0; +} + +static void __exit s5p_tv_exit(void) +{ +#ifdef CONFIG_PM +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&s5p_tv_early_suspend_desc); +#endif +#endif + platform_driver_unregister(&s5p_tv_driver); +} + +late_initcall(s5p_tv_init); +module_exit(s5p_tv_exit); + +MODULE_AUTHOR("SangPil Moon"); +MODULE_DESCRIPTION("SS5PC1XX TVOUT driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c b/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c new file mode 100644 index 0000000..2a2a5e5 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c @@ -0,0 +1,1822 @@ +/* linux/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c + * + * Video4Linux API ftn. file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/delay.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> + +#include "s5p_tv.h" + +#ifdef COFIG_TVOUT_DBG +#define S5P_V4L2_DEBUG 1 +#endif + +#ifdef S5P_V4L2_DEBUG +#define V4L2PRINTK(fmt, args...)\ + printk(KERN_INFO "[V4L2_IF] %s: " fmt, __func__ , ## args) +#else +#define V4L2PRINTK(fmt, args...) +#endif + +/* 0 - hdcp stopped, 1 - hdcp started, 2 - hdcp reset */ +u8 hdcp_protocol_status; + +#define CVBS_S_VIDEO (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP| \ + V4L2_STD_PAL | V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ + V4L2_STD_PAL_60 | V4L2_STD_NTSC_443) + +static struct v4l2_output s5p_tv_outputs[] = { + { + .index = 0, + .name = "Analog COMPOSITE", + .type = V4L2_OUTPUT_TYPE_COMPOSITE, + .audioset = 0, + .modulator = 0, + .std = CVBS_S_VIDEO, + }, { + .index = 1, + .name = "Analog SVIDEO", + .type = V4L2_OUTPUT_TYPE_SVIDEO, + .audioset = 0, + .modulator = 0, + .std = CVBS_S_VIDEO, + }, { + .index = 2, + .name = "Analog COMPONENT_YPBPR_I", + .type = V4L2_OUTPUT_TYPE_YPBPR_INERLACED, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_ALL, + }, { + .index = 3, + .name = "Analog COMPONENT_YPBPR_P", + .type = V4L2_OUTPUT_TYPE_YPBPR_PROGRESSIVE, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_ALL, + }, { + .index = 4, + .name = "Analog COMPONENT_RGB_P", + .type = V4L2_OUTPUT_TYPE_RGB_PROGRESSIVE, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_ALL, + }, { + .index = 5, + .name = "Digital HDMI(YCbCr)", + .type = V4L2_OUTPUT_TYPE_HDMI, + .audioset = 2, + .modulator = 0, + .std = V4L2_STD_480P_60_16_9 | + V4L2_STD_480P_60_16_9 | V4L2_STD_720P_60 | + V4L2_STD_720P_50 +#ifdef CONFIG_CPU_S5PV210 + | V4L2_STD_1080P_60 | V4L2_STD_1080P_50 | + V4L2_STD_1080I_60 | V4L2_STD_1080I_50 | + V4L2_STD_480P_59 | V4L2_STD_720P_59 | + V4L2_STD_1080I_59 | V4L2_STD_1080P_59 | + V4L2_STD_1080P_30, +#endif + }, { + .index = 6, + .name = "Digital HDMI(RGB)", + .type = V4L2_OUTPUT_TYPE_HDMI_RGB, + .audioset = 2, + .modulator = 0, + .std = V4L2_STD_480P_60_16_9 | + V4L2_STD_480P_60_16_9 | + V4L2_STD_720P_60 | V4L2_STD_720P_50 +#ifdef CONFIG_CPU_S5PV210 + | V4L2_STD_1080P_60 | V4L2_STD_1080P_50 | + V4L2_STD_1080I_60 | V4L2_STD_1080I_50 | + V4L2_STD_480P_59 | V4L2_STD_720P_59 | + V4L2_STD_1080I_59 | V4L2_STD_1080P_59 | + V4L2_STD_1080P_30, +#endif + }, { + .index = 7, + .name = "Digital DVI", + .type = V4L2_OUTPUT_TYPE_DVI, + .audioset = 2, + .modulator = 0, + .std = V4L2_STD_480P_60_16_9 | + V4L2_STD_480P_60_16_9 | + V4L2_STD_720P_60 | V4L2_STD_720P_50 +#ifdef CONFIG_CPU_S5PV210 + | V4L2_STD_1080P_60 | V4L2_STD_1080P_50 | + V4L2_STD_1080I_60 | V4L2_STD_1080I_50 | + V4L2_STD_480P_59 | V4L2_STD_720P_59 | + V4L2_STD_1080I_59 | V4L2_STD_1080P_59 | + V4L2_STD_1080P_30, +#endif + } + +}; + +const struct v4l2_fmtdesc s5p_tv_o_fmt_desc[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, + .description = "YUV420, NV12 (Video Processor)", + .pixelformat = V4L2_PIX_FMT_NV12, + .flags = FORMAT_FLAGS_CrCb, + } +}; + +const struct v4l2_fmtdesc s5p_tv_o_overlay_fmt_desc[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + .description = "16bpp RGB, le - RGB[565]", + .pixelformat = V4L2_PIX_FMT_RGB565, + .flags = FORMAT_FLAGS_PACKED, + }, { + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + .description = "16bpp RGB, le - ARGB[1555]", + .pixelformat = V4L2_PIX_FMT_RGB555, + .flags = FORMAT_FLAGS_PACKED, + }, { + .index = 2, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + .description = "16bpp RGB, le - ARGB[4444]", + .pixelformat = V4L2_PIX_FMT_RGB444, + .flags = FORMAT_FLAGS_PACKED, + }, { + .index = 3, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + .description = "32bpp RGB, le - ARGB[8888]", + .pixelformat = V4L2_PIX_FMT_RGB32, + .flags = FORMAT_FLAGS_PACKED, + } +}; + +const struct v4l2_standard s5p_tv_standards[] = { + { + .index = 0, + .id = V4L2_STD_NTSC_M, + .name = "NTSC_M", + }, { + + .index = 1, + .id = V4L2_STD_PAL_BDGHI, + .name = "PAL_BDGHI", + }, { + .index = 2, + .id = V4L2_STD_PAL_M, + .name = "PAL_M", + }, { + .index = 3, + .id = V4L2_STD_PAL_N, + .name = "PAL_N", + }, { + .index = 4, + .id = V4L2_STD_PAL_Nc, + .name = "PAL_Nc", + }, { + .index = 5, + .id = V4L2_STD_PAL_60, + .name = "PAL_60", + }, { + .index = 6, + .id = V4L2_STD_NTSC_443, + .name = "NTSC_443", + }, { + .index = 7, + .id = V4L2_STD_480P_60_16_9, + .name = "480P_60_16_9", + }, { + .index = 8, + .id = V4L2_STD_480P_60_4_3, + .name = "480P_60_4_3", + }, { + .index = 9, + .id = V4L2_STD_576P_50_16_9, + .name = "576P_50_16_9", + }, { + .index = 10, + .id = V4L2_STD_576P_50_4_3, + .name = "576P_50_4_3", + }, { + .index = 11, + .id = V4L2_STD_720P_60, + .name = "720P_60", + }, { + .index = 12, + .id = V4L2_STD_720P_50, + .name = "720P_50", + }, +#ifdef CONFIG_CPU_S5PV210 + { + .index = 13, + .id = V4L2_STD_1080P_60, + .name = "1080P_60", + }, { + .index = 14, + .id = V4L2_STD_1080P_50, + .name = "1080P_50", + }, { + .index = 15, + .id = V4L2_STD_1080I_60, + .name = "1080I_60", + }, { + .index = 16, + .id = V4L2_STD_1080I_50, + .name = "1080I_50", + }, { + .index = 17, + .id = V4L2_STD_480P_59, + .name = "480P_59", + }, { + .index = 18, + .id = V4L2_STD_720P_59, + .name = "720P_59", + }, { + .index = 19, + .id = V4L2_STD_1080I_59, + .name = "1080I_59", + }, { + .index = 20, + .id = V4L2_STD_1080P_59, + .name = "1080I_50", + }, { + .index = 21, + .id = V4L2_STD_1080P_30, + .name = "1080I_30", + } +#endif +}; + +/* TODO: set default format for v, vo0/1 */ + +const struct v4l2_format s5p_tv_format[] = { + { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, + }, { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + }, { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, + }, +}; + +#define S5P_TVOUT_MAX_STANDARDS \ + ARRAY_SIZE(s5p_tv_standards) +#define S5P_TVOUT_MAX_O_TYPES \ + ARRAY_SIZE(s5p_tv_outputs) +#define S5P_TVOUT_MAX_O_FMT \ + ARRAY_SIZE(s5p_tv_format) +#define S5P_TVOUT_MAX_O_FMT_DESC \ + ARRAY_SIZE(s5p_tv_o_fmt_desc) +#define S5P_TVOUT_MAX_O_OVERLAY_FMT_DESC \ + ARRAY_SIZE(s5p_tv_o_overlay_fmt_desc) + + +void s5p_tv_v4l2_init_param(void) +{ + s5ptv_status.v4l2.output = (struct v4l2_output *)&s5p_tv_outputs[0]; + s5ptv_status.v4l2.std = (struct v4l2_standard *)&s5p_tv_standards[0]; + s5ptv_status.v4l2.fmt_v = (struct v4l2_format *)&s5p_tv_o_fmt_desc[0]; + s5ptv_status.v4l2.fmt_vo_0 = (struct v4l2_format *)&s5p_tv_format[1]; + s5ptv_status.v4l2.fmt_vo_1 = (struct v4l2_format *)&s5p_tv_format[2]; + s5ptv_status.hdmi_audio_type = HDMI_AUDIO_PCM; +} + +/* VIDIOC_QUERYCAP handler */ +static int s5p_tv_v4l2_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + u32 index; + + if (layer == NULL) { + index = 0; + strcpy(cap->driver, "S3C TV Vid drv"); + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT; + } else { + index = layer->index + 1; + strcpy(cap->driver, "S3C TV Grp drv"); + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + } + + strlcpy(cap->card, s5ptv_status.video_dev[index]->name, + sizeof(cap->card)); + + sprintf(cap->bus_info, "ARM AHB BUS"); + cap->version = KERNEL_VERSION(2, 6, 29); + + return 0; +} + + +/* VIDIOC_ENUM_FMT handlers */ +static int s5p_tv_v4l2_enum_fmt_vid_out(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + int index = f->index; + + V4L2PRINTK("(%d)++\n", f->index); + + if (index >= S5P_TVOUT_MAX_O_FMT_DESC) { + V4L2PRINTK("exceeded S5P_TVOUT_MAX_O_FMT_DESC\n"); + return -EINVAL; + } + + memcpy(f, &s5p_tv_o_fmt_desc[index], sizeof(struct v4l2_fmtdesc)); + + V4L2PRINTK("()--\n"); + return 0; + +} + +static int s5p_tv_v4l2_enum_fmt_vid_out_overlay(struct file *file, + void *fh, struct v4l2_fmtdesc *f) +{ + int index = f->index; + + V4L2PRINTK("(%d)++\n", f->index); + + if (index >= S5P_TVOUT_MAX_O_OVERLAY_FMT_DESC) { + V4L2PRINTK("exceeded S5P_TVOUT_MAX_O_OVERLAY_FMT_DESC\n"); + return -EINVAL; + } + + memcpy(f, &s5p_tv_o_overlay_fmt_desc[index], + sizeof(struct v4l2_fmtdesc)); + + V4L2PRINTK("()--\n"); + + return 0; +} + + +/* VIDIOC_G_FMT handlers */ +static int s5p_tv_v4l2_g_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + + struct v4l2_format *vid_out_fmt = f; + + V4L2PRINTK("(0x%08x)++\n", f->type); + + switch (vid_out_fmt->type) { + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: { + + struct v4l2_pix_format_s5p_tvout vparam; + memset(&vparam, 0, sizeof(struct v4l2_pix_format_s5p_tvout)); + + vparam.base_y = + (void *)s5ptv_status.vl_basic_param.top_y_address; + vparam.base_c = + (void *)s5ptv_status.vl_basic_param.top_c_address; + vparam.pix_fmt.pixelformat = + s5ptv_status.src_color; + vparam.pix_fmt.width = + s5ptv_status.vl_basic_param.src_width; + vparam.pix_fmt.height = + s5ptv_status.vl_basic_param.src_height; + V4L2PRINTK("[type 0x%08x] : addr_y: [0x%08x],\ + addr_c [0x%08x], width[%d], height[%d]\n", + f->type, + s5ptv_status.vl_basic_param.top_y_address, + s5ptv_status.vl_basic_param.top_c_address, + s5ptv_status.vl_basic_param.src_width, + s5ptv_status.vl_basic_param.src_height); + memcpy(vid_out_fmt->fmt.raw_data, &vparam, + sizeof(struct v4l2_pix_format_s5p_tvout)); + break; + } + + default: + break; + } + + return 0; +} + +static int s5p_tv_v4l2_g_fmt_vid_out_overlay(struct file *file, + void *fh, struct v4l2_format *f) +{ + + struct v4l2_format *vid_out_fmt = f; + + V4L2PRINTK("(0x%08x)++\n", f->type); + + switch (vid_out_fmt->type) { + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { + + struct v4l2_window_s5p_tvout vparam; + memset(&vparam, 0, sizeof(struct v4l2_window_s5p_tvout)); + + if (s5ptv_status.vl_basic_param.win_blending) { + vparam.flags = V4L2_FBUF_FLAG_CHROMAKEY; + vparam.capability = V4L2_FBUF_CAP_CHROMAKEY; + } + + if (s5ptv_status.vl_basic_param.alpha) { + vparam.flags = V4L2_FBUF_FLAG_LOCAL_ALPHA; + vparam.capability = V4L2_FBUF_CAP_LOCAL_ALPHA; + } + + vparam.priority = + s5ptv_status.vl_basic_param.priority; + + vparam.win.w.left = + s5ptv_status.vl_basic_param.src_offset_x; + vparam.win.w.top = + s5ptv_status.vl_basic_param.src_offset_y; + vparam.win.w.width = + s5ptv_status.vl_basic_param.src_width; + vparam.win.w.height = + s5ptv_status.vl_basic_param.src_height; + V4L2PRINTK("[type 0x%08x] : left: [%d], top [%d],\ + width[%d], height[%d]\n", + f->type, + s5ptv_status.vl_basic_param.src_offset_x, + s5ptv_status.vl_basic_param.src_offset_y, + s5ptv_status.vl_basic_param.src_width, + s5ptv_status.vl_basic_param.src_height); + memcpy(vid_out_fmt->fmt.raw_data, &vparam, + sizeof(struct v4l2_window_s5p_tvout)); + break; + } + + default: + break; + } + + V4L2PRINTK("()--\n"); + + return 0; +} + +/* VIDIOC_S_FMT handlers */ +static int s5p_tv_v4l2_s_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + + struct v4l2_format *vid_out_fmt = f; + + V4L2PRINTK("(0x%08x)++\n", f->type); + + switch (vid_out_fmt->type) { + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: { + + struct v4l2_pix_format_s5p_tvout vparam; + memcpy(&vparam, vid_out_fmt->fmt.raw_data, + sizeof(struct v4l2_pix_format_s5p_tvout)); + + s5ptv_status.vl_basic_param.img_width = + vparam.pix_fmt.width; + + s5ptv_status.vl_basic_param.img_height = + vparam.pix_fmt.height; + + s5ptv_status.vl_basic_param.src_width = + vparam.pix_fmt.width; + s5ptv_status.vl_basic_param.src_height = + vparam.pix_fmt.height; + s5ptv_status.src_color = + vparam.pix_fmt.pixelformat; + + s5ptv_status.vl_basic_param.top_y_address = + (unsigned int)vparam.base_y; + s5ptv_status.vl_basic_param.top_c_address = + (unsigned int)vparam.base_c; + + /* check progressive or not */ + if (vparam.pix_fmt.field == V4L2_FIELD_NONE) { + + /* progressive */ + + switch (vparam.pix_fmt.pixelformat) { + + case V4L2_PIX_FMT_NV12: + /* linear */ + s5ptv_status.src_color = + VPROC_SRC_COLOR_NV12; + break; + case V4L2_PIX_FMT_NV12T: + /* tiled */ + s5ptv_status.src_color = + VPROC_SRC_COLOR_TILE_NV12; + break; + default: + V4L2PRINTK("src img format not supported\n"); + break; + } + + s5ptv_status.field_id = VPROC_TOP_FIELD; + + if ((s5ptv_status.hpd_status) && \ + s5ptv_status.vp_layer_enable) { + struct s5p_video_img_address temp_addr; + struct s5p_img_size img_size; + + temp_addr.y_address = + (unsigned int)vparam.base_y; + temp_addr.c_address = + (unsigned int)vparam.base_c; + img_size.img_width = + (unsigned int)vparam.pix_fmt.width; + img_size.img_height = + (unsigned int)vparam.pix_fmt.height; + + _s5p_vlayer_set_top_address((unsigned long) + &temp_addr); + _s5p_vlayer_set_img_size((unsigned long) + &img_size); + + } + } else if (vparam.pix_fmt.field == V4L2_FIELD_INTERLACED_TB) { + + /* interlaced */ + + switch (vparam.pix_fmt.pixelformat) { + + case V4L2_PIX_FMT_NV12: + /* linear */ + s5ptv_status.src_color = + VPROC_SRC_COLOR_NV12IW; + break; + case V4L2_PIX_FMT_NV12T: + /* tiled */ + s5ptv_status.src_color = + VPROC_SRC_COLOR_TILE_NV12IW; + break; + default: + V4L2PRINTK("src img format not supported\n"); + break; + } + + if (vparam.pix_fmt.priv == V4L2_FIELD_BOTTOM) + s5ptv_status.field_id = VPROC_BOTTOM_FIELD; + else + s5ptv_status.field_id = VPROC_TOP_FIELD; + + if ((s5ptv_status.hpd_status) && \ + s5ptv_status.vp_layer_enable) { + struct s5p_video_img_address temp_addr; + struct s5p_img_size img_size; + + temp_addr.y_address = + (unsigned int)vparam.base_y; + temp_addr.c_address = + (unsigned int)vparam.base_c; + img_size.img_width = + (unsigned int)vparam.pix_fmt.width; + img_size.img_height = + (unsigned int)vparam.pix_fmt.height; + + _s5p_vlayer_set_top_address((unsigned long) + &temp_addr); + _s5p_vlayer_set_img_size((unsigned long) + &img_size); + + } + + } else { + V4L2PRINTK("this field id not supported\n"); + } + break; + } + + default: + break; + } + + V4L2PRINTK("[type 0x%08x] : addr_y: [0x%08x], addr_c [0x%08x],\ + width[%d], height[%d]\n", + f->type, + s5ptv_status.vl_basic_param.top_y_address, + s5ptv_status.vl_basic_param.top_c_address, + s5ptv_status.vl_basic_param.src_width, + s5ptv_status.vl_basic_param.src_height); + V4L2PRINTK("()--\n"); + + return 0; +} + + +static int s5p_tv_v4l2_s_fmt_vid_out_overlay(struct file *file, void *fh, + struct v4l2_format *f) +{ + + struct v4l2_format *vid_out_fmt = f; + + V4L2PRINTK("(0x%08x)++\n", f->type); + + switch (vid_out_fmt->type) { + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { + + struct v4l2_window_s5p_tvout vparam; + memcpy(&vparam, vid_out_fmt->fmt.raw_data, + sizeof(struct v4l2_window_s5p_tvout)); + + s5ptv_status.vl_basic_param.win_blending = + (vparam.flags & V4L2_FBUF_FLAG_CHROMAKEY) ? 1 : 0; + s5ptv_status.vl_basic_param.alpha = + (vparam.flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) ? 1 : 0; + s5ptv_status.vl_basic_param.priority = + vparam.priority; + s5ptv_status.vl_basic_param.src_offset_x = + vparam.win.w.left; + s5ptv_status.vl_basic_param.src_offset_y = + vparam.win.w.top; + s5ptv_status.vl_basic_param.src_width = + vparam.win.w.width; + s5ptv_status.vl_basic_param.src_height = + vparam.win.w.height; + V4L2PRINTK("[type 0x%08x] : left: [%d], top [%d],\ + width[%d], height[%d]\n", + f->type, + s5ptv_status.vl_basic_param.src_offset_x , + s5ptv_status.vl_basic_param.src_offset_y , + s5ptv_status.vl_basic_param.src_width, + s5ptv_status.vl_basic_param.src_height); + + if ((s5ptv_status.hpd_status) && s5ptv_status.vp_layer_enable) { + struct s5p_img_offset img_offset; + struct s5p_img_size img_size; + + img_offset.offset_x = vparam.win.w.left; + img_offset.offset_y = vparam.win.w.top; + img_size.img_width = vparam.win.w.width; + img_size.img_height = vparam.win.w.height; + _s5p_vlayer_set_blending( + s5ptv_status.vl_basic_param.win_blending); + _s5p_vlayer_set_alpha( + s5ptv_status.vl_basic_param.alpha); + _s5p_vlayer_set_priority(vparam.priority); + _s5p_vlayer_set_src_position((unsigned long) + &img_offset); + _s5p_vlayer_set_src_size((unsigned long) + &img_size); + } + + break; + } + + default: + break; + } + + V4L2PRINTK("()--\n"); + + return 0; +} + +/* start overlay * */ +static int s5p_tv_v4l2_overlay(struct file *file, void *fh, unsigned int i) +{ + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + int start = i; + V4L2PRINTK("(0x%08x)++\n", i); + + /* tv dirver is on suspend mode + Just set the status variable on this function + overlay will be enabled or disabled on resume or + handle_cable function according to this status variable*/ + if (s5ptv_status.suspend_status == true || !(s5ptv_status.hpd_status)) { + if (start) + s5ptv_status.grp_layer_enable[layer->index] = true; + else + s5ptv_status.grp_layer_enable[layer->index] = false; + + V4L2PRINTK("suspend mode/hdmi cable is not inserted\n"); + return 0; + } else { + if (start) + _s5p_grp_start(layer->index); + else + _s5p_grp_stop(layer->index); + } + V4L2PRINTK("()--\n"); + return 0; +} + +static int s5p_tv_v4l2_g_fbuf(struct file *file, void *fh, + struct v4l2_framebuffer *a) +{ + + struct v4l2_framebuffer *fbuf = a; + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + + fbuf->base = (void *)s5ptv_overlay[layer->index].base_addr; + fbuf->fmt.pixelformat = s5ptv_overlay[layer->index].fb.fmt.pixelformat; + + return 0; +} + +static int s5p_tv_v4l2_s_fbuf(struct file *file, void *fh, + struct v4l2_framebuffer *a) +{ + + struct v4l2_framebuffer *fbuf = a; + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + + s5ptv_overlay[layer->index].base_addr = (unsigned int)fbuf->base; + + switch (fbuf->fmt.pixelformat) { + + case V4L2_PIX_FMT_RGB565: + s5ptv_overlay[layer->index].fb.fmt.pixelformat = + VM_DIRECT_RGB565; + break; + + case V4L2_PIX_FMT_RGB555: + s5ptv_overlay[layer->index].fb.fmt.pixelformat = + VM_DIRECT_RGB1555; + break; + + case V4L2_PIX_FMT_RGB444: + s5ptv_overlay[layer->index].fb.fmt.pixelformat = + VM_DIRECT_RGB4444; + break; + + case V4L2_PIX_FMT_RGB32: + s5ptv_overlay[layer->index].fb.fmt.pixelformat = + VM_DIRECT_RGB8888; + break; + + default: + break; + } + + return 0; +} + +/* Stream on/off */ +static int s5p_tv_v4l2_streamon(struct file *file, void *fh, + enum v4l2_buf_type i) +{ + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + + V4L2PRINTK("(0x%08x)++\n", i); + + /* tv dirver is on suspend mode or hdmi cable is not inserted + Just set the status variable on this function + overlay will be enabled or disabled on resume or handle_cable + function according to this status variable*/ + if (s5ptv_status.suspend_status == true || !(s5ptv_status.hpd_status)) { + switch (i) { + /* Vlayer */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + _s5p_vlayer_init_param(0); + s5ptv_status.vp_layer_enable = true; + break; + /* GRP0/1*/ + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + s5ptv_status.grp_layer_enable[layer->index] = true; + break; + + default: + break; + } + V4L2PRINTK("suspend mode/hdmi cable is not inserted\n"); + return 0; + } + + switch (i) { + /* Vlayer*/ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (!(s5ptv_status.vp_layer_enable)) { + _s5p_vlayer_init_param(0); + _s5p_vlayer_start(); + s5ptv_status.vp_layer_enable = true; + + mdelay(50); + } else + return -EBUSY; + + break; + /* GRP0/1 */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + _s5p_grp_start(layer->index); + break; + + default: + break; + } + + V4L2PRINTK("()--\n"); + + return 0; +} + +static int s5p_tv_v4l2_streamoff(struct file *file, void *fh, + enum v4l2_buf_type i) +{ + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + + V4L2PRINTK("(0x%08x)++\n", i); + + /* tv driver is on suspend mode or hdmi cable is not inserted + Each layer was disabled on suspend function already. + Just set the status variable on this function + Each layer will be enabled or disabled on resume or + handle_cable function according to this status variable*/ + if (s5ptv_status.suspend_status == true || !(s5ptv_status.hpd_status)) { + switch (i) { + /* Vlayer*/ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + s5ptv_status.vp_layer_enable = false; + break; + /* GRP0/1*/ + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + s5ptv_status.grp_layer_enable[layer->index] = false; + break; + + default: + break; + } + V4L2PRINTK("suspend mode\hdmi cable is not inserted\n"); + return 0; + } + + switch (i) { + /* Vlayer */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + _s5p_vlayer_stop(); + break; + /* GRP0/1 */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + _s5p_grp_stop(layer->index); + break; + + default: + break; + } + + V4L2PRINTK("()--\n"); + + return 0; +} + +/* Standard handling ENUMSTD is handled by videodev.c */ +static int s5p_tv_v4l2_g_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + V4L2PRINTK("()++\n"); + + *norm = s5ptv_status.v4l2.std->id; + + V4L2PRINTK("(%d)++\n", (int)(*norm)); + + return 0; +} + +static int s5p_tv_v4l2_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + unsigned int i = 0; + v4l2_std_id std_id = *norm; + + V4L2PRINTK("(0x%08Lx)++\n", std_id); + + s5ptv_status.v4l2.std = NULL; + + do { + if (s5p_tv_standards[i].id == std_id) { + s5ptv_status.v4l2.std = (struct v4l2_standard *) + &s5p_tv_standards[i]; + break; + } + + i++; + } while (i < S5P_TVOUT_MAX_STANDARDS); + + if (i >= S5P_TVOUT_MAX_STANDARDS || s5ptv_status.v4l2.std == NULL) { + V4L2PRINTK("(ERR) There is no tv-out standards :\ + index = 0x%08Lx\n", std_id); + return -EINVAL; + } + + switch (std_id) { + + case V4L2_STD_NTSC_M: + s5ptv_status.tvout_param.disp_mode = TVOUT_NTSC_M; + break; + + case V4L2_STD_PAL_BDGHI: + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_BDGHI; + break; + + case V4L2_STD_PAL_M: + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_M; + break; + + case V4L2_STD_PAL_N: + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_N; + break; + + case V4L2_STD_PAL_Nc: + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_NC; + break; + + case V4L2_STD_PAL_60: + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_60; + break; + + case V4L2_STD_NTSC_443: + s5ptv_status.tvout_param.disp_mode = TVOUT_NTSC_443; + break; + + case V4L2_STD_480P_60_16_9: + s5ptv_status.tvout_param.disp_mode = TVOUT_480P_60_16_9; + break; + + case V4L2_STD_480P_60_4_3: + s5ptv_status.tvout_param.disp_mode = TVOUT_480P_60_4_3; + break; + +#ifdef CONFIG_CPU_S5PV210 + case V4L2_STD_480P_59: + s5ptv_status.tvout_param.disp_mode = TVOUT_480P_59; + break; +#endif + case V4L2_STD_576P_50_16_9: + s5ptv_status.tvout_param.disp_mode = TVOUT_576P_50_16_9; + break; + + case V4L2_STD_576P_50_4_3: + s5ptv_status.tvout_param.disp_mode = TVOUT_576P_50_4_3; + break; + + case V4L2_STD_720P_60: + s5ptv_status.tvout_param.disp_mode = TVOUT_720P_60; + break; + +#ifdef CONFIG_CPU_S5PV210 + case V4L2_STD_720P_59: + s5ptv_status.tvout_param.disp_mode = TVOUT_720P_59; + break; +#endif + + case V4L2_STD_720P_50: + s5ptv_status.tvout_param.disp_mode = TVOUT_720P_50; + break; + +#ifdef CONFIG_CPU_S5PV210 + case V4L2_STD_1080I_60: + s5ptv_status.tvout_param.disp_mode = TVOUT_1080I_60; + break; + + case V4L2_STD_1080I_59: + s5ptv_status.tvout_param.disp_mode = TVOUT_1080I_59; + break; + + case V4L2_STD_1080I_50: + s5ptv_status.tvout_param.disp_mode = TVOUT_1080I_50; + break; + + case V4L2_STD_1080P_30: + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_30; + break; + + case V4L2_STD_1080P_60: + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_60; + break; + + case V4L2_STD_1080P_59: + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_59; + break; + + case V4L2_STD_1080P_50: + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_50; + break; +#endif + default: + V4L2PRINTK("(ERR) not supported standard id :\ + index = 0x%08Lx\n", std_id); + return -EINVAL; + break; + } + + V4L2PRINTK("()--\n"); + + return 0; +} + +/* Output handling */ +static int s5p_tv_v4l2_enum_output(struct file *file, void *fh, + struct v4l2_output *a) +{ + unsigned int index = a->index; + V4L2PRINTK("(%d)++\n", a->index); + + if (index >= S5P_TVOUT_MAX_O_TYPES) { + V4L2PRINTK("exceeded supported output!!\n"); + return -EINVAL; + } + + memcpy(a, &s5p_tv_outputs[index], sizeof(struct v4l2_output)); + + V4L2PRINTK("()--\n"); + + return 0; +} + +static int s5p_tv_v4l2_g_output(struct file *file, void *fh, unsigned int *i) +{ + V4L2PRINTK("(%d)++\n", *i); + + *i = s5ptv_status.v4l2.output->index; + + V4L2PRINTK("()--\n"); + return 0; +} + +static int s5p_tv_v4l2_s_output(struct file *file, void *fh, unsigned int i) +{ + V4L2PRINTK("(%d)++\n", i); + + if (i >= S5P_TVOUT_MAX_O_TYPES) + return -EINVAL; + + s5ptv_status.v4l2.output = &s5p_tv_outputs[i]; + + switch (s5ptv_status.v4l2.output->type) { + + case V4L2_OUTPUT_TYPE_COMPOSITE: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_COMPOSITE; + break; + + case V4L2_OUTPUT_TYPE_SVIDEO: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_SVIDEO; + break; + + case V4L2_OUTPUT_TYPE_YPBPR_INERLACED: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED; + break; + + case V4L2_OUTPUT_TYPE_YPBPR_PROGRESSIVE: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE; + break; + + case V4L2_OUTPUT_TYPE_RGB_PROGRESSIVE: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_COMPOSITE; + break; + + case V4L2_OUTPUT_TYPE_HDMI: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_HDMI; + break; + + case V4L2_OUTPUT_TYPE_HDMI_RGB: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_HDMI_RGB; + break; + + case V4L2_OUTPUT_TYPE_DVI: + s5ptv_status.tvout_param.out_mode = + TVOUT_OUTPUT_DVI; + break; + + + default: + break; + } + + if ((s5ptv_status.tvout_param.out_mode != TVOUT_OUTPUT_HDMI) && \ + (s5ptv_status.tvout_param.out_mode != TVOUT_OUTPUT_HDMI_RGB) && + (s5ptv_status.tvout_param.out_mode != TVOUT_OUTPUT_DVI)) { + if (!(s5ptv_status.hpd_status)) + s5p_tv_clk_gate(true); + + s5ptv_status.hpd_status = 1; + } + + _s5p_tv_if_set_disp(); + + V4L2PRINTK("()--\n"); + + return 0; +}; + +/* Crop ioctls */ + +/* + * Video Format Name Pixel aspect ratio Description + * STD(4:3) Anamorphic(16:9) + * 640x480 4:3 Used on YouTube + * 720x576 576i 5:4 64:45 Used on D1/DV PAL + * 704x576 576p 12:11 16:11 Used on EDTV PAL + * 720x480 480i 8:9 32:27 Used on DV NTSC + * 720x486 480i 8:9 32:27 Used on D1 NTSC + * 704x480 480p 10:11 40:33 Used on EDTV NTSC + */ + +static int s5p_tv_v4l2_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *a) +{ + + struct v4l2_cropcap *cropcap = a; + + switch (cropcap->type) { + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + break; + + default: + return -1; + break; + } + + switch (s5ptv_status.tvout_param.disp_mode) { + + case TVOUT_NTSC_M: + + case TVOUT_NTSC_443: + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + +#ifdef CONFIG_CPU_S5PV210 + case TVOUT_480P_59: +#endif + cropcap->bounds.top = 0; + cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = 480; + + cropcap->defrect.top = 0; + cropcap->defrect.left = 0; + cropcap->defrect.width = 720; + cropcap->defrect.height = 480; + break; + + case TVOUT_PAL_M: + + case TVOUT_PAL_BDGHI: + + case TVOUT_PAL_N: + + case TVOUT_PAL_NC: + + case TVOUT_PAL_60: + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + + cropcap->bounds.top = 0; + cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = 576; + + cropcap->defrect.top = 0; + cropcap->defrect.left = 0; + cropcap->defrect.width = 720; + cropcap->defrect.height = 576; + break; + + case TVOUT_720P_60: +#ifdef CONFIG_CPU_S5PV210 + case TVOUT_720P_59: +#endif + case TVOUT_720P_50: + cropcap->bounds.top = 0; + cropcap->bounds.left = 0; + cropcap->bounds.width = 1280; + cropcap->bounds.height = 720; + + cropcap->defrect.top = 0; + cropcap->defrect.left = 0; + cropcap->defrect.width = 1280; + cropcap->defrect.height = 720; + break; + +#ifdef CONFIG_CPU_S5PV210 + + case TVOUT_1080I_60: + + case TVOUT_1080I_59: + + case TVOUT_1080I_50: + + case TVOUT_1080P_60: + + case TVOUT_1080P_59: + + case TVOUT_1080P_50: + + case TVOUT_1080P_30: + + cropcap->bounds.top = 0; + cropcap->bounds.left = 0; + cropcap->bounds.width = 1920; + cropcap->bounds.height = 1080; + + cropcap->defrect.top = 0; + cropcap->defrect.left = 0; + cropcap->defrect.width = 1920; + cropcap->defrect.height = 1080; + break; +#endif + + default: + return -1; + break; + + } + + V4L2PRINTK("[input type 0x%08x] : left: [%d], top [%d],\ + width[%d], height[%d]\n", + + s5ptv_status.tvout_param.disp_mode, + cropcap->bounds.top , + cropcap->bounds.left , + cropcap->bounds.width, + cropcap->bounds.height); + + return 0; +} + +static int s5p_tv_v4l2_g_crop(struct file *file, void *fh, struct v4l2_crop *a) +{ + + struct v4l2_crop *crop = a; + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + + switch (crop->type) { + /* Vlayer */ + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + crop->c.left = s5ptv_status.vl_basic_param.dest_offset_x; + crop->c.top = s5ptv_status.vl_basic_param.dest_offset_y; + crop->c.width = s5ptv_status.vl_basic_param.dest_width; + crop->c.height = s5ptv_status.vl_basic_param.dest_height; + break; + /* GRP0/1 */ + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + crop->c.left = s5ptv_overlay[layer->index].dst_rect.left; + crop->c.top = s5ptv_overlay[layer->index].dst_rect.top; + crop->c.width = s5ptv_overlay[layer->index].dst_rect.width; + crop->c.height = s5ptv_overlay[layer->index].dst_rect.height; + + break; + + default: + break; + } + + return 0; +} + +static int s5p_tv_v4l2_s_crop(struct file *file, void *fh, struct v4l2_crop *a) +{ + + struct v4l2_crop *crop = a; + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + + switch (crop->type) { + /* Vlayer - scaling!! */ + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + + s5ptv_status.vl_basic_param.dest_offset_x = crop->c.left; + s5ptv_status.vl_basic_param.dest_offset_y = crop->c.top; + s5ptv_status.vl_basic_param.dest_width = crop->c.width; + s5ptv_status.vl_basic_param.dest_height = crop->c.height; + + if ((s5ptv_status.hpd_status) && s5ptv_status.vp_layer_enable) { + struct s5p_img_size img_size; + struct s5p_img_offset img_offset; + img_size.img_width = crop->c.width; + img_size.img_height = crop->c.height; + img_offset.offset_x = crop->c.left; + img_offset.offset_y = crop->c.top; + + _s5p_vlayer_set_dest_size((unsigned long) + &img_size); + _s5p_vlayer_set_dest_position((unsigned long) + &img_offset); + } + + break; + + /* GRP0/1 */ + + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + s5ptv_overlay[layer->index].dst_rect.left = crop->c.left; + s5ptv_overlay[layer->index].dst_rect.top = crop->c.top; + s5ptv_overlay[layer->index].dst_rect.width = crop->c.width; + s5ptv_overlay[layer->index].dst_rect.height = crop->c.height; + break; + + default: + break; + } + + return 0; +} + +/* Stream type-dependent parameter ioctls */ + +static int s5p_tv_v4l2_g_parm_v(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + + struct v4l2_streamparm *param = a; + + struct v4l2_window_s5p_tvout vparam; + + if (s5ptv_status.vl_basic_param.win_blending) { + vparam.flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA; + vparam.capability = V4L2_FBUF_FLAG_GLOBAL_ALPHA; + } + + vparam.win.global_alpha = s5ptv_status.vl_basic_param.alpha; + + vparam.priority = s5ptv_status.vl_basic_param.priority; + vparam.win.w.left = s5ptv_status.vl_basic_param.src_offset_x; + vparam.win.w.top = s5ptv_status.vl_basic_param.src_offset_y; + vparam.win.w.width = s5ptv_status.vl_basic_param.src_width; + vparam.win.w.height = s5ptv_status.vl_basic_param.src_height; + + memcpy(param->parm.raw_data, &vparam, + sizeof(struct v4l2_window_s5p_tvout)); + + return 0; +} + +static int s5p_tv_v4l2_s_parm_v(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + + struct v4l2_streamparm *param = a; + + struct v4l2_window_s5p_tvout vparam; + + memcpy(&vparam, param->parm.raw_data, + sizeof(struct v4l2_window_s5p_tvout)); + + s5ptv_status.vl_basic_param.win_blending = + (vparam.flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) ? 1 : 0; + s5ptv_status.vl_basic_param.alpha = vparam.win.global_alpha; + s5ptv_status.vl_basic_param.priority = vparam.priority; + s5ptv_status.vl_basic_param.src_offset_x = vparam.win.w.left; + s5ptv_status.vl_basic_param.src_offset_y = vparam.win.w.top; + s5ptv_status.vl_basic_param.src_width = vparam.win.w.width; + s5ptv_status.vl_basic_param.src_height = vparam.win.w.height; + + V4L2PRINTK("[type 0x%08x] : left: [%d], top [%d],\ + width[%d], height[%d]\n", + a->type, + s5ptv_status.vl_basic_param.src_offset_x , + s5ptv_status.vl_basic_param.src_offset_y , + s5ptv_status.vl_basic_param.src_width, + s5ptv_status.vl_basic_param.src_height); + + if ((s5ptv_status.hpd_status) && s5ptv_status.vp_layer_enable) { + struct s5p_img_offset img_offset; + struct s5p_img_size img_size; + + img_offset.offset_x = vparam.win.w.left; + img_offset.offset_y = vparam.win.w.top; + img_size.img_width = vparam.win.w.width; + img_size.img_height = vparam.win.w.height; + _s5p_vlayer_set_blending( + s5ptv_status.vl_basic_param.win_blending); + _s5p_vlayer_set_alpha(s5ptv_status.vl_basic_param.alpha); + _s5p_vlayer_set_priority(vparam.priority); + _s5p_vlayer_set_src_position((unsigned long)&img_offset); + _s5p_vlayer_set_src_size((unsigned long)&img_size); + } + + return 0; +} + +static int s5p_tv_v4l2_g_parm_vo(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + + struct v4l2_streamparm *param = a; + + struct v4l2_window_s5p_tvout vparam; + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + + memset(&vparam, 0, sizeof(struct v4l2_window_s5p_tvout)); + + V4L2PRINTK("entered\n"); + + if (s5ptv_overlay[layer->index].win_blending) { + vparam.flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA; + vparam.capability = V4L2_FBUF_CAP_GLOBAL_ALPHA; + } + + if (s5ptv_overlay[layer->index].blank_change) { + vparam.flags |= V4L2_FBUF_FLAG_CHROMAKEY; + vparam.capability |= V4L2_FBUF_CAP_CHROMAKEY; + } + + if (s5ptv_overlay[layer->index].pixel_blending) { + vparam.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; + vparam.capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; + } + + if (s5ptv_overlay[layer->index].pre_mul) { + vparam.flags |= V4L2_FBUF_FLAG_PRE_MULTIPLY; + vparam.capability |= V4L2_FBUF_CAP_PRE_MULTIPLY; + } + + vparam.priority = s5ptv_overlay[layer->index].priority; + + vparam.win.chromakey = s5ptv_overlay[layer->index].blank_color; + vparam.win.w.left = s5ptv_overlay[layer->index].dst_rect.left; + vparam.win.w.top = s5ptv_overlay[layer->index].dst_rect.top; + vparam.win.w.left = s5ptv_overlay[layer->index].win.w.left; + vparam.win.w.top = s5ptv_overlay[layer->index].win.w.top; + vparam.win.w.width = s5ptv_overlay[layer->index].win.w.width; + vparam.win.w.height = s5ptv_overlay[layer->index].win.w.height; + vparam.win.global_alpha = s5ptv_overlay[layer->index].win.global_alpha; + + vparam.win.w.width = + s5ptv_overlay[layer->index].fb.fmt.bytesperline; + + memcpy(param->parm.raw_data, &vparam, + sizeof(struct v4l2_window_s5p_tvout)); + + return 0; + +} + +static int s5p_tv_v4l2_s_parm_vo(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + + struct v4l2_streamparm *param = a; + + struct v4l2_window_s5p_tvout vparam; + + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh; + memcpy(&vparam, param->parm.raw_data, + sizeof(struct v4l2_window_s5p_tvout)); + + s5ptv_overlay[layer->index].win_blending = + (vparam.flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) ? 1 : 0; + s5ptv_overlay[layer->index].blank_change = + (vparam.flags & V4L2_FBUF_FLAG_CHROMAKEY) ? 1 : 0; + s5ptv_overlay[layer->index].pixel_blending = + (vparam.flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) ? 1 : 0; + s5ptv_overlay[layer->index].pre_mul = + (vparam.flags & V4L2_FBUF_FLAG_PRE_MULTIPLY) ? 1 : 0; + s5ptv_overlay[layer->index].priority = + vparam.priority; + s5ptv_overlay[layer->index].blank_color = + vparam.win.chromakey; + s5ptv_overlay[layer->index].dst_rect.left = + vparam.win.w.left; + s5ptv_overlay[layer->index].dst_rect.top = + vparam.win.w.top; + s5ptv_overlay[layer->index].win.w.left = + vparam.win.w.left; + s5ptv_overlay[layer->index].win.w.top = + vparam.win.w.top; + s5ptv_overlay[layer->index].win.w.width = + vparam.win.w.width; + s5ptv_overlay[layer->index].win.w.height = + vparam.win.w.height; + s5ptv_overlay[layer->index].win.global_alpha = + vparam.win.global_alpha; + + s5ptv_overlay[layer->index].fb.fmt.bytesperline = + vparam.win.w.width; + + return 0; +} + +#define VIDIOC_HDCP_ENABLE _IOWR('V', 100, unsigned int) +#define VIDIOC_HDCP_STATUS _IOR('V', 101, unsigned int) +#define VIDIOC_HDCP_PROT_STATUS _IOR('V', 102, unsigned int) +#define VIDIOC_INIT_AUDIO _IOR('V', 103, unsigned int) +#define VIDIOC_AV_MUTE _IOR('V', 104, unsigned int) +#define VIDIOC_G_AVMUTE _IOR('V', 105, unsigned int) + +long s5p_tv_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + + case VIDIOC_HDCP_ENABLE: + s5ptv_status.hdcp_en = (unsigned int) arg; + V4L2PRINTK("HDCP status is %s\n", + s5ptv_status.hdcp_en ? "enabled" : "disabled"); + return 0; + + case VIDIOC_HDCP_STATUS: { + + unsigned int *status = (unsigned int *)&arg; + + *status = 1; + + V4L2PRINTK("HPD status is %s\n", + s5ptv_status.hpd_status ? "plugged" : "unplugged"); + return 0; + } + + case VIDIOC_HDCP_PROT_STATUS: { + + unsigned int *prot = (unsigned int *)&arg; + + *prot = 1; + + V4L2PRINTK("hdcp prot status is %d\n", + hdcp_protocol_status); + return 0; + } + + case VIDIOC_ENUMSTD: { + + struct v4l2_standard *p = (struct v4l2_standard *)arg; + + if (p->index >= S5P_TVOUT_MAX_STANDARDS) { + V4L2PRINTK("exceeded S5P_TVOUT_MAX_STANDARDS\n"); + return -EINVAL; + } + + memcpy(p, &s5p_tv_standards[p->index], + sizeof(struct v4l2_standard)); + + return 0; +} + + default: + break; + } + + /* + * in 2.6.28 version Mauro Carvalho Chehab added for removing inode + * but 2.6.29 is not applied. what is it? + */ + return video_ioctl2(file, cmd, arg); +} + +long s5p_tv_vid_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct video_device *vfd = video_devdata(file); + const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; + + switch (cmd) { + + case VIDIOC_S_FMT: { + struct v4l2_format *f = (struct v4l2_format *)arg; + void *fh = file->private_data; + long ret = -EINVAL; + + if (ops->vidioc_s_fmt_vid_out) + ret = ops->vidioc_s_fmt_vid_out(file, fh, f); + return ret; + } + + default: + break; + } + + /* + * in 2.6.28 version Mauro Carvalho Chehab added for removing inode + * but 2.6.29 is not applied. what is it? + */ + return video_ioctl2(file, cmd, arg); +} + + +long s5p_tv_v_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct video_device *vfd = video_devdata(file); + const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; + + switch (cmd) { + + case VIDIOC_INIT_AUDIO: + s5ptv_status.hdmi_audio_type = (unsigned int) arg; + + if (arg) { + s5p_hdmi_set_audio(true); + if (s5ptv_status.tvout_output_enable) + s5p_hdmi_audio_enable(true); + } else { + s5p_hdmi_set_audio(false); + if (s5ptv_status.tvout_output_enable) + s5p_hdmi_audio_enable(false); + + } + + return 0; + + case VIDIOC_AV_MUTE: + if (arg) { + s5ptv_status.hdmi_audio_type = HDMI_AUDIO_NO; + if (s5ptv_status.tvout_output_enable) { + s5p_hdmi_audio_enable(false); + __s5p_hdmi_video_set_bluescreen(true, 0, 0, 0); + } + s5p_hdmi_set_mute(true); + } else { + s5ptv_status.hdmi_audio_type = HDMI_AUDIO_PCM; + if (s5ptv_status.tvout_output_enable) { + s5p_hdmi_audio_enable(true); + __s5p_hdmi_video_set_bluescreen(false, 0, 0, 0); + } + s5p_hdmi_set_mute(false); + } + return 0; + case VIDIOC_G_AVMUTE: + return s5p_hdmi_get_mute(); + + case VIDIOC_S_FMT: { + struct v4l2_format *f = (struct v4l2_format *)arg; + void *fh = file->private_data; + long ret = -EINVAL; + + if (ops->vidioc_s_fmt_vid_out) + ret = ops->vidioc_s_fmt_vid_out(file, fh, f); + return ret; + } + + case VIDIOC_HDCP_ENABLE: + s5ptv_status.hdcp_en = (unsigned int) arg; + V4L2PRINTK("HDCP status is %s\n", + s5ptv_status.hdcp_en ? "enabled" : "disabled"); + return 0; + + case VIDIOC_HDCP_STATUS: { + + unsigned int *status = (unsigned int *)arg; + + *status = s5ptv_status.hpd_status; + + V4L2PRINTK("HPD status is %s\n", + s5ptv_status.hpd_status ? "plugged" : "unplugged"); + return 0; + } + + case VIDIOC_HDCP_PROT_STATUS: { + + unsigned int *prot = (unsigned int *)&arg; + + *prot = 1; + + V4L2PRINTK("hdcp prot status is %d\n", + hdcp_protocol_status); + return 0; + } + + case VIDIOC_ENUMSTD: { + + struct v4l2_standard *p = (struct v4l2_standard *)arg; + + if (p->index >= S5P_TVOUT_MAX_STANDARDS) { + V4L2PRINTK("exceeded S5P_TVOUT_MAX_STANDARDS\n"); + return -EINVAL; + } + + memcpy(p, &s5p_tv_standards[p->index], + sizeof(struct v4l2_standard)); + + return 0; + } + + default: + break; + } + + /* + * in 2.6.28 version Mauro Carvalho Chehab added for removing inode + * but 2.6.29 is not applied. what is it? + */ + return video_ioctl2(file, cmd, arg); +} + +long s5p_tv_vo_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void *fh = file->private_data; + + switch (cmd) { + + case VIDIOC_ENUM_FMT: { + + struct v4l2_fmtdesc *f = (struct v4l2_fmtdesc *)arg; + enum v4l2_buf_type type; + unsigned int index; + + index = f->index; + type = f->type; + + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) { + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = type; + + return s5p_tv_v4l2_enum_fmt_vid_out_overlay(file, + fh, f); + } + + break; + } + + case VIDIOC_G_FMT: { + + struct v4l2_format *f = (struct v4l2_format *)arg; + + return s5p_tv_v4l2_g_fmt_vid_out_overlay(file, fh, f); + } + + break; + + default: + break; + } + + /* + * in 2.6.28 version Mauro Carvalho Chehab added for removing inode + * but 2.6.29 is not applied. what is it? + */ + return video_ioctl2(file, cmd, arg); +} + +const struct v4l2_ioctl_ops s5p_tv_v4l2_ops = { + .vidioc_querycap = s5p_tv_v4l2_querycap, + .vidioc_g_std = s5p_tv_v4l2_g_std, + .vidioc_s_std = s5p_tv_v4l2_s_std, + .vidioc_enum_output = s5p_tv_v4l2_enum_output, + .vidioc_g_output = s5p_tv_v4l2_g_output, + .vidioc_s_output = s5p_tv_v4l2_s_output, +}; + +const struct v4l2_ioctl_ops s5p_tv_v4l2_vid_ops = { + .vidioc_querycap = s5p_tv_v4l2_querycap, + .vidioc_enum_fmt_vid_out = s5p_tv_v4l2_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = s5p_tv_v4l2_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = s5p_tv_v4l2_s_fmt_vid_out, + .vidioc_streamon = s5p_tv_v4l2_streamon, + .vidioc_streamoff = s5p_tv_v4l2_streamoff, + .vidioc_cropcap = s5p_tv_v4l2_cropcap, + .vidioc_g_crop = s5p_tv_v4l2_g_crop, + .vidioc_s_crop = s5p_tv_v4l2_s_crop, + .vidioc_g_parm = s5p_tv_v4l2_g_parm_v, + .vidioc_s_parm = s5p_tv_v4l2_s_parm_v, +}; + +const struct v4l2_ioctl_ops s5p_tv_v4l2_v_ops = { + .vidioc_querycap = s5p_tv_v4l2_querycap, + .vidioc_enum_fmt_vid_out = s5p_tv_v4l2_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = s5p_tv_v4l2_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = s5p_tv_v4l2_s_fmt_vid_out, + .vidioc_streamon = s5p_tv_v4l2_streamon, + .vidioc_streamoff = s5p_tv_v4l2_streamoff, + .vidioc_g_std = s5p_tv_v4l2_g_std, + .vidioc_s_std = s5p_tv_v4l2_s_std, + .vidioc_enum_output = s5p_tv_v4l2_enum_output, + .vidioc_g_output = s5p_tv_v4l2_g_output, + .vidioc_s_output = s5p_tv_v4l2_s_output, + .vidioc_cropcap = s5p_tv_v4l2_cropcap, + .vidioc_g_crop = s5p_tv_v4l2_g_crop, + .vidioc_s_crop = s5p_tv_v4l2_s_crop, + .vidioc_g_parm = s5p_tv_v4l2_g_parm_v, + .vidioc_s_parm = s5p_tv_v4l2_s_parm_v, +}; + +const struct v4l2_ioctl_ops s5p_tv_v4l2_vo_ops = { + .vidioc_querycap = s5p_tv_v4l2_querycap, + .vidioc_g_fmt_vid_out_overlay = s5p_tv_v4l2_g_fmt_vid_out_overlay, + .vidioc_s_fmt_vid_out_overlay = s5p_tv_v4l2_s_fmt_vid_out_overlay, + .vidioc_overlay = s5p_tv_v4l2_overlay, + .vidioc_g_fbuf = s5p_tv_v4l2_g_fbuf, + .vidioc_s_fbuf = s5p_tv_v4l2_s_fbuf, + .vidioc_streamon = s5p_tv_v4l2_streamon, + .vidioc_streamoff = s5p_tv_v4l2_streamoff, + .vidioc_cropcap = s5p_tv_v4l2_cropcap, + .vidioc_g_crop = s5p_tv_v4l2_g_crop, + .vidioc_s_crop = s5p_tv_v4l2_s_crop, + .vidioc_g_parm = s5p_tv_v4l2_g_parm_vo, + .vidioc_s_parm = s5p_tv_v4l2_s_parm_vo, +}; + diff --git a/drivers/media/video/samsung/tv20/s5pc100/hdcp_s5pc100.c b/drivers/media/video/samsung/tv20/s5pc100/hdcp_s5pc100.c new file mode 100644 index 0000000..7ca9cf4 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/hdcp_s5pc100.c @@ -0,0 +1,1596 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/hdcp_s5pc100.c + * + * hdcp raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/device.h> +#include <linux/wait.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include <mach/gpio.h> + +#include "tv_out_s5pc100.h" +#include "regs/regs-hdmi.h" + +/* for Operation check */ +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_HDCP_DEBUG 1 +#define S5P_HDCP_I2C_DEBUG 1 +#define S5P_HDCP_AUTH_DEBUG 1 +#endif + +#ifdef S5P_HDCP_DEBUG +#define HDCPPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[HDCP] %s: " fmt, __func__ , ## args) +#else +#define HDCPPRINTK(fmt, args...) +#endif + +/* for i2c bus check */ +#ifdef S5P_HDCP_I2C_DEBUG +#define I2CPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t\t\t[I2C] %s: " fmt, __func__ , ## args) +#else +#define I2CPRINTK(fmt, args...) +#endif + +/* for authentication key check */ +#ifdef S5P_HDCP_AUTH_DEBUG +#define AUTHPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t\t[AUTHKEY] %s: " fmt, __func__ , ## args) +#else +#define AUTHPRINTK(fmt, args...) +#endif + + + +enum hdmi_run_mode { + DVI_MODE, + HDMI_MODE +}; + +enum hdmi_resolution { + SD480P, + SD480I, + WWSD480P, + HD720P, + SD576P, + WWSD576P, + HD1080I +}; + +enum hdmi_color_bar_type { + HORIZONTAL, + VERTICAL +}; + +enum hdcp_event { + /* Stop HDCP */ + HDCP_EVENT_STOP, + /* Start HDCP*/ + HDCP_EVENT_START, + /* Start to read Bksv,Bcaps */ + HDCP_EVENT_READ_BKSV_START, + /* Start to write Aksv,An */ + HDCP_EVENT_WRITE_AKSV_START, + /* Start to check if Ri is equal to Rj */ + HDCP_EVENT_CHECK_RI_START, + /* Start 2nd authentication process */ + HDCP_EVENT_SECOND_AUTH_START +}; + +enum hdcp_state { + NOT_AUTHENTICATED, + RECEIVER_READ_READY, + BCAPS_READ_DONE, + BKSV_READ_DONE, + AN_WRITE_DONE, + AKSV_WRITE_DONE, + FIRST_AUTHENTICATION_DONE, + SECOND_AUTHENTICATION_RDY, + RECEIVER_FIFOLSIT_READY, + SECOND_AUTHENTICATION_DONE, +}; + +/* + * Below CSC_TYPE is temporary. CSC_TYPE enum. + * may be included in SetSD480pVars_60Hz etc. + * + * LR : Limited Range (16~235) + * FR : Full Range (0~255) + */ +enum hdmi_intr_src { + WAIT_FOR_ACTIVE_RX, + WDT_FOR_REPEATER, + EXCHANGE_KSV, + UPDATE_P_VAL, + UPDATE_R_VAL, + AUDIO_OVERFLOW, + AUTHEN_ACK, + UNKNOWN_INT +}; + +const u8 hdcp_key[288] = { + 0x48, 0xf8, 0x11, 0xb6, 0x85, 0x66, 0x9b, 0x65, 0x0b, 0x9f, + 0x5a, 0x01, 0xb4, 0x43, 0xaf, 0xd7, 0x34, 0xeb, 0xbe, 0xe0, + 0x52, 0xfb, 0x85, 0xfe, 0xfa, 0xb1, 0x2f, 0xe4, 0xc3, 0xce, + 0xa9, 0x27, 0x33, 0x74, 0x97, 0xd8, 0xfc, 0x62, 0xb8, 0x92, + 0x4a, 0xb6, 0xce, 0x7b, 0xb8, 0xda, 0x67, 0xbf, 0xda, 0xea, + 0xbf, 0xa9, 0xc0, 0x2a, 0xc8, 0xf6, 0x44, 0x41, 0x5a, 0x10, + 0x59, 0x88, 0x54, 0xcf, 0x51, 0x91, 0x12, 0xd5, 0xa8, 0x41, + 0x3a, 0x8a, 0x88, 0xd1, 0x5a, 0x9a, 0x55, 0xc1, 0xbb, 0x5e, + 0x8a, 0xa0, 0x84, 0x1b, 0xa8, 0xea, 0x31, 0x59, 0xea, 0x71, + 0x0c, 0xcf, 0x59, 0xf5, 0xa8, 0x32, 0x57, 0xbb, 0xd4, 0xa0, + 0x5b, 0x88, 0x44, 0x66, 0xd6, 0x80, 0xfa, 0xe9, 0x18, 0xe0, + 0x50, 0x73, 0x92, 0x63, 0xe1, 0x5c, 0x13, 0xbf, 0x7d, 0x0d, + 0x70, 0x0b, 0xf8, 0x25, 0x4a, 0x3b, 0x9c, 0x17, 0x56, 0xb3, + 0x71, 0x2b, 0xfe, 0x3c, 0xcb, 0x7c, 0x19, 0x28, 0x53, 0xa7, + 0x5c, 0x57, 0x47, 0xe3, 0xe1, 0x4c, 0x76, 0x62, 0x0a, 0x40, + 0x30, 0xcf, 0xbe, 0x51, 0xaf, 0x0d, 0x11, 0x73, 0xd6, 0x6a, + 0xc2, 0xbf, 0x4f, 0xc1, 0x88, 0x8d, 0x14, 0xa6, 0xd1, 0x92, + 0x6c, 0xf7, 0x8a, 0xe6, 0x9c, 0x96, 0xc5, 0xc4, 0x5c, 0x36, + 0xf6, 0xfb, 0x39, 0xf4, 0x79, 0x3f, 0x7a, 0x30, 0x71, 0x5e, + 0x3e, 0xfe, 0xf3, 0x4d, 0x0c, 0x02, 0x55, 0xeb, 0x08, 0x24, + 0x5f, 0x64, 0xd7, 0xcf, 0xf3, 0x48, 0x35, 0x03, 0xc4, 0xc8, + 0x29, 0xf7, 0x9d, 0xcf, 0x21, 0xb8, 0x67, 0x05, 0xc6, 0x47, + 0x05, 0x1b, 0x5f, 0xf3, 0xa7, 0xbc, 0x23, 0xf0, 0x09, 0xc4, + 0x90, 0x44, 0x5d, 0x3f, 0xf9, 0x79, 0x74, 0xea, 0x7b, 0x42, + 0x57, 0x88, 0xce, 0x32, 0x43, 0xa5, 0xf4, 0x4e, 0x05, 0xc9, + 0x73, 0xc2, 0x49, 0x94, 0x85, 0x5c, 0xa2, 0x11, 0x91, 0x1f, + 0x9e, 0xe3, 0x21, 0xbe, 0xe9, 0x36, 0x52, 0xec, 0x4b, 0xa6, + 0x7d, 0xf6, 0x8a, 0x85, 0xb9, 0xe1, 0xc7, 0x6e, 0x6b, 0x08, + 0x9d, 0xf2, 0xee, 0x7d, 0x28, 0xbd, 0xf0, 0x9d +}; + +struct s5p_hdcp_info { + bool is_repeater; + bool hpd_status; + u32 time_out; + u32 hdcp_enable; + + spinlock_t lock; + + struct i2c_client *client; + + wait_queue_head_t waitq; + enum hdcp_event event; + enum hdcp_state auth_status; + + struct work_struct work; +}; + +static struct s5p_hdcp_info hdcp_info = { + .is_repeater = false, + .time_out = 0, + .hdcp_enable = false, + .client = NULL, + .event = HDCP_EVENT_STOP, + .auth_status = NOT_AUTHENTICATED, + +}; + +#define HDCP_RI_OFFSET 0x08 +#define INFINITE 0xffffffff + +#define DO_NOT_TRANSMIT (0) +#define HDMI_SYS_ENABLE (1 << 0) +#define HDMI_ASP_ENABLE (1 << 2) +#define HDMI_ASP_DISABLE (~HDMI_ASP_ENABLE) + +#define MAX_DEVS_EXCEEDED (0x1 << 7) +#define MAX_CASCADE_EXCEEDED (0x1 << 3) + +#define MAX_CASCADE_EXCEEDED_ERROR (-1) +#define MAX_DEVS_EXCEEDED_ERROR (-2) +#define REPEATER_ILLEGAL_DEVICE_ERROR (-3) + +#define AINFO_SIZE 1 +#define BCAPS_SIZE 1 +#define BSTATUS_SIZE 2 +#define SHA_1_HASH_SIZE 20 + +#define KSV_FIFO_READY (0x1 << 5) + +#define SET_HDCP_KSV_WRITE_DONE (0x1 << 3) +#define CLEAR_HDCP_KSV_WRITE_DONE (~SET_HDCP_KSV_WRITE_DONE) + +#define SET_HDCP_KSV_LIST_EMPTY (0x1 << 2) +#define CLEAR_HDCP_KSV_LIST_EMPTY (~SET_HDCP_KSV_LIST_EMPTY) +#define SET_HDCP_KSV_END (0x1 << 1) +#define CLEAR_HDCP_KSV_END (~SET_HDCP_KSV_END) +#define SET_HDCP_KSV_READ (0x1 << 0) +#define CLEAR_HDCP_KSV_READ (~SET_HDCP_KSV_READ) + +#define SET_HDCP_SHA_VALID_READY (0x1 << 1) +#define CLEAR_HDCP_SHA_VALID_READY (~SET_HDCP_SHA_VALID_READY) +#define SET_HDCP_SHA_VALID (0x1 << 0) +#define CLEAR_HDCP_SHA_VALID (~SET_HDCP_SHA_VALID) + +#define TRANSMIT_EVERY_VSYNC (0x1 << 1) + +/* must be checked */ + +/* + * Read the HDCP data from Rx by using IIC + */ +static int hdcp_i2c_read(struct i2c_client *client, u8 subaddr, + u8 *data, u16 len) +{ + u8 addr = subaddr; + int ret = 0; + + struct i2c_msg msg[] = { + { client->addr, 0, 1, &addr}, + { client->addr, I2C_M_RD, len, data } + }; + + if (!hdcp_info.client) { + HDCPPRINTK("DDC port is not available!!" + "Check hdmi receiver's DDC Port \n"); + return -EIO; + } + + I2CPRINTK("sub addr = 0x%08x, data len = %d\n", subaddr, len); + + if (i2c_transfer(client->adapter, msg, 2) != 2) + ret = -EIO; + + I2CPRINTK("ret :%d\n", ret); + +#ifdef S5P_HDCP_I2C_DEBUG + { + int loop = 0; + HDCPPRINTK("read_data :: \n"); + printk(KERN_INFO "\t\t\t"); + + for (loop = 0; loop < len; loop++) + printk("0x%02x ", data[loop]); + + printk(KERN_INFO "\n"); + } +#endif + return ret; +} + +/* + * Write the HDCP data to receiver by using IIC + * - use i2c_master_send() + */ +static int hdcp_i2c_write(struct i2c_client *client, u8 *data, u16 len) +{ + int ret = 0; + + if (!hdcp_info.client) { + HDCPPRINTK("DDC port is not available!!" + "Check hdmi receiver's DDC Port \n"); + return -EIO; + } + + I2CPRINTK("sub addr = 0x%08x, data len = %d\n", + + data[0], len); + + if (i2c_master_send(client, (const char *) data, len) != len) + ret = -EIO; + + I2CPRINTK("ret :%d\n", ret); + + return ret; +} + +/* + * 1st Authentication step func. + * Write the Ainfo data to Rx + */ +static bool write_ainfo(void) +{ + int ret = 0; + u8 ainfo[2]; + + ainfo[0] = HDCP_Ainfo; + ainfo[1] = 0; + + ret = hdcp_i2c_write(hdcp_info.client, ainfo, 2); + + if (ret < 0) + HDCPPRINTK("Can't write ainfo data through i2c bus\n"); + + return (ret < 0) ? false : true; +} + +/* + * Write the An data to Rx + */ +static bool write_an(void) +{ + int ret = 0; + u8 an[AN_SIZE+1]; + + an[0] = HDCP_An; + + /* Read An from HDMI */ + an[1] = readb(hdmi_base + S5P_HDCP_An_0_0); + an[2] = readb(hdmi_base + S5P_HDCP_An_0_1); + an[3] = readb(hdmi_base + S5P_HDCP_An_0_2); + an[4] = readb(hdmi_base + S5P_HDCP_An_0_3); + an[5] = readb(hdmi_base + S5P_HDCP_An_1_0); + an[6] = readb(hdmi_base + S5P_HDCP_An_1_1); + an[7] = readb(hdmi_base + S5P_HDCP_An_1_2); + an[8] = readb(hdmi_base + S5P_HDCP_An_1_3); + + ret = hdcp_i2c_write(hdcp_info.client, an, AN_SIZE + 1); + + if (ret < 0) + HDCPPRINTK("Can't write an data through i2c bus\n"); + +#ifdef S5P_HDCP_AUTH_DEBUG + { + u16 i = 0; + + for (i = 1; i < AN_SIZE + 1; i++) + AUTHPRINTK("HDCPAn[%d]: 0x%x \n", i, an[i]); + + } +#endif + + return (ret < 0) ? false : true; +} + +/* + * Write the Aksv data to Rx + */ +static bool write_aksv(void) +{ + int ret = 0; + u8 aksv[AKSV_SIZE+1]; + + aksv[0] = HDCP_Aksv; + + /* Read Aksv from HDMI */ + aksv[1] = readb(hdmi_base + S5P_HDCP_AKSV_0_0); + aksv[2] = readb(hdmi_base + S5P_HDCP_AKSV_0_1); + aksv[3] = readb(hdmi_base + S5P_HDCP_AKSV_0_2); + aksv[4] = readb(hdmi_base + S5P_HDCP_AKSV_0_3); + aksv[5] = readb(hdmi_base + S5P_HDCP_AKSV_1); + + ret = hdcp_i2c_write(hdcp_info.client, aksv, AKSV_SIZE + 1); + + if (ret < 0) + HDCPPRINTK("Can't write aksv data through i2c bus\n"); + +#ifdef S5P_HDCP_AUTH_DEBUG + { + u16 i = 0; + + for (i = 1; i < AKSV_SIZE + 1; i++) + AUTHPRINTK("HDCPAksv[%d]: 0x%x\n", i, aksv[i]); + + } +#endif + + return (ret < 0) ? false : true; +} + +static bool read_bcaps(void) +{ + int ret = 0; + u8 bcaps[BCAPS_SIZE] = {0}; + + ret = hdcp_i2c_read(hdcp_info.client, HDCP_Bcaps, bcaps, BCAPS_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bcaps data from i2c bus\n"); + return false; + } + + writel(bcaps[0], hdmi_base + S5P_HDCP_BCAPS); + + HDCPPRINTK("BCAPS(from i2c) : 0x%08x\n", bcaps[0]); + + if (bcaps[0] & REPEATER_SET) + hdcp_info.is_repeater = true; + else + hdcp_info.is_repeater = false; + + HDCPPRINTK("attached device type : %s !! \n\r", + hdcp_info.is_repeater ? "REPEATER" : "SINK"); + + HDCPPRINTK("BCAPS(from sfr) = 0x%08x\n", + readl(hdmi_base + S5P_HDCP_BCAPS)); + + return true; +} + +static bool read_again_bksv(void) +{ + u8 bk_sv[BKSV_SIZE] = {0, 0, 0, 0, 0}; + u8 i = 0; + u8 j = 0; + u32 no_one = 0; + u32 no_zero = 0; + u32 result = 0; + int ret = 0; + + ret = hdcp_i2c_read(hdcp_info.client, HDCP_Bksv, bk_sv, BKSV_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bk_sv data from i2c bus\n"); + return false; + } + +#ifdef S5P_HDCP_AUTH_DEBUG + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("i2c read : Bksv[%d]: 0x%x\n", i, bk_sv[i]); + +#endif + + for (i = 0; i < BKSV_SIZE; i++) { + + for (j = 0; j < 8; j++) { + + result = bk_sv[i] & (0x1 << j); + + if (result == 0) + no_zero += 1; + else + no_one += 1; + } + } + + if ((no_zero == 20) && (no_one == 20)) { + HDCPPRINTK("Suucess: no_zero, and no_one is 20\n"); + + writel(bk_sv[0], hdmi_base + S5P_HDCP_BKSV_0_0); + writel(bk_sv[1], hdmi_base + S5P_HDCP_BKSV_0_1); + writel(bk_sv[2], hdmi_base + S5P_HDCP_BKSV_0_2); + writel(bk_sv[3], hdmi_base + S5P_HDCP_BKSV_0_3); + writel(bk_sv[4], hdmi_base + S5P_HDCP_BKSV_1); + +#ifdef S5P_HDCP_AUTH_DEBUG + + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("set reg : Bksv[%d]: 0x%x\n", i, bk_sv[i]); + +#endif + return true; + } else { + HDCPPRINTK("Failed: no_zero or no_one is NOT 20\n"); + return false; + } +} + +static bool read_bksv(void) +{ + u8 bk_sv[BKSV_SIZE] = {0, 0, 0, 0, 0}; + + int i = 0; + int j = 0; + + u32 no_one = 0; + u32 no_zero = 0; + u32 result = 0; + u32 count = 0; + int ret = 0; + + ret = hdcp_i2c_read(hdcp_info.client, HDCP_Bksv, bk_sv, BKSV_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bk_sv data from i2c bus\n"); + return false; + } + +#ifdef S5P_HDCP_AUTH_DEBUG + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("i2c read : Bksv[%d]: 0x%x\n", i, bk_sv[i]); + +#endif + + for (i = 0; i < BKSV_SIZE; i++) { + + for (j = 0; j < 8; j++) { + + result = bk_sv[i] & (0x1 << j); + + if (result == 0) + no_zero++; + else + no_one++; + } + } + + if ((no_zero == 20) && (no_one == 20)) { + + writel(bk_sv[0], hdmi_base + S5P_HDCP_BKSV_0_0); + writel(bk_sv[1], hdmi_base + S5P_HDCP_BKSV_0_1); + writel(bk_sv[2], hdmi_base + S5P_HDCP_BKSV_0_2); + writel(bk_sv[3], hdmi_base + S5P_HDCP_BKSV_0_3); + writel(bk_sv[4], hdmi_base + S5P_HDCP_BKSV_1); + +#ifdef S5P_HDCP_AUTH_DEBUG + + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("set reg : Bksv[%d]: 0x%x\n", i, bk_sv[i]); + +#endif + + HDCPPRINTK("Success: no_zero, and no_one is 20\n"); + + } else { + + HDCPPRINTK("Failed: no_zero or no_one is NOT 20\n"); + + + while (!read_again_bksv()) { + + count++; + + mdelay(20); + + if (count == 140) + return false; + } + } + + return true; +} + +/* + * Compare the R value of Tx with that of Rx + */ +static bool compare_r_val(void) +{ + int ret = 0; + u8 ri[2] = {0, 0}; + u8 rj[2] = {0, 0}; + u16 i; + + for (i = 0; i < R_VAL_RETRY_CNT; i++) { + /* Read R value from Tx */ + ri[0] = readl(hdmi_base + S5P_HDCP_Ri_0); + ri[1] = readl(hdmi_base + S5P_HDCP_Ri_1); + + /* Read R value from Rx */ + ret = hdcp_i2c_read(hdcp_info.client, HDCP_Ri, rj, 2); + + if (ret < 0) { + HDCPPRINTK("Can't read r data from i2c bus\n"); + return false; + } + +#ifdef S5P_HDCP_AUTH_DEBUG + AUTHPRINTK("retries :: %d\n", i); + + printk(KERN_INFO "\t\t\t Rx(ddc) ->"); + + printk(KERN_INFO "rj[0]: 0x%02x, rj[1]: 0x%02x\n", + rj[0], rj[1]); + + printk(KERN_INFO "\t\t\t Tx(register) ->"); + + printk(KERN_INFO "ri[0]: 0x%02x, ri[1]: 0x%02x\n", + ri[0], ri[1]); + +#endif + + /* Compare R value */ + if ((ri[0] == rj[0]) && (ri[1] == rj[1]) && (ri[0] | ri[1])) { + writel(Ri_MATCH_RESULT__YES, + hdmi_base + S5P_HDCP_CHECK_RESULT); + HDCPPRINTK("R0, R0' is matched!!\n"); + ret = true; + break; + } else { + writel(Ri_MATCH_RESULT__NO, + hdmi_base + S5P_HDCP_CHECK_RESULT); + HDCPPRINTK("R0, R0' is not matched!!\n"); + ret = false; + } + + } + + return ret ? true : false; +} + +static bool make_aes_key(void) +{ + u32 aes_reg_val; + + + aes_reg_val = readl(hdmi_base + S5P_HAES_CON); + aes_reg_val = SCRAMBLER_KEY_START_EN; + + /* Start generation of AES key */ + writel(aes_reg_val, hdmi_base + S5P_HAES_CON); + + do { + aes_reg_val = readl(hdmi_base + S5P_HAES_CON); + } while (!(aes_reg_val & SCRAMBLER_KEY_DONE)); + + return true; +} + +/* + * HAES function + */ +static void start_decrypting(const u8 *hdcp_key, u32 hdcp_key_size) +{ + u32 i = 0; + u32 aes_start = 0; + u32 aes_reg_val = 0; + + make_aes_key(); + + writel(hdcp_key_size, hdmi_base + S5P_HAES_DATA_SIZE_L); + + for (i = 0; i < hdcp_key_size; i++) + writel(hdcp_key[i], hdmi_base + S5P_HAES_DATA); + + + aes_reg_val = readl(hdmi_base + S5P_HAES_CON); + + aes_reg_val |= HAES_START_EN; + + writel(aes_reg_val, hdmi_base + S5P_HAES_CON); + + do { + aes_start = readl(hdmi_base + S5P_HAES_CON); + } while (aes_start & HAES_START_EN); +} + +/* + * Start encryption + */ +static void start_encryption(void) +{ + u32 hdcp_status; + + /* Ri == Ri' |Ready the compared result of Ri */ + writel(Ri_MATCH_RESULT__YES, hdmi_base + S5P_HDCP_CHECK_RESULT); + + do { + hdcp_status = readl(hdmi_base + S5P_STATUS); + /* Wait for STATUS[7] to '1'*/ + } while ((hdcp_status & AUTHENTICATED) != AUTHENTICATED); + + /* Start encryption */ + writel(HDCP_ENC_ENABLE, hdmi_base + S5P_ENC_EN); + +} + +/* + * Check whether Rx is repeater or not + */ +static int check_repeater(void) +{ + int ret = 0; + + u8 i = 0; + u16 j = 0; + + u8 bcaps[BCAPS_SIZE] = {0}; + u8 status[BSTATUS_SIZE] = {0, 0}; + u8 rx_v[SHA_1_HASH_SIZE]; + u8 ksv_list[HDCP_MAX_DEVS*HDCP_KSV_SIZE]; + + u32 hdcp_ctrl; + u32 dev_cnt; + u32 stat; + + bool ksv_fifo_ready = false; + + while (j <= 500) { + ret = hdcp_i2c_read(hdcp_info.client, HDCP_Bcaps, + bcaps, BCAPS_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bcaps data from i2c bus\n"); + return false; + } + + if (bcaps[0] & KSV_FIFO_READY) { + HDCPPRINTK("ksv fifo is ready\n"); + ksv_fifo_ready = true; + writel(bcaps[0], hdmi_base + S5P_HDCP_BCAPS); + break; + } else { + HDCPPRINTK("ksv fifo is not ready\n"); + ksv_fifo_ready = false; + mdelay(10); + j++; + } + + } + + if (j == 500) { + HDCPPRINTK("ksv fifo check timeout occurred!!\n"); + return false; + } + + if (ksv_fifo_ready) { + hdcp_ctrl = readl(hdmi_base + S5P_HDCP_CTRL); + hdcp_ctrl &= CLEAR_REPEATER_TIMEOUT; + writel(hdcp_ctrl, hdmi_base + S5P_HDCP_CTRL); + } else + return false; + + /* + * Check MAX_CASCADE_EXCEEDED + * or MAX_DEVS_EXCEEDED indicator + */ + ret = hdcp_i2c_read(hdcp_info.client, HDCP_BStatus, + status, BSTATUS_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read status data from i2c bus\n"); + return false; + } + + /* MAX_CASCADE_EXCEEDED || MAX_DEVS_EXCEEDED */ + if (status[1] & MAX_CASCADE_EXCEEDED) { + HDCPPRINTK("MAX_CASCADE_EXCEEDED\n"); + return MAX_CASCADE_EXCEEDED_ERROR; + } else if (status[0] & MAX_DEVS_EXCEEDED) { + HDCPPRINTK("MAX_CASCADE_EXCEEDED\n"); + return MAX_DEVS_EXCEEDED_ERROR; + } + + + writel(status[0], hdmi_base + S5P_HDCP_BSTATUS_0); + + writel(status[1], hdmi_base + S5P_HDCP_BSTATUS_1); + + /* Read KSV list */ + dev_cnt = (*status) & 0x7f; + + HDCPPRINTK("status[0] :0x%08x, status[1] :0x%08x!!\n", + status[0], status[1]); + + if (dev_cnt) { + + u32 val; + + /* read ksv */ + ret = hdcp_i2c_read(hdcp_info.client, HDCP_KSVFIFO, ksv_list, + dev_cnt * HDCP_KSV_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read ksv fifo!!\n"); + return false; + } + + /* write ksv */ + for (i = 0; i < dev_cnt; i++) { + + writel(ksv_list[(i*5) + 0], + hdmi_base + S5P_HDCP_RX_KSV_0_0); + writel(ksv_list[(i*5) + 1], + hdmi_base + S5P_HDCP_RX_KSV_0_1); + writel(ksv_list[(i*5) + 2], + hdmi_base + S5P_HDCP_RX_KSV_0_2); + writel(ksv_list[(i*5) + 3], + hdmi_base + S5P_HDCP_RX_KSV_0_3); + writel(ksv_list[(i*5) + 4], + hdmi_base + S5P_HDCP_RX_KSV_0_4); + + if (i != (dev_cnt - 1)) { /* if it's not end */ + /* it's not in manual */ + writel(SET_HDCP_KSV_WRITE_DONE, + S5P_HDCP_RX_KSV_LIST_CTRL); + + mdelay(20); + + /* check ksv readed */ + + do { + if (!hdcp_info.hdcp_enable) + return false; + + stat = readl(hdmi_base + + S5P_HDCP_RX_KSV_LIST_CTRL); + + } while (!(stat & SET_HDCP_KSV_READ)); + + + HDCPPRINTK("read complete\n"); + + } + + HDCPPRINTK("HDCP_RX_KSV_1 = 0x%x\n\r", + readl(hdmi_base + + S5P_HDCP_RX_KSV_LIST_CTRL)); + HDCPPRINTK("i : %d, dev_cnt : %d, val = 0x%08x\n", + i, dev_cnt, val); + } + + /* end of ksv */ + val = readl(hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL); + + val |= SET_HDCP_KSV_END | SET_HDCP_KSV_WRITE_DONE; + + writel(val, hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL); + + HDCPPRINTK("HDCP_RX_KSV_1 = 0x%x\n\r", + readl(hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL)); + + HDCPPRINTK("i : %d, dev_cnt : %d, val = 0x%08x\n", + i, dev_cnt, val); + + } else { + + writel(SET_HDCP_KSV_LIST_EMPTY, + hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL); + } + + + /* Read SHA-1 from receiver */ + ret = hdcp_i2c_read(hdcp_info.client, HDCP_SHA1, + rx_v, SHA_1_HASH_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read sha_1_hash data from i2c bus\n"); + return false; + } + + for (i = 0; i < SHA_1_HASH_SIZE; i++) + HDCPPRINTK("SHA_1 rx :: %x\n", rx_v[i]); + + + /* write SHA-1 to register */ + writel(rx_v[0], hdmi_base + S5P_HDCP_RX_SHA1_0_0); + + writel(rx_v[1], hdmi_base + S5P_HDCP_RX_SHA1_0_1); + + writel(rx_v[2], hdmi_base + S5P_HDCP_RX_SHA1_0_2); + + writel(rx_v[3], hdmi_base + S5P_HDCP_RX_SHA1_0_3); + + writel(rx_v[4], hdmi_base + S5P_HDCP_RX_SHA1_1_0); + + writel(rx_v[5], hdmi_base + S5P_HDCP_RX_SHA1_1_1); + + writel(rx_v[6], hdmi_base + S5P_HDCP_RX_SHA1_1_2); + + writel(rx_v[7], hdmi_base + S5P_HDCP_RX_SHA1_1_3); + + writel(rx_v[8], hdmi_base + S5P_HDCP_RX_SHA1_2_0); + + writel(rx_v[9], hdmi_base + S5P_HDCP_RX_SHA1_2_1); + + writel(rx_v[10], hdmi_base + S5P_HDCP_RX_SHA1_2_2); + + writel(rx_v[11], hdmi_base + S5P_HDCP_RX_SHA1_2_3); + + writel(rx_v[12], hdmi_base + S5P_HDCP_RX_SHA1_3_0); + + writel(rx_v[13], hdmi_base + S5P_HDCP_RX_SHA1_3_1); + + writel(rx_v[14], hdmi_base + S5P_HDCP_RX_SHA1_3_2); + + writel(rx_v[15], hdmi_base + S5P_HDCP_RX_SHA1_3_3); + + writel(rx_v[16], hdmi_base + S5P_HDCP_RX_SHA1_4_0); + + writel(rx_v[17], hdmi_base + S5P_HDCP_RX_SHA1_4_1); + + writel(rx_v[18], hdmi_base + S5P_HDCP_RX_SHA1_4_2); + + writel(rx_v[19], hdmi_base + S5P_HDCP_RX_SHA1_4_3); + + /* SHA write done, and wait for SHA computation being done */ + mdelay(1); + + /* check authentication success or not */ + stat = readl(hdmi_base + S5P_HDCP_AUTH_STATUS); + + HDCPPRINTK("auth status %d\n", stat); + + if (stat & SET_HDCP_SHA_VALID_READY) { + + HDCPPRINTK("SHA valid ready 0x%x \n\r", stat); + + stat = readl(hdmi_base + S5P_HDCP_AUTH_STATUS); + + if (stat & SET_HDCP_SHA_VALID) { + + HDCPPRINTK("SHA valid 0x%x \n\r", stat); + + ret = true; + } else { + HDCPPRINTK("SHA valid ready, but not valid 0x%x \n\r", + stat); + ret = false; + } + + } else { + + HDCPPRINTK("SHA not ready 0x%x \n\r", stat); + ret = false; + } + + + /* clear all validate bit */ + writel(0x0, hdmi_base + S5P_HDCP_AUTH_STATUS); + + return ret; + +} + +/* + * Check whether the HDCP event occurred or not + */ +/* +static bool __s5p_is_occurred_hdcp_event(void) +{ + u32 status_val; + + status_val = readl(hdmi_base + S5P_STATUS); + + return (((status_val == (0x1 << 0) || status_val == (0x1 << 1) || + status_val == (0x1 << 2) || status_val == (0x1 << 3) || + status_val == (0x1 << 4))) ? true : false); +} +*/ + +static bool try_read_receiver(void) +{ + u8 i = 0; + bool ret = false; + + for (i = 0; i < 40; i++) { + + mdelay(250); + + if (hdcp_info.auth_status != RECEIVER_READ_READY) { + + HDCPPRINTK("hdcp stat. changed!!" + "failed attempt no = %d\n\r", i); + + return false; + } + + ret = read_bcaps(); + + if (ret) { + + HDCPPRINTK("succeeded at attempt no= %d \n\r", i); + + return true; + + } else + HDCPPRINTK("can't read bcaps!!" + "failed attempt no=%d\n\r", i); + } + + return false; +} + + +/* + * stop - stop functions are only called under running HDCP + */ +bool __s5p_stop_hdcp(void) +{ + u32 sfr_val; + + HDCPPRINTK("HDCP ftn. Stop!!\n"); + + hdcp_protocol_status = 0; + + hdcp_info.time_out = INFINITE; + hdcp_info.event = HDCP_EVENT_STOP; + hdcp_info.auth_status = NOT_AUTHENTICATED; + hdcp_info.hdcp_enable = false; + + + + /* 3. disable hdcp control reg. */ + sfr_val = readl(hdmi_base + S5P_HDCP_CTRL); + sfr_val &= (ENABLE_1_DOT_1_FEATURE_DIS + & CLEAR_REPEATER_TIMEOUT + & EN_PJ_DIS + & CP_DESIRED_DIS); + writel(sfr_val, hdmi_base + S5P_HDCP_CTRL); + + /* 2. disable aes_data_size & haes_con reg. */ + sfr_val = readl(hdmi_base + S5P_HAES_CON); + sfr_val &= SCRAMBLER_KEY_START_DIS; + writel(sfr_val, hdmi_base + S5P_HAES_CON); + + /* 1-3. disable hdmi hpd reg. */ + writel(CABLE_UNPLUGGED, hdmi_base + S5P_HPD); + + /* 1-2. disable hdmi status enable reg. */ + sfr_val = readl(hdmi_base + S5P_STATUS_EN); + sfr_val &= HDCP_STATUS_DIS_ALL; + writel(sfr_val, hdmi_base + S5P_STATUS_EN); + + /* 1-1. clear all status pending */ + sfr_val = readl(hdmi_base + S5P_STATUS); + sfr_val |= HDCP_STATUS_EN_ALL; + writel(sfr_val, hdmi_base + S5P_STATUS); + + /* disable encryption */ + writel(HDCP_ENC_DISABLE, hdmi_base + S5P_ENC_EN); + + /* clear result */ + writel(Ri_MATCH_RESULT__NO, hdmi_base + S5P_HDCP_CHECK_RESULT); + writel(readl(hdmi_base + S5P_HDMI_CON_0) & HDMI_DIS, + hdmi_base + S5P_HDMI_CON_0); + writel(readl(hdmi_base + S5P_HDMI_CON_0) | HDMI_EN, + hdmi_base + S5P_HDMI_CON_0); + writel(CLEAR_ALL_RESULTS, hdmi_base + S5P_HDCP_CHECK_RESULT); + + /* hdmi disable */ + /* + sfr_val = readl(hdmi_base + S5P_HDMI_CON_0); + sfr_val &= ~(PWDN_ENB_NORMAL | HDMI_EN | ASP_EN); + writel( sfr_val, hdmi_base + S5P_HDMI_CON_0); + */ + HDCPPRINTK("\tSTATUS \t0x%08x\n", readl(hdmi_base + S5P_STATUS)); + HDCPPRINTK("\tSTATUS_EN \t0x%08x\n", readl(hdmi_base + S5P_STATUS_EN)); + HDCPPRINTK("\tHPD \t0x%08x\n", readl(hdmi_base + S5P_HPD)); + HDCPPRINTK("\tHDCP_CTRL \t0x%08x\n", readl(hdmi_base + S5P_HDCP_CTRL)); + HDCPPRINTK("\tMODE_SEL \t0x%08x\n", readl(hdmi_base + S5P_MODE_SEL)); + HDCPPRINTK("\tENC_EN \t0x%08x\n", readl(hdmi_base + S5P_ENC_EN)); + HDCPPRINTK("\tHDMI_CON_0 \t0x%08x\n", + readl(hdmi_base + S5P_HDMI_CON_0)); + + return true; +} + + +void __s5p_hdcp_reset(void) +{ + + __s5p_stop_hdcp(); + + hdcp_protocol_status = 2; + + HDCPPRINTK("HDCP ftn. reset!!\n"); + +} + +/* + * start - start functions are only called under stopping HDCP + */ +bool __s5p_start_hdcp(void) +{ + u32 sfr_val; + + hdcp_info.event = HDCP_EVENT_STOP; + hdcp_info.time_out = INFINITE; + hdcp_info.auth_status = NOT_AUTHENTICATED; + + HDCPPRINTK("HDCP ftn. Start!!\n"); + + hdcp_protocol_status = 1; + + if (!read_bcaps()) { + HDCPPRINTK("can't read ddc port!\n"); + __s5p_hdcp_reset(); + } + + /* for av mute */ + writel(DO_NOT_TRANSMIT, hdmi_base + S5P_GCP_CON); + + /* + * 1-1. set hdmi status enable reg. + * Update_Ri_int_en should be enabled after + * s/w gets ExchangeKSV_int. + */ + writel(HDCP_STATUS_EN_ALL, hdmi_base + S5P_STATUS_EN); + + /* 1-2. set hdmi hpd reg. */ + writel(CABLE_PLUGGED, hdmi_base + S5P_HPD); + + /* + * 1-3. set hdmi offset & cycle_aa reg. + * HDCP memory read cycle count(0x4 is recommanded) + */ + writel(0x00, hdmi_base + S5P_HDCP_OFFSET_TX_0); + + writel(0xA0, hdmi_base + S5P_HDCP_OFFSET_TX_1); + + writel(0x00, hdmi_base + S5P_HDCP_OFFSET_TX_2); + + writel(0x00, hdmi_base + S5P_HDCP_OFFSET_TX_3); + + writel(0x04, hdmi_base + S5P_HDCP_CYCLE_AA); + + /* 2. set aes_data_size & haes_con reg. */ + start_decrypting(hdcp_key, 288); + + /* + * 3. set hdcp control reg. + * Disable advance cipher option, Enable CP(Content Protection), + * Disable time-out (This bit is only available in a REPEATER) + * Disable XOR shift,Disable Pj port update,Use external key + */ + sfr_val = 0; + + sfr_val |= CP_DESIRED_EN; + + writel(sfr_val, hdmi_base + S5P_HDCP_CTRL); + + hdcp_info.hdcp_enable = true; + + HDCPPRINTK("\tSTATUS \t0x%08x\n", readl(hdmi_base + S5P_STATUS)); + + HDCPPRINTK("\tSTATUS_EN \t0x%08x\n", readl(hdmi_base + S5P_STATUS_EN)); + + HDCPPRINTK("\tHPD \t0x%08x\n", readl(hdmi_base + S5P_HPD)); + + HDCPPRINTK("\tHDCP_CTRL \t0x%08x\n", readl(hdmi_base + S5P_HDCP_CTRL)); + + HDCPPRINTK("\tMODE_SEL \t0x%08x\n", readl(hdmi_base + S5P_MODE_SEL)); + + HDCPPRINTK("\tENC_EN \t0x%08x\n", readl(hdmi_base + S5P_ENC_EN)); + + HDCPPRINTK("\tHDMI_CON_0 \t0x%08x\n", + readl(hdmi_base + S5P_HDMI_CON_0)); + + + return true; +} + + +static void bksv_start_bh(void) +{ + bool ret = false; + + HDCPPRINTK("HDCP_EVENT_READ_BKSV_START bh\n"); + + hdcp_info.auth_status = RECEIVER_READ_READY; + + ret = read_bcaps(); + + if (!ret) { + + ret = try_read_receiver(); + + if (!ret) { + HDCPPRINTK("Can't read bcaps!! retry failed!!\n" + "\t\t\t\thdcp ftn. will be stopped\n"); + + __s5p_stop_hdcp(); + return; + } + } + + hdcp_info.auth_status = BCAPS_READ_DONE; + + ret = read_bksv(); + + if (!ret) { + HDCPPRINTK("Can't read bksv!!" + "hdcp ftn. will be reset\n"); + + __s5p_stop_hdcp(); + return; + } + + hdcp_info.auth_status = BKSV_READ_DONE; + + HDCPPRINTK("authentication status : bksv is done (0x%08x)\n", + hdcp_info.auth_status); +} + +static void second_auth_start_bh(void) +{ + u8 count = 0; + bool ret = false; + + int ret_err; + + u32 bcaps; + + HDCPPRINTK("HDCP_EVENT_SECOND_AUTH_START bh\n"); + + ret = read_bcaps(); + + if (!ret) { + + ret = try_read_receiver(); + + if (!ret) { + + HDCPPRINTK("Can't read bcaps!! retry failed!!\n" + "\t\t\t\thdcp ftn. will be stopped\n"); + + __s5p_stop_hdcp(); + return; + } + + } + + bcaps = readl(hdmi_base + S5P_HDCP_BCAPS); + + bcaps &= (KSV_FIFO_READY); + + if (!bcaps) { + + HDCPPRINTK("ksv fifo is not ready\n"); + + do { + count++; + + ret = read_bcaps(); + + if (!ret) { + + ret = try_read_receiver(); + + if (!ret) + __s5p_stop_hdcp(); + + return; + + } + + bcaps = readl(hdmi_base + S5P_HDCP_BCAPS); + + bcaps &= (KSV_FIFO_READY); + + if (bcaps) { + HDCPPRINTK("bcaps retries : %d\n", count); + break; + } + + mdelay(100); + + if (!hdcp_info.hdcp_enable) { + + __s5p_stop_hdcp(); + + return; + + } + + } while (count <= 50); + + /* wait times exceeded 5 seconds */ + if (count > 50) { + + hdcp_info.time_out = INFINITE; + + /* + * time-out (This bit is only available in a REPEATER) + */ + writel(readl(hdmi_base + S5P_HDCP_CTRL) | 0x1 << 2, + hdmi_base + S5P_HDCP_CTRL); + + __s5p_hdcp_reset(); + + return; + } + } + + HDCPPRINTK("ksv fifo ready\n"); + + ret_err = check_repeater(); + + if (ret_err == true) { + u32 flag; + + hdcp_info.auth_status = SECOND_AUTHENTICATION_DONE; + HDCPPRINTK("second authentication done!!\n"); + + flag = readb(hdmi_base + S5P_STATUS); + HDCPPRINTK("hdcp state : %s authenticated!!\n", + flag & AUTHENTICATED ? "" : "not not"); + + + start_encryption(); + } else if (ret_err == false) { + /* i2c error */ + HDCPPRINTK("repeater check error!!\n"); + __s5p_hdcp_reset(); + } else { + if (ret_err == REPEATER_ILLEGAL_DEVICE_ERROR) { + /* + * No need to start the HDCP + * in case of invalid KSV (revocation case) + */ + HDCPPRINTK("illegal dev. error!!\n"); + + __s5p_stop_hdcp(); + } else { + /* + * MAX_CASCADE_EXCEEDED_ERROR + * MAX_DEVS_EXCEEDED_ERROR + */ + HDCPPRINTK("repeater check error(MAX_EXCEEDED)!!\n"); + __s5p_hdcp_reset(); + } + } +} + +static bool write_aksv_start_bh(void) +{ + bool ret = false; + + HDCPPRINTK("HDCP_EVENT_WRITE_AKSV_START bh\n"); + + if (hdcp_info.auth_status != BKSV_READ_DONE) { + HDCPPRINTK("bksv is not ready!!\n"); + return false; + } + + ret = write_ainfo(); + + if (!ret) + return false; + + HDCPPRINTK("ainfo write done!!\n"); + + ret = write_an(); + + if (!ret) + return false; + + hdcp_info.auth_status = AN_WRITE_DONE; + + HDCPPRINTK("an write done!!\n"); + + ret = write_aksv(); + + if (!ret) + return false; + + /* + * Wait for 100ms. Transmitter must not read + * Ro' value sooner than 100ms after writing + * Aksv + */ + mdelay(100); + + hdcp_info.auth_status = AKSV_WRITE_DONE; + + HDCPPRINTK("aksv write done!!\n"); + + return ret; +} + +static bool check_ri_start_bh(void) +{ + bool ret = false; + + + HDCPPRINTK("HDCP_EVENT_CHECK_RI_START bh\n"); + + if (hdcp_info.auth_status == AKSV_WRITE_DONE || + hdcp_info.auth_status == FIRST_AUTHENTICATION_DONE || + hdcp_info.auth_status == SECOND_AUTHENTICATION_DONE) { + + ret = compare_r_val(); + + if (ret) { + + if (hdcp_info.auth_status == AKSV_WRITE_DONE) { + /* + * Check whether HDMI receiver is + * repeater or not + */ + if (hdcp_info.is_repeater) + hdcp_info.auth_status + = SECOND_AUTHENTICATION_RDY; + else { + hdcp_info.auth_status + = FIRST_AUTHENTICATION_DONE; + start_encryption(); + } + } + + } else { + + HDCPPRINTK("authentication reset\n"); + + __s5p_hdcp_reset(); + } + + HDCPPRINTK("auth_status = 0x%08x\n", + + hdcp_info.auth_status); + + + return true; + } + + HDCPPRINTK("aksv_write or first/second" + + " authentication is not done\n"); + + return false; +} + +/* + * bottom half for hdmi interrupt + * + */ +static void hdcp_work(void *arg) +{ + + /* + * I2C int. was occurred + * for reading Bksv and Bcaps + */ + + if (hdcp_info.event & (1 << HDCP_EVENT_READ_BKSV_START)) { + + bksv_start_bh(); + + /* clear event */ + hdcp_info.event &= ~(1 << HDCP_EVENT_READ_BKSV_START); + } + + /* + * Watchdog timer int. was occurred + * for checking repeater + */ + if (hdcp_info.event & (1 << HDCP_EVENT_SECOND_AUTH_START)) { + + second_auth_start_bh(); + + /* clear event */ + hdcp_info.event &= ~(1 << HDCP_EVENT_SECOND_AUTH_START); + } + + /* + * An_Write int. was occurred + * for writing Ainfo, An and Aksv + */ + if (hdcp_info.event & (1 << HDCP_EVENT_WRITE_AKSV_START)) { + + write_aksv_start_bh(); + + /* clear event */ + hdcp_info.event &= ~(1 << HDCP_EVENT_WRITE_AKSV_START); + } + + /* + * Ri int. was occurred + * for comparing Ri and Ri'(from HDMI sink) + */ + if (hdcp_info.event & (1 << HDCP_EVENT_CHECK_RI_START)) { + + + check_ri_start_bh(); + + /* clear event */ + hdcp_info.event &= ~(1 << HDCP_EVENT_CHECK_RI_START); + } + +} + +void __s5p_init_hdcp(bool hpd_status, struct i2c_client *ddc_port) +{ + + HDCPPRINTK("HDCP ftn. Init!!\n"); + + hdcp_info.client = ddc_port; + + /* for bh */ + INIT_WORK(&hdcp_info.work, (work_func_t)hdcp_work); + + init_waitqueue_head(&hdcp_info.waitq); + + /* for dev_dbg err. */ + spin_lock_init(&hdcp_info.lock); + +} + +/* + * HDCP ISR. + * If HDCP IRQ occurs, set hdcp_event and wake up the waitqueue. + */ +irqreturn_t __s5p_hdmi_irq(int irq, void *dev_id) +{ + u8 flag; + u32 event; + + event = 0; + + /* check HDCP Status */ + flag = readb(hdmi_base + S5P_STATUS); + HDCPPRINTK("irq_status : 0x%08x\n", readb(hdmi_base + S5P_STATUS)); + + HDCPPRINTK("hdcp state : %s authenticated!!\n", + flag & AUTHENTICATED ? "" : "not not"); + + spin_lock_irq(&hdcp_info.lock); + + /* + * processing interrupt + * interrupt processing seq. is firstly set event for workqueue, + * and interrupt pending clear. 'flag|' was used for preventing + * to clear AUTHEN_ACK.- it caused many problem. be careful. + */ + /* I2C INT */ + + if (flag & WTFORACTIVERX_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_READ_BKSV_START); + writeb(flag | WTFORACTIVERX_INT_OCCURRED, + hdmi_base + S5P_STATUS); + } + + /* AN INT */ + if (flag & EXCHANGEKSV_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_WRITE_AKSV_START); + writeb(flag | EXCHANGEKSV_INT_OCCURRED, + hdmi_base + S5P_STATUS); + } + + /* RI INT */ + if (flag & UPDATE_RI_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_CHECK_RI_START); + writeb(flag | UPDATE_RI_INT_OCCURRED, + hdmi_base + S5P_STATUS); + } + + /* WATCHDOG INT */ + if (flag & WATCHDOG_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_SECOND_AUTH_START); + writeb(flag | WATCHDOG_INT_OCCURRED, + hdmi_base + S5P_STATUS); + } + + if (!event) { + HDCPPRINTK("unknown irq.\n"); + return IRQ_HANDLED; + } + + hdcp_info.event |= event; + + schedule_work(&hdcp_info.work); + + spin_unlock_irq(&hdcp_info.lock); + + return IRQ_HANDLED; +} + +bool __s5p_set_hpd_detection(bool detection, bool hdcp_enabled, + struct i2c_client *client) +{ + u32 hpd_reg_val = 0; + + /* hdcp_enabled is status of tvout_sys */ + /* + if (hdcp_enabled) { + if (detection) { + hdcp_info.client = client; + __s5p_start_hdcp(); + } else { + hdcp_info.client = NULL; + __s5p_stop_hdcp(); + } + } else { + */ + + if (detection) + hpd_reg_val = CABLE_PLUGGED; + else + hpd_reg_val = CABLE_UNPLUGGED; + + + writel(hpd_reg_val, hdmi_base + S5P_HPD); + + HDCPPRINTK("HPD status :: 0x%08x\n\r", + readl(hdmi_base + S5P_HPD)); + + return true; +} diff --git a/drivers/media/video/samsung/tv20/s5pc100/hdmi_s5pc100.c b/drivers/media/video/samsung/tv20/s5pc100/hdmi_s5pc100.c new file mode 100644 index 0000000..8b41b8b --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/hdmi_s5pc100.c @@ -0,0 +1,1435 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/hdmi_s5pc100.c + * + * hdmi raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include "tv_out_s5pc100.h" + +#include "regs/regs-hdmi.h" + +#include "plat/regs-clock.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_HDMI_DEBUG 1 +#endif + +#ifdef S5P_HDMI_DEBUG +#define HDMIPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[HDMI] %s: " fmt, __func__ , ## args) +#else +#define HDMIPRINTK(fmt, args...) +#endif + +static struct resource *hdmi_mem; +void __iomem *hdmi_base; + +static unsigned short g_hdmi_video_parm_tbl[] = { + /* 480P_60, 576P_50, 720P_60, 720P_50, 1080I_60, 1080I_50, VGAP_60*/ + 138, 144, 370, 700, 280, 720, 160, + 525, 625, 750, 750, 562, 562, 525, + 45, 49, 30, 30, 22, 22, 45, + 525, 625, 750, 750, 1125, 1125, 525, + 858, 864, 1650, 1980, 2200, 2640, 800, + 1, 1, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 585, 585, 0, + 0, 0, 0, 0, 1125, 1125, 0, + 14, 10, 108, 438, 86, 526, 14, + 76, 74, 148, 478, 130, 570, 110, + 1, 1, 0, 0, 0, 0, 1, + 15, 10, 10, 10, 7, 7, 12, + 9, 5, 5, 5, 2, 2, 10, + 0, 0, 0, 0, 569, 569, 0, + 0, 0, 0, 0, 564, 564, 0, + 0, 0, 0, 0, 1187, 1847, 0, + 0, 0, 0, 0, 1187, 1847, 0, + 858, 864, 1650, 1980, 2200, 2640, 800 + 138, 144, 370, 700, 280, 720, 160, + 720, 720, 1280, 1280, 1920, 1920, 640, + 525, 625, 750, 750, 1125, 1125, 525, + 7, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 563, 563, 0, + 45, 49, 30, 30, 22, 22, 45, + 480, 576, 720, 720, 540, 540, 480, + 0, 0, 0, 0, 563, 563, 0, + 0, 0, 0, 0, 584, 584, 0, + 7, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 563, 563, 1, + 7, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 563, 563, 1 +}; + + + +/* +* set - set functions are only called under running HDMI +*/ +void __s5p_hdmi_set_hpd_onoff(bool on_off) +{ + HDMIPRINTK("%d\n\r", on_off); + + if (on_off) + writel(SW_HPD_PLUGGED, hdmi_base + S5P_HPD); + else + writel(SW_HPD_UNPLUGGED, hdmi_base + S5P_HPD); + + + HDMIPRINTK("0x%08x\n\r", readl(hdmi_base + S5P_HPD)); +} + + +void __s5p_hdmi_audio_set_config(enum s5p_tv_audio_codec_type audio_codec) +{ + + u32 data_type = (audio_codec == PCM) ? CONFIG_LINEAR_PCM_TYPE : + (audio_codec == AC3) ? CONFIG_NON_LINEAR_PCM_TYPE : + 0xff; + + HDMIPRINTK("(%d)\n\r", audio_codec); + + writel(CONFIG_FILTER_2_SAMPLE | data_type + | CONFIG_PCPD_MANUAL_SET | CONFIG_WORD_LENGTH_MANUAL_SET + | CONFIG_U_V_C_P_REPORT | CONFIG_BURST_SIZE_2 + | CONFIG_DATA_ALIGN_32BIT + , hdmi_base + S5P_SPDIFIN_CONFIG_1); + writel(0, hdmi_base + S5P_SPDIFIN_CONFIG_2); + HDMIPRINTK("()\n\r"); +} + +void __s5p_hdmi_audio_set_acr(u32 sample_rate) +{ + u32 value_n = (sample_rate == 32000) ? 4096 : + (sample_rate == 44100) ? 6272 : + (sample_rate == 88200) ? 12544 : + (sample_rate == 176400) ? 25088 : + (sample_rate == 48000) ? 6144 : + (sample_rate == 96000) ? 12288 : + (sample_rate == 192000) ? 24576 : 0; + + u32 cts = (sample_rate == 32000) ? 27000 : + (sample_rate == 44100) ? 30000 : + (sample_rate == 88200) ? 30000 : + (sample_rate == 176400) ? 30000 : + (sample_rate == 48000) ? 27000 : + (sample_rate == 96000) ? 27000 : + (sample_rate == 192000) ? 27000 : 0; + + HDMIPRINTK("(%d)\n\r", sample_rate); + + writel(value_n & 0xff, hdmi_base + S5P_ACR_N0); + writel((value_n >> 8) & 0xff, hdmi_base + S5P_ACR_N1); + writel((value_n >> 16) & 0xff, hdmi_base + S5P_ACR_N2); + + writel(cts & 0xff, hdmi_base + S5P_ACR_MCTS0); + writel((cts >> 8) & 0xff, hdmi_base + S5P_ACR_MCTS1); + writel((cts >> 16) & 0xff, hdmi_base + S5P_ACR_MCTS2); + + writel(cts & 0xff, hdmi_base + S5P_ACR_CTS0); + writel((cts >> 8) & 0xff, hdmi_base + S5P_ACR_CTS1); + writel((cts >> 16) & 0xff, hdmi_base + S5P_ACR_CTS2); + + writel(4, hdmi_base + S5P_ACR_CON); + + HDMIPRINTK("()\n\r"); +} + +void __s5p_hdmi_audio_set_asp(void) +{ + HDMIPRINTK("()\n\r"); + writel(0x0, hdmi_base + S5P_ASP_CON); + writel(0x0, hdmi_base + S5P_ASP_SP_FLAT); + + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG0); + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG1); + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG2); + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG3); + HDMIPRINTK("()\n\r"); +} + +void __s5p_hdmi_audio_clock_enable(void) +{ + HDMIPRINTK("()\n\r"); + writel(0x1, hdmi_base + S5P_SPDIFIN_CLK_CTRL); + writel(0x3, hdmi_base + S5P_SPDIFIN_OP_CTRL); + HDMIPRINTK("()\n\r"); +} + +void __s5p_hdmi_audio_set_repetition_time( + enum s5p_tv_audio_codec_type audio_codec, + u32 bits, u32 frame_size_code) +{ + u32 wl = 5 << 1 | 1; + u32 rpt_cnt = (audio_codec == AC3) ? 1536 * 2 - 1 : 0; + + HDMIPRINTK("()\n\r"); + + writel(((rpt_cnt&0xf) << 4) | wl, + hdmi_base + S5P_SPDIFIN_USER_VALUE_1); + writel((rpt_cnt >> 4)&0xff, hdmi_base + S5P_SPDIFIN_USER_VALUE_2); + writel(frame_size_code&0xff, hdmi_base + S5P_SPDIFIN_USER_VALUE_3); + writel((frame_size_code >> 8)&0xff, + hdmi_base + S5P_SPDIFIN_USER_VALUE_4); + HDMIPRINTK("()\n\r"); +} + + + +void __s5p_hdmi_audio_irq_enable(u32 irq_en) +{ + writel(irq_en, hdmi_base + S5P_SPDIFIN_IRQ_MASK); +} + + +void __s5p_hdmi_audio_set_aui(enum s5p_tv_audio_codec_type audio_codec, + u32 sample_rate, + u32 bits) +{ + u8 sum_of_bits, bytes1, bytes2, bytes3, check_sum; + u32 bit_rate; + u32 bps = (audio_codec == PCM) ? bits : 16; + + u32 type = (audio_codec == PCM) ? 1 : + (audio_codec == AC3) ? 2 : 0; + u32 ch = (audio_codec == PCM) ? 1 : 0; + + u32 sample = (sample_rate == 32000) ? 1 : + (sample_rate == 44100) ? 2 : + (sample_rate == 48000) ? 3 : + (sample_rate == 88200) ? 4 : + (sample_rate == 96000) ? 5 : + (sample_rate == 176400) ? 6 : + (sample_rate == 192000) ? 7 : 0; + + u32 bpsType = (bps == 16) ? 1 : + (bps == 20) ? 2 : + (bps == 24) ? 3 : 0; + + HDMIPRINTK("()\n\r"); + + bpsType = (audio_codec == PCM) ? bpsType : 0; + + sum_of_bits = (0x84 + 0x1 + 10); + + bytes1 = (u8)((type << 4) | ch); + + bytes2 = (u8)((sample << 2) | bpsType); + + bit_rate = 256; + + bytes3 = (audio_codec == PCM) ? (u8)0 : (u8)(bit_rate / 8) ; + + + sum_of_bits += (bytes1 + bytes2 + bytes3); + check_sum = 256 - sum_of_bits; + + writel(check_sum , hdmi_base + S5P_AUI_CHECK_SUM); + writel(bytes1 , hdmi_base + S5P_AUI_BYTE1); + writel(bytes2 , hdmi_base + S5P_AUI_BYTE2); + writel(bytes3 , hdmi_base + S5P_AUI_BYTE3); + writel(0x00 , hdmi_base + S5P_AUI_BYTE4); + writel(0x00 , hdmi_base + S5P_AUI_BYTE5); + + + writel(2 , hdmi_base + S5P_ACP_CON); + writel(1 , hdmi_base + S5P_ACP_TYPE); + + writel(0x10 , hdmi_base + S5P_GCP_BYTE1); + writel(0x2 , hdmi_base + S5P_GCP_CON); + + HDMIPRINTK("()\n\r"); + +} + +void __s5p_hdmi_video_set_bluescreen(bool en, + u8 cb_b, + u8 y_g, + u8 cr_r) +{ + HDMIPRINTK("%d,%d,%d,%d\n\r", en, cb_b, y_g, cr_r); + + if (en) { + writel(SET_BLUESCREEN_0(cb_b), hdmi_base + S5P_BLUE_SCREEN_0); + writel(SET_BLUESCREEN_1(y_g), hdmi_base + S5P_BLUE_SCREEN_1); + writel(SET_BLUESCREEN_2(cr_r), hdmi_base + S5P_BLUE_SCREEN_2); + writel(readl(hdmi_base + S5P_HDMI_CON_0) | BLUE_SCR_EN, + hdmi_base + S5P_HDMI_CON_0); + + HDMIPRINTK("HDMI_BLUE_SCREEN0 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_0)); + HDMIPRINTK("HDMI_BLUE_SCREEN1 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_1)); + HDMIPRINTK("HDMI_BLUE_SCREEN2 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_2)); + } else { + writel(readl(hdmi_base + S5P_HDMI_CON_0)&~BLUE_SCR_EN, + hdmi_base + S5P_HDMI_CON_0); + } + + HDMIPRINTK("HDMI_CON0 = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CON_0)); +} + + +/* +* initialization - iniization functions are only called under stopping HDMI +*/ +enum s5p_tv_hdmi_err __s5p_hdmi_init_spd_infoframe( + enum s5p_hdmi_transmit trans_type, + u8 *spd_header, + u8 *spd_data) +{ + HDMIPRINTK("%d,%d,%d\n\r", (u32)trans_type, + (u32)spd_header, + (u32)spd_data); + + switch (trans_type) { + + case HDMI_DO_NOT_TANS: + writel(SPD_TX_CON_NO_TRANS, hdmi_base + S5P_SPD_CON); + break; + + case HDMI_TRANS_ONCE: + writel(SPD_TX_CON_TRANS_ONCE, hdmi_base + S5P_SPD_CON); + break; + + case HDMI_TRANS_EVERY_SYNC: + writel(SPD_TX_CON_TRANS_EVERY_VSYNC, hdmi_base + S5P_SPD_CON); + break; + + default: + HDMIPRINTK(" invalid out_mode parameter(%d)\n\r", trans_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + writel(SET_SPD_HEADER(*(spd_header)), hdmi_base + S5P_SPD_HEADER0); + + writel(SET_SPD_HEADER(*(spd_header + 1)) , hdmi_base + S5P_SPD_HEADER1); + writel(SET_SPD_HEADER(*(spd_header + 2)) , hdmi_base + S5P_SPD_HEADER2); + + writel(SET_SPD_DATA(*(spd_data)), hdmi_base + S5P_SPD_DATA0); + writel(SET_SPD_DATA(*(spd_data + 1)) , hdmi_base + S5P_SPD_DATA1); + writel(SET_SPD_DATA(*(spd_data + 2)) , hdmi_base + S5P_SPD_DATA2); + writel(SET_SPD_DATA(*(spd_data + 3)) , hdmi_base + S5P_SPD_DATA3); + writel(SET_SPD_DATA(*(spd_data + 4)) , hdmi_base + S5P_SPD_DATA4); + writel(SET_SPD_DATA(*(spd_data + 5)) , hdmi_base + S5P_SPD_DATA5); + writel(SET_SPD_DATA(*(spd_data + 6)) , hdmi_base + S5P_SPD_DATA6); + writel(SET_SPD_DATA(*(spd_data + 7)) , hdmi_base + S5P_SPD_DATA7); + writel(SET_SPD_DATA(*(spd_data + 8)) , hdmi_base + S5P_SPD_DATA8); + writel(SET_SPD_DATA(*(spd_data + 9)) , hdmi_base + S5P_SPD_DATA9); + writel(SET_SPD_DATA(*(spd_data + 10)) , hdmi_base + S5P_SPD_DATA10); + writel(SET_SPD_DATA(*(spd_data + 11)) , hdmi_base + S5P_SPD_DATA11); + writel(SET_SPD_DATA(*(spd_data + 12)) , hdmi_base + S5P_SPD_DATA12); + writel(SET_SPD_DATA(*(spd_data + 13)) , hdmi_base + S5P_SPD_DATA13); + writel(SET_SPD_DATA(*(spd_data + 14)) , hdmi_base + S5P_SPD_DATA14); + writel(SET_SPD_DATA(*(spd_data + 15)) , hdmi_base + S5P_SPD_DATA15); + writel(SET_SPD_DATA(*(spd_data + 16)) , hdmi_base + S5P_SPD_DATA16); + writel(SET_SPD_DATA(*(spd_data + 17)) , hdmi_base + S5P_SPD_DATA17); + writel(SET_SPD_DATA(*(spd_data + 18)) , hdmi_base + S5P_SPD_DATA18); + writel(SET_SPD_DATA(*(spd_data + 19)) , hdmi_base + S5P_SPD_DATA19); + writel(SET_SPD_DATA(*(spd_data + 20)) , hdmi_base + S5P_SPD_DATA20); + writel(SET_SPD_DATA(*(spd_data + 21)) , hdmi_base + S5P_SPD_DATA21); + writel(SET_SPD_DATA(*(spd_data + 22)) , hdmi_base + S5P_SPD_DATA22); + writel(SET_SPD_DATA(*(spd_data + 23)) , hdmi_base + S5P_SPD_DATA23); + writel(SET_SPD_DATA(*(spd_data + 24)) , hdmi_base + S5P_SPD_DATA24); + writel(SET_SPD_DATA(*(spd_data + 25)) , hdmi_base + S5P_SPD_DATA25); + writel(SET_SPD_DATA(*(spd_data + 26)) , hdmi_base + S5P_SPD_DATA26); + writel(SET_SPD_DATA(*(spd_data + 27)) , hdmi_base + S5P_SPD_DATA27); + + HDMIPRINTK("SPD_CON = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_CON)); + HDMIPRINTK("SPD_HEADER0 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_HEADER0)); + HDMIPRINTK("SPD_HEADER1 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_HEADER1)); + HDMIPRINTK("SPD_HEADER2 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_HEADER2)); + HDMIPRINTK("SPD_DATA0 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA0)); + HDMIPRINTK("SPD_DATA1 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA1)); + HDMIPRINTK("SPD_DATA2 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA2)); + HDMIPRINTK("SPD_DATA3 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA3)); + HDMIPRINTK("SPD_DATA4 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA4)); + HDMIPRINTK("SPD_DATA5 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA5)); + HDMIPRINTK("SPD_DATA6 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA6)); + HDMIPRINTK("SPD_DATA7 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA7)); + HDMIPRINTK("SPD_DATA8 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA8)); + HDMIPRINTK("SPD_DATA9 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA9)); + HDMIPRINTK("SPD_DATA10 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA10)); + HDMIPRINTK("SPD_DATA11 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA11)); + HDMIPRINTK("SPD_DATA12 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA12)); + HDMIPRINTK("SPD_DATA13 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA13)); + HDMIPRINTK("SPD_DATA14 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA14)); + HDMIPRINTK("SPD_DATA15 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA15)); + HDMIPRINTK("SPD_DATA16 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA16)); + HDMIPRINTK("SPD_DATA17 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA17)); + HDMIPRINTK("SPD_DATA18 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA18)); + HDMIPRINTK("SPD_DATA19 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA19)); + HDMIPRINTK("SPD_DATA20 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA20)); + HDMIPRINTK("SPD_DATA21 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA21)); + HDMIPRINTK("SPD_DATA22 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA22)); + HDMIPRINTK("SPD_DATA23 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA23)); + HDMIPRINTK("SPD_DATA24 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA24)); + HDMIPRINTK("SPD_DATA25 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA25)); + HDMIPRINTK("SPD_DATA26 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA26)); + HDMIPRINTK("SPD_DATA27 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA27)); + + return HDMI_NO_ERROR; +} + +void __s5p_hdmi_init_hpd_onoff(bool on_off) +{ + HDMIPRINTK("%d\n\r", on_off); + __s5p_hdmi_set_hpd_onoff(on_off); + HDMIPRINTK("0x%08x\n\r", readl(hdmi_base + S5P_HPD)); +} + +enum s5p_tv_hdmi_err __s5p_hdmi_audio_init( + enum s5p_tv_audio_codec_type audio_codec, + u32 sample_rate, u32 bits, u32 frame_size_code) +{ + __s5p_hdmi_audio_set_config(audio_codec); + __s5p_hdmi_audio_set_repetition_time(audio_codec, bits, + frame_size_code); + __s5p_hdmi_audio_irq_enable(IRQ_BUFFER_OVERFLOW_ENABLE); + __s5p_hdmi_audio_clock_enable(); + __s5p_hdmi_audio_set_asp(); + __s5p_hdmi_audio_set_acr(sample_rate); + __s5p_hdmi_audio_set_aui(audio_codec, sample_rate, bits); + + return HDMI_NO_ERROR; +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_display_mode( + enum s5p_tv_disp_mode disp_mode, + enum s5p_tv_o_mode out_mode) +{ + enum s5p_tv_hdmi_disp_mode hdmi_disp_num; + + HDMIPRINTK("%d,%d\n\r", disp_mode, out_mode); + + switch (disp_mode) { + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + + case TVOUT_720P_60: + + case TVOUT_720P_50: + writel(INT_PRO_MODE_PROGRESSIVE, hdmi_base + S5P_INT_PRO_MODE); + break; + + default: + HDMIPRINTK("invalid disp_mode parameter(%d)\n\r", disp_mode); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + switch (disp_mode) { + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + hdmi_disp_num = S5P_TV_HDMI_DISP_MODE_480P_60; + break; + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + hdmi_disp_num = S5P_TV_HDMI_DISP_MODE_576P_50; + break; + + case TVOUT_720P_60: + hdmi_disp_num = S5P_TV_HDMI_DISP_MODE_720P_60; + break; + + case TVOUT_720P_50: + hdmi_disp_num = S5P_TV_HDMI_DISP_MODE_720P_50; + break; + + default: + HDMIPRINTK(" invalid disp_mode parameter(%d)\n\r", disp_mode); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + switch (out_mode) { + + case TVOUT_OUTPUT_HDMI: + writel(PX_LMT_CTRL_BYPASS, hdmi_base + S5P_HDMI_CON_1); + writel(VID_PREAMBLE_EN | GUARD_BAND_EN, + hdmi_base + S5P_HDMI_CON_2); + writel(HDMI_MODE_EN | DVI_MODE_DIS, hdmi_base + S5P_MODE_SEL); + break; + + default: + HDMIPRINTK("invalid out_mode parameter(%d)\n\r", out_mode); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + writel(0x2b, hdmi_base + S5P_VACT_ST_MG); + + writel(0x30, hdmi_base + S5P_VACT_END_MG); + + writel(SET_H_BLANK_L(g_hdmi_video_parm_tbl + [H_BLANK*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_H_BLANK_0); + writel(SET_H_BLANK_H(g_hdmi_video_parm_tbl + [H_BLANK*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_H_BLANK_1); + + writel(SET_V2_BLANK_L(g_hdmi_video_parm_tbl + [V2_BLANK*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_BLANK_0); + writel(SET_V2_BLANK_H(g_hdmi_video_parm_tbl + [V2_BLANK*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + SET_V1_BLANK_L(g_hdmi_video_parm_tbl + [V1_BLANK*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_BLANK_1); + writel(SET_V1_BLANK_H(g_hdmi_video_parm_tbl + [V1_BLANK*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_BLANK_2); + + writel(SET_V_LINE_L(g_hdmi_video_parm_tbl + [V_LINE*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_H_V_LINE_0); + writel(SET_V_LINE_H(g_hdmi_video_parm_tbl + [V_LINE*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + SET_H_LINE_L(g_hdmi_video_parm_tbl + [H_LINE*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_H_V_LINE_1); + writel(SET_H_LINE_H(g_hdmi_video_parm_tbl + [H_LINE*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_H_V_LINE_2); + + writel(g_hdmi_video_parm_tbl + [VSYNC_POL*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num], + hdmi_base + S5P_SYNC_MODE); + + writel(0xfd, hdmi_base + S5P_SEND_PER_START0); + writel(0x01, hdmi_base + S5P_SEND_PER_START1); + writel(0x0d, hdmi_base + S5P_SEND_PER_END0); + writel(0x3a, hdmi_base + S5P_SEND_PER_END1); + writel(0x08, hdmi_base + S5P_SEND_PER_END2); + + writel(SET_V_BOT_ST_L(g_hdmi_video_parm_tbl + [V_BOT_ST*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_BLANK_F_0); + writel(SET_V_BOT_ST_H(g_hdmi_video_parm_tbl + [V_BOT_ST*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + SET_V_BOT_END_L(g_hdmi_video_parm_tbl + [V_BOT_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_BLANK_F_1); + writel(SET_V_BOT_END_H(g_hdmi_video_parm_tbl + [V_BOT_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_BLANK_F_2); + + + writel(SET_HSYNC_START_L(g_hdmi_video_parm_tbl + [HSYNC_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_H_SYNC_GEN_0); + writel(SET_HSYNC_START_H(g_hdmi_video_parm_tbl + [HSYNC_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + SET_HSYNC_END_L(g_hdmi_video_parm_tbl + [HSYNC_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_H_SYNC_GEN_1); + writel(SET_HSYNC_END_H(g_hdmi_video_parm_tbl + [HSYNC_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + ((g_hdmi_video_parm_tbl + [HSYNC_POL*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) ? + SET_HSYNC_POL_ACT_LOW : SET_HSYNC_POL_ACT_HIGH) , + hdmi_base + S5P_H_SYNC_GEN_2); + + + writel(SET_VSYNC_T_END_L(g_hdmi_video_parm_tbl + [VSYNC_T_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_1_0); + writel(SET_VSYNC_T_END_H(g_hdmi_video_parm_tbl + [VSYNC_T_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + SET_VSYNC_T_ST_L(g_hdmi_video_parm_tbl + [VSYNC_T_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + + hdmi_base + S5P_V_SYNC_GEN_1_1); + writel(SET_VSYNC_T_ST_H(g_hdmi_video_parm_tbl + [VSYNC_T_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_1_2); + + writel(SET_VSYNC_B_END_L(g_hdmi_video_parm_tbl + [VSYNC_B_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_2_0); + writel(SET_VSYNC_B_END_H(g_hdmi_video_parm_tbl + [VSYNC_B_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + SET_VSYNC_B_ST_L(g_hdmi_video_parm_tbl + [VSYNC_B_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_2_1); + writel(SET_VSYNC_B_ST_H(g_hdmi_video_parm_tbl + [VSYNC_B_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_2_2); + + writel(SET_VSYNC_H_POST_END_L(g_hdmi_video_parm_tbl + [VSYNC_h_POS_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_3_0); + + writel(SET_VSYNC_H_POST_END_H(g_hdmi_video_parm_tbl + [VSYNC_h_POS_END*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) | + SET_VSYNC_H_POST_ST_L(g_hdmi_video_parm_tbl + [VSYNC_h_POS_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_3_1); + + writel(SET_VSYNC_H_POST_ST_H(g_hdmi_video_parm_tbl + [VSYNC_h_POS_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_V_SYNC_GEN_3_2); + + + writel(0 , hdmi_base + S5P_TG_CMD); + writel(SET_TG_H_FSZ_L(g_hdmi_video_parm_tbl + [TG_H_FSZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) , + hdmi_base + S5P_TG_H_FSZ_L); + writel(SET_TG_H_FSZ_H(g_hdmi_video_parm_tbl + [TG_H_FSZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) , + hdmi_base + S5P_TG_H_FSZ_H); + + writel(SET_TG_HACT_ST_L(g_hdmi_video_parm_tbl + [TG_HACT_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]) , + hdmi_base + S5P_TG_HACT_ST_L); + writel(SET_TG_HACT_ST_H(g_hdmi_video_parm_tbl + [TG_HACT_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_HACT_ST_H); + writel(SET_TG_HACT_SZ_L(g_hdmi_video_parm_tbl + [TG_HACT_SZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_HACT_SZ_L); + writel(SET_TG_HACT_SZ_H(g_hdmi_video_parm_tbl + [TG_HACT_SZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_HACT_SZ_H); + + + writel(SET_TG_V_FSZ_L(g_hdmi_video_parm_tbl + [TG_V_FSZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_V_FSZ_L); + writel(SET_TG_V_FSZ_H(g_hdmi_video_parm_tbl + [TG_V_FSZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_V_FSZ_H); + writel(SET_TG_VSYNC_L(g_hdmi_video_parm_tbl + [TG_VSYNC*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC_L); + writel(SET_TG_VSYNC_H(g_hdmi_video_parm_tbl + [TG_VSYNC*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC_H); + writel(SET_TG_VSYNC2_L(g_hdmi_video_parm_tbl + [TG_VSYNC2*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC2_L); + writel(SET_TG_VSYNC2_H(g_hdmi_video_parm_tbl + [TG_VSYNC2*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC2_H); + + writel(SET_TG_VACT_ST_L(g_hdmi_video_parm_tbl + [TG_VACT_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VACT_ST_L); + writel(SET_TG_VACT_ST_H(g_hdmi_video_parm_tbl + [TG_VACT_START*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VACT_ST_H); + writel(SET_TG_VACT_SZ_L(g_hdmi_video_parm_tbl + [TG_VACT_SZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VACT_SZ_L); + writel(SET_TG_VACT_SZ_H(g_hdmi_video_parm_tbl + [TG_VACT_SZ*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VACT_SZ_H); + + writel(SET_TG_FIELD_CHG_L(g_hdmi_video_parm_tbl + [TG_FIELD_CHG*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_FIELD_CHG_L); + writel(SET_TG_FIELD_CHG_H(g_hdmi_video_parm_tbl + [TG_FIELD_CHG*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_FIELD_CHG_H); + + writel(SET_TG_VACT_ST2_L(g_hdmi_video_parm_tbl + [TG_VACT_START2*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VACT_ST2_L); + writel(SET_TG_VACT_ST2_H(g_hdmi_video_parm_tbl + [TG_VACT_START2*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VACT_ST2_H); + + writel(SET_TG_VSYNC_TOP_HDMI_L(g_hdmi_video_parm_tbl + [TG_VSYNC_TOP_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC_TOP_HDMI_L); + writel(SET_TG_VSYNC_TOP_HDMI_H(g_hdmi_video_parm_tbl + [TG_VSYNC_TOP_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC_TOP_HDMI_H); + writel(SET_TG_VSYNC_BOT_HDMI_L(g_hdmi_video_parm_tbl + [TG_VSYNC_BOTTOM_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC_BOT_HDMI_L); + writel(SET_TG_VSYNC_BOT_HDMI_H(g_hdmi_video_parm_tbl + [TG_VSYNC_BOTTOM_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + + hdmi_disp_num]), + hdmi_base + S5P_TG_VSYNC_BOT_HDMI_H); + + writel(SET_TG_FIELD_TOP_HDMI_L(g_hdmi_video_parm_tbl + [TG_FIELD_TOP_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_FIELD_TOP_HDMI_L); + writel(SET_TG_FIELD_TOP_HDMI_H(g_hdmi_video_parm_tbl + [TG_FIELD_TOP_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + hdmi_disp_num]), + hdmi_base + S5P_TG_FIELD_TOP_HDMI_H); + writel(SET_TG_FIELD_BOT_HDMI_L(g_hdmi_video_parm_tbl + [TG_FIELD_BOTTOM_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + + hdmi_disp_num]), + hdmi_base + S5P_TG_FIELD_BOT_HDMI_L); + writel(SET_TG_FIELD_BOT_HDMI_H(g_hdmi_video_parm_tbl + [TG_FIELD_BOTTOM_HDMI*S5P_TV_HDMI_DISP_MODE_NUM + + hdmi_disp_num]), + hdmi_base + S5P_TG_FIELD_BOT_HDMI_H); + + HDMIPRINTK("HDMI_CON_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CON_1)); + HDMIPRINTK("HDMI_CON_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CON_2)); + HDMIPRINTK("MODE_SEL = 0x%08x \n\r", + readl(hdmi_base + S5P_MODE_SEL)); + HDMIPRINTK("BLUE_SCREEN_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_0)); + HDMIPRINTK("BLUE_SCREEN_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_1)); + HDMIPRINTK("BLUE_SCREEN_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_2)); + HDMIPRINTK("VBI_ST_MG = 0x%08x \n\r", + readl(hdmi_base + S5P_VBI_ST_MG)); + HDMIPRINTK("VBI_END_MG = 0x%08x \n\r", + readl(hdmi_base + S5P_VBI_END_MG)); + HDMIPRINTK("VACT_ST_MG = 0x%08x \n\r", + readl(hdmi_base + S5P_VACT_ST_MG)); + HDMIPRINTK("VACT_END_MG = 0x%08x \n\r", + readl(hdmi_base + S5P_VACT_END_MG)); + HDMIPRINTK("H_BLANK_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_BLANK_0)); + HDMIPRINTK("H_BLANK_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_BLANK_1)); + HDMIPRINTK("V_BLANK_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_BLANK_0)); + HDMIPRINTK("V_BLANK_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_BLANK_1)); + HDMIPRINTK("V_BLANK_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_BLANK_2)); + HDMIPRINTK("H_V_LINE_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_V_LINE_0)); + HDMIPRINTK("H_V_LINE_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_V_LINE_1)); + HDMIPRINTK("H_V_LINE_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_V_LINE_2)); + HDMIPRINTK("SYNC_MODE = 0x%08x \n\r", + readl(hdmi_base + S5P_SYNC_MODE)); + HDMIPRINTK("INT_PRO_MODE = 0x%08x \n\r", + readl(hdmi_base + S5P_INT_PRO_MODE)); + HDMIPRINTK("SEND_PER_START0 = 0x%08x \n\r", + readl(hdmi_base + S5P_SEND_PER_START0)); + HDMIPRINTK("SEND_PER_START1 = 0x%08x \n\r", + readl(hdmi_base + S5P_SEND_PER_START1)); + HDMIPRINTK("SEND_PER_END0 = 0x%08x \n\r", + readl(hdmi_base + S5P_SEND_PER_END0)); + HDMIPRINTK("SEND_PER_END1 = 0x%08x \n\r", + readl(hdmi_base + S5P_SEND_PER_END1)); + HDMIPRINTK("SEND_PER_END2 = 0x%08x \n\r", + readl(hdmi_base + S5P_SEND_PER_END2)); + HDMIPRINTK("V_BLANK_F_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_BLANK_F_0)); + HDMIPRINTK("V_BLANK_F_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_BLANK_F_1)); + HDMIPRINTK("V_BLANK_F_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_BLANK_F_2)); + HDMIPRINTK("H_SYNC_GEN_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_SYNC_GEN_0)); + HDMIPRINTK("H_SYNC_GEN_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_SYNC_GEN_1)); + HDMIPRINTK("H_SYNC_GEN_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_H_SYNC_GEN_2)); + HDMIPRINTK("V_SYNC_GEN_1_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_1_0)); + HDMIPRINTK("V_SYNC_GEN_1_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_1_1)); + HDMIPRINTK("V_SYNC_GEN_1_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_1_2)); + HDMIPRINTK("V_SYNC_GEN_2_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_2_0)); + HDMIPRINTK("V_SYNC_GEN_2_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_2_1)); + HDMIPRINTK("V_SYNC_GEN_2_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_2_2)); + HDMIPRINTK("V_SYNC_GEN_3_0 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_3_0)); + HDMIPRINTK("V_SYNC_GEN_3_1 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_3_1)); + HDMIPRINTK("V_SYNC_GEN_3_2 = 0x%08x \n\r", + readl(hdmi_base + S5P_V_SYNC_GEN_3_2)); + HDMIPRINTK("TG_CMD = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_CMD)); + HDMIPRINTK("TG_H_FSZ_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_H_FSZ_L)); + HDMIPRINTK("TG_H_FSZ_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_H_FSZ_H)); + HDMIPRINTK("TG_HACT_ST_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_HACT_ST_L)); + HDMIPRINTK("TG_HACT_ST_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_HACT_ST_H)); + HDMIPRINTK("TG_HACT_SZ_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_HACT_SZ_L)); + HDMIPRINTK("TG_HACT_SZ_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_HACT_SZ_H)); + HDMIPRINTK("TG_V_FSZ_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_V_FSZ_L)); + HDMIPRINTK("TG_V_FSZ_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_V_FSZ_H)); + HDMIPRINTK("TG_VSYNC_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC_L)); + HDMIPRINTK("TG_VSYNC_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC_H)); + HDMIPRINTK("TG_VSYNC2_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC2_L)); + HDMIPRINTK("TG_VSYNC2_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC2_H)); + HDMIPRINTK("TG_VACT_ST_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VACT_ST_L)); + HDMIPRINTK("TG_VACT_ST_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VACT_ST_H)); + HDMIPRINTK("TG_VACT_SZ_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VACT_SZ_L)); + HDMIPRINTK("TG_VACT_SZ_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VACT_SZ_H)); + HDMIPRINTK("TG_FIELD_CHG_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_FIELD_CHG_L)); + HDMIPRINTK("TG_FIELD_CHG_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_FIELD_CHG_H)); + HDMIPRINTK("TG_VACT_ST2_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VACT_ST2_L)); + HDMIPRINTK("TG_VACT_ST2_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VACT_ST2_H)); + HDMIPRINTK("TG_VSYNC_TOP_HDMI_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC_TOP_HDMI_L)); + HDMIPRINTK("TG_VSYNC_TOP_HDMI_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC_TOP_HDMI_H)); + HDMIPRINTK("TG_VSYNC_BOT_HDMI_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC_BOT_HDMI_L)); + HDMIPRINTK("TG_VSYNC_BOT_HDMI_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_VSYNC_BOT_HDMI_H)); + HDMIPRINTK("TG_FIELD_TOP_HDMI_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_FIELD_TOP_HDMI_L)); + HDMIPRINTK("TG_FIELD_TOP_HDMI_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_FIELD_TOP_HDMI_H)); + HDMIPRINTK("TG_FIELD_BOT_HDMI_L = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_FIELD_BOT_HDMI_L)); + HDMIPRINTK("TG_FIELD_BOT_HDMI_H = 0x%08x \n\r", + readl(hdmi_base + S5P_TG_FIELD_BOT_HDMI_H)); + + return HDMI_NO_ERROR; +} + +void __s5p_hdmi_video_init_bluescreen(bool en, + u8 cb_b, + u8 y_g, + u8 cr_r) +{ + HDMIPRINTK("()\n\r"); + + __s5p_hdmi_video_set_bluescreen(en, cb_b, y_g, cr_r); + + HDMIPRINTK("()\n\r"); +} + +void __s5p_hdmi_video_init_color_range(u8 y_min, + u8 y_max, + u8 c_min, + u8 c_max) +{ + HDMIPRINTK("%d,%d,%d,%d\n\r", y_max, y_min, c_max, c_min); + + writel(y_max, hdmi_base + S5P_HDMI_YMAX); + writel(y_min, hdmi_base + S5P_HDMI_YMIN); + writel(c_max, hdmi_base + S5P_HDMI_CMAX); + writel(c_min, hdmi_base + S5P_HDMI_CMIN); + + HDMIPRINTK("HDMI_YMAX = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_YMAX)); + HDMIPRINTK("HDMI_YMIN = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_YMIN)); + HDMIPRINTK("HDMI_CMAX = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CMAX)); + HDMIPRINTK("HDMI_CMIN = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CMIN)); +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_csc( + enum s5p_tv_hdmi_csc_type csc_type) +{ + unsigned short us_csc_coeff[10]; + + HDMIPRINTK("%d)\n\r", csc_type); + + switch (csc_type) { + + case HDMI_CSC_YUV601_TO_RGB_LR: + us_csc_coeff[0] = 0x23; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 938; + us_csc_coeff[3] = 846; + us_csc_coeff[4] = 256; + us_csc_coeff[5] = 443; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 256; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 350; + break; + + case HDMI_CSC_YUV601_TO_RGB_FR: + us_csc_coeff[0] = 0x03; + us_csc_coeff[1] = 298; + us_csc_coeff[2] = 924; + us_csc_coeff[3] = 816; + us_csc_coeff[4] = 298; + us_csc_coeff[5] = 516; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 298; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 408; + break; + + case HDMI_CSC_YUV709_TO_RGB_LR: + us_csc_coeff[0] = 0x23; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 978; + us_csc_coeff[3] = 907; + us_csc_coeff[4] = 256; + us_csc_coeff[5] = 464; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 256; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 394; + break; + + case HDMI_CSC_YUV709_TO_RGB_FR: + us_csc_coeff[0] = 0x03; + us_csc_coeff[1] = 298; + us_csc_coeff[2] = 970; + us_csc_coeff[3] = 888; + us_csc_coeff[4] = 298; + us_csc_coeff[5] = 540; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 298; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 458; + break; + + case HDMI_CSC_YUV601_TO_YUV709: + us_csc_coeff[0] = 0x33; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 995; + us_csc_coeff[3] = 971; + us_csc_coeff[4] = 0; + us_csc_coeff[5] = 260; + us_csc_coeff[6] = 29; + us_csc_coeff[7] = 0; + us_csc_coeff[8] = 19; + us_csc_coeff[9] = 262; + break; + + case HDMI_CSC_RGB_FR_TO_RGB_LR: + us_csc_coeff[0] = 0x20; + us_csc_coeff[1] = 220; + us_csc_coeff[2] = 0; + us_csc_coeff[3] = 0; + us_csc_coeff[4] = 0; + us_csc_coeff[5] = 220; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 0; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 220; + break; + + case HDMI_CSC_RGB_FR_TO_YUV601: + us_csc_coeff[0] = 0x30; + us_csc_coeff[1] = 129; + us_csc_coeff[2] = 25; + us_csc_coeff[3] = 65; + us_csc_coeff[4] = 950; + us_csc_coeff[5] = 112; + us_csc_coeff[6] = 986; + us_csc_coeff[7] = 930; + us_csc_coeff[8] = 1006; + us_csc_coeff[9] = 112; + break; + + case HDMI_CSC_RGB_FR_TO_YUV709: + us_csc_coeff[0] = 0x30; + us_csc_coeff[1] = 157; + us_csc_coeff[2] = 16; + us_csc_coeff[3] = 47; + us_csc_coeff[4] = 937; + us_csc_coeff[5] = 112; + us_csc_coeff[6] = 999; + us_csc_coeff[7] = 922; + us_csc_coeff[8] = 1014; + us_csc_coeff[9] = 112; + break; + + case HDMI_BYPASS: + us_csc_coeff[0] = 0x33; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 0; + us_csc_coeff[3] = 0; + us_csc_coeff[4] = 0; + us_csc_coeff[5] = 256; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 0; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 256; + break; + + default: + HDMIPRINTK("invalid out_mode parameter(%d)\n\r", csc_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + writel(us_csc_coeff[0], hdmi_base + S5P_HDMI_CSC_CON);; + + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[1]), + hdmi_base + S5P_HDMI_Y_G_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[1]), + hdmi_base + S5P_HDMI_Y_G_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[2]), + hdmi_base + S5P_HDMI_Y_B_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[2]), + hdmi_base + S5P_HDMI_Y_B_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[3]), + hdmi_base + S5P_HDMI_Y_R_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[3]), + hdmi_base + S5P_HDMI_Y_R_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[4]), + hdmi_base + S5P_HDMI_CB_G_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[4]), + hdmi_base + S5P_HDMI_CB_G_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[5]), + hdmi_base + S5P_HDMI_CB_B_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[5]), + hdmi_base + S5P_HDMI_CB_B_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[6]), + hdmi_base + S5P_HDMI_CB_R_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[6]), + hdmi_base + S5P_HDMI_CB_R_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[7]), + hdmi_base + S5P_HDMI_CR_G_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[7]), + hdmi_base + S5P_HDMI_CR_G_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[8]), + hdmi_base + S5P_HDMI_CR_B_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[8]), + hdmi_base + S5P_HDMI_CR_B_COEF_H); + writel(SET_HDMI_CSC_COEF_L(us_csc_coeff[9]), + hdmi_base + S5P_HDMI_CR_R_COEF_L); + writel(SET_HDMI_CSC_COEF_H(us_csc_coeff[9]), + hdmi_base + S5P_HDMI_CR_R_COEF_H); + + HDMIPRINTK("HDMI_CSC_CON = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CSC_CON)); + HDMIPRINTK("HDMI_Y_G_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_Y_G_COEF_L)); + HDMIPRINTK("HDMI_Y_G_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_Y_G_COEF_H)); + HDMIPRINTK("HDMI_Y_B_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_Y_B_COEF_L)); + HDMIPRINTK("HDMI_Y_B_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_Y_B_COEF_H)); + HDMIPRINTK("HDMI_Y_R_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_Y_R_COEF_L)); + HDMIPRINTK("HDMI_Y_R_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_Y_R_COEF_H)); + HDMIPRINTK("HDMI_CB_G_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CB_G_COEF_L)); + HDMIPRINTK("HDMI_CB_G_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CB_G_COEF_H)); + HDMIPRINTK("HDMI_CB_B_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CB_B_COEF_L)); + HDMIPRINTK("HDMI_CB_B_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CB_B_COEF_H)); + HDMIPRINTK("HDMI_CB_R_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CB_R_COEF_L)); + HDMIPRINTK("HDMI_CB_R_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CB_R_COEF_H)); + HDMIPRINTK("HDMI_CR_G_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CR_G_COEF_L)); + HDMIPRINTK("HDMI_CR_G_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CR_G_COEF_H)); + HDMIPRINTK("HDMI_CR_B_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CR_B_COEF_L)); + HDMIPRINTK("HDMI_CR_B_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CR_B_COEF_H)); + HDMIPRINTK("HDMI_CR_R_COEF_L = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CR_R_COEF_L)); + HDMIPRINTK("HDMI_CR_R_COEF_H = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CR_R_COEF_H)); + + return HDMI_NO_ERROR; +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_avi_infoframe( + enum s5p_hdmi_transmit trans_type, u8 check_sum, u8 *avi_data) +{ + HDMIPRINTK("%d,%d,%d\n\r", (u32)trans_type, (u32)check_sum, + (u32)avi_data); + + switch (trans_type) { + + case HDMI_DO_NOT_TANS: + writel(AVI_TX_CON_NO_TRANS, hdmi_base + S5P_AVI_CON); + break; + + case HDMI_TRANS_ONCE: + writel(AVI_TX_CON_TRANS_ONCE, hdmi_base + S5P_AVI_CON); + break; + + case HDMI_TRANS_EVERY_SYNC: + writel(AVI_TX_CON_TRANS_EVERY_VSYNC, hdmi_base + S5P_AVI_CON); + break; + + default: + HDMIPRINTK(" invalid out_mode parameter(%d)\n\r", trans_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + writel(SET_AVI_CHECK_SUM(check_sum), hdmi_base + S5P_AVI_CHECK_SUM); + + writel(SET_AVI_BYTE(*(avi_data)), hdmi_base + S5P_AVI_BYTE1); + writel(SET_AVI_BYTE(*(avi_data + 1)), hdmi_base + S5P_AVI_BYTE2); + writel(SET_AVI_BYTE(*(avi_data + 2)), hdmi_base + S5P_AVI_BYTE3); + writel(SET_AVI_BYTE(*(avi_data + 3)), hdmi_base + S5P_AVI_BYTE4); + writel(SET_AVI_BYTE(*(avi_data + 4)), hdmi_base + S5P_AVI_BYTE5); + writel(SET_AVI_BYTE(*(avi_data + 5)), hdmi_base + S5P_AVI_BYTE6); + writel(SET_AVI_BYTE(*(avi_data + 6)), hdmi_base + S5P_AVI_BYTE7); + writel(SET_AVI_BYTE(*(avi_data + 7)), hdmi_base + S5P_AVI_BYTE8); + writel(SET_AVI_BYTE(*(avi_data + 8)), hdmi_base + S5P_AVI_BYTE9); + writel(SET_AVI_BYTE(*(avi_data + 9)), hdmi_base + S5P_AVI_BYTE10); + writel(SET_AVI_BYTE(*(avi_data + 10)), hdmi_base + S5P_AVI_BYTE11); + writel(SET_AVI_BYTE(*(avi_data + 11)), hdmi_base + S5P_AVI_BYTE12); + writel(SET_AVI_BYTE(*(avi_data + 12)), hdmi_base + S5P_AVI_BYTE13); + + HDMIPRINTK("AVI_CON = 0x%08x \n\r", readl(hdmi_base + S5P_AVI_CON)); + HDMIPRINTK("AVI_CHECK_SUM = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_CHECK_SUM)); + HDMIPRINTK("AVI_BYTE1 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE1)); + HDMIPRINTK("AVI_BYTE2 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE2)); + HDMIPRINTK("AVI_BYTE3 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE3)); + HDMIPRINTK("AVI_BYTE4 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE4)); + HDMIPRINTK("AVI_BYTE5 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE5)); + HDMIPRINTK("AVI_BYTE6 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE6)); + HDMIPRINTK("AVI_BYTE7 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE7)); + HDMIPRINTK("AVI_BYTE8 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE8)); + HDMIPRINTK("AVI_BYTE9 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE9)); + HDMIPRINTK("AVI_BYTE10 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE10)); + HDMIPRINTK("AVI_BYTE11 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE11)); + HDMIPRINTK("AVI_BYTE12 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE12)); + HDMIPRINTK("AVI_BYTE13 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE13)); + + /* + * for test color bar + */ + /* + { + + writel( 0xff&32,HDMI_TPGEN_1); + writel( (32>>8)&0xff,HDMI_TPGEN_2); + writel( 0xff&480,HDMI_TPGEN_3); + writel( (480>>8)&0xff,HDMI_TPGEN_4); + writel( 0xff&720,HDMI_TPGEN_5); + writel( (720>>8)&0xff,HDMI_TPGEN_6); + + u8 uTpGen0Reg = 0x1 | (0x1<<3) | (1<<4); + writel( uTpGen0Reg, HDMI_TPGEN_0); + + HDMIPRINTK("HDMI_TPGEN_0 0x%08x\n",readl(HDMI_TPGEN_0)); + HDMIPRINTK("HDMI_TPGEN_1 0x%08x\n",readl(HDMI_TPGEN_1)); + HDMIPRINTK("HDMI_TPGEN_2 0x%08x\n",readl(HDMI_TPGEN_2)); + HDMIPRINTK("HDMI_TPGEN_3 0x%08x\n",readl(HDMI_TPGEN_3)); + HDMIPRINTK("HDMI_TPGEN_5 0x%08x\n",readl(HDMI_TPGEN_4)); + HDMIPRINTK("HDMI_TPGEN_0 0x%08x\n",readl(HDMI_TPGEN_5)); + HDMIPRINTK("HDMI_TPGEN_1 0x%08x\n",readl(HDMI_TPGEN_6)); + } + */ + + return HDMI_NO_ERROR; +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_mpg_infoframe( + enum s5p_hdmi_transmit trans_type, u8 check_sum, u8 *mpg_data) +{ + HDMIPRINTK("trans_type : %d,%d,%d\n\r", (u32)trans_type, + (u32)check_sum, (u32)mpg_data); + + switch (trans_type) { + + case HDMI_DO_NOT_TANS: + writel(MPG_TX_CON_NO_TRANS, + hdmi_base + S5P_MPG_CON); + break; + + case HDMI_TRANS_ONCE: + writel(MPG_TX_CON_TRANS_ONCE, + hdmi_base + S5P_MPG_CON); + break; + + case HDMI_TRANS_EVERY_SYNC: + writel(MPG_TX_CON_TRANS_EVERY_VSYNC, + hdmi_base + S5P_MPG_CON); + break; + + default: + HDMIPRINTK("invalid out_mode parameter(%d)\n\r", + trans_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + writel(SET_MPG_CHECK_SUM(check_sum), + + hdmi_base + S5P_MPG_CHECK_SUM); + + writel(SET_MPG_BYTE(*(mpg_data)), + hdmi_base + S5P_MPEG_BYTE1); + writel(SET_MPG_BYTE(*(mpg_data + 1)), + hdmi_base + S5P_MPEG_BYTE2); + writel(SET_MPG_BYTE(*(mpg_data + 2)), + hdmi_base + S5P_MPEG_BYTE3); + writel(SET_MPG_BYTE(*(mpg_data + 3)), + hdmi_base + S5P_MPEG_BYTE4); + writel(SET_MPG_BYTE(*(mpg_data + 4)), + hdmi_base + S5P_MPEG_BYTE5); + + HDMIPRINTK("MPG_CON = 0x%08x \n\r", + readl(hdmi_base + S5P_MPG_CON)); + HDMIPRINTK("MPG_CHECK_SUM = 0x%08x \n\r", + readl(hdmi_base + S5P_MPG_CHECK_SUM)); + HDMIPRINTK("MPEG_BYTE1 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE1)); + HDMIPRINTK("MPEG_BYTE2 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE2)); + HDMIPRINTK("MPEG_BYTE3 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE3)); + HDMIPRINTK("MPEG_BYTE4 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE4)); + HDMIPRINTK("MPEG_BYTE5 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE5)); + + return HDMI_NO_ERROR; +} + +void __s5p_hdmi_video_init_tg_cmd(bool time_c_e, + bool bt656_sync_en, + bool tg_en) +{ + u32 temp_reg = 0; + + temp_reg = readl(hdmi_base + S5P_TG_CMD); + + if (time_c_e) + temp_reg |= GETSYNC_TYPE_EN; + else + temp_reg &= GETSYNC_TYPE_DIS; + + if (bt656_sync_en) + temp_reg |= GETSYNC_EN; + else + temp_reg &= GETSYNC_DIS; + + if (tg_en) + temp_reg |= TG_EN; + else + temp_reg &= TG_DIS; + + writel(temp_reg, hdmi_base + S5P_TG_CMD); + + HDMIPRINTK("TG_CMD = 0x%08x \n\r", readl(hdmi_base + S5P_TG_CMD)); +} + + +/* +* start - start functions are only called under stopping HDMI +*/ +bool __s5p_hdmi_start(enum s5p_hdmi_audio_type hdmi_audio_type, + bool hdcp_en, + struct i2c_client *ddc_port) +{ + u32 temp_reg = PWDN_ENB_NORMAL | HDMI_EN;; + + HDMIPRINTK("aud type : %d, hdcp enable : %d\n\r", + hdmi_audio_type, hdcp_en); + + switch (hdmi_audio_type) { + + case HDMI_AUDIO_PCM: + temp_reg |= ASP_EN; + break; + + case HDMI_AUDIO_NO: + break; + + default: + HDMIPRINTK(" invalid hdmi_audio_type(%d)\n\r", + hdmi_audio_type); + return false; + break; + } + + writel(readl(hdmi_base + S5P_HDMI_CON_0) | temp_reg, + + hdmi_base + S5P_HDMI_CON_0); + + if (hdcp_en) { + __s5p_init_hdcp(true, ddc_port); + + if (!__s5p_start_hdcp()) + HDMIPRINTK("HDCP start failed\n"); + + } + + HDMIPRINTK("HDCP_CTRL : 0x%08x, HPD : 0x%08x, HDMI_CON_0 :\ + 0x%08x\n\r", + + readl(hdmi_base + S5P_HDCP_CTRL), + readl(hdmi_base + S5P_HPD), + readl(hdmi_base + S5P_HDMI_CON_0)); + + return true; +} + + + +/* +* stop - stop functions are only called under running HDMI +*/ +void __s5p_hdmi_stop(void) +{ + HDMIPRINTK("\n\r"); + + __s5p_stop_hdcp(); + + writel(readl(hdmi_base + S5P_HDMI_CON_0) & + ~(PWDN_ENB_NORMAL | HDMI_EN | ASP_EN), + hdmi_base + S5P_HDMI_CON_0); + + HDMIPRINTK("HDCP_CTRL 0x%08x, HPD 0x%08x,HDMI_CON_0 0x%08x\n\r", + readl(hdmi_base + S5P_HDCP_CTRL), + readl(hdmi_base + S5P_HPD), + readl(hdmi_base + S5P_HDMI_CON_0)); +} + +int __init __s5p_hdmi_probe(struct platform_device *pdev, u32 res_num) +{ + + struct resource *res; + size_t size; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + ret = -ENOENT; + } + + size = (res->end - res->start) + 1; + + hdmi_mem = request_mem_region(res->start, size, pdev->name); + + if (hdmi_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + ret = -ENOENT; + } + + hdmi_base = ioremap(res->start, size); + + if (hdmi_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + ret = -ENOENT; + } + + return ret; + +} + +int __init __s5p_hdmi_release(struct platform_device *pdev) +{ + iounmap(hdmi_base); + + /* remove memory region */ + + if (hdmi_mem != NULL) { + if (release_resource(hdmi_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(hdmi_mem); + + hdmi_mem = NULL; + } + + return 0; +} + diff --git a/drivers/media/video/samsung/tv20/s5pc100/regs/regs-clock_extra.h b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-clock_extra.h new file mode 100644 index 0000000..ff00b23 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-clock_extra.h @@ -0,0 +1,79 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-clock_extra.h + * + * Clock Other header file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_CLK_EXTRA_H +#define __ASM_ARCH_REGS_CLK_EXTRA_H + +#include <mach/map.h> + +#define S5P_CLK_OTHER_BASE(x) (x) + +#define S5P_CLK_OTHER_SWRESET S5P_CLK_OTHER_BASE(0x0000) +#define S5P_CLK_OTHER_ONENAND_SWRESET S5P_CLK_OTHER_BASE(0x0008) +#define S5P_CLK_OTHER_GENERAL_CTRL S5P_CLK_OTHER_BASE(0x0100) +#define S5P_CLK_OTHER_GENERAL_STATUS S5P_CLK_OTHER_BASE(0x0104) +#define S5P_CLK_OTHER_MEM_SYS_CFG S5P_CLK_OTHER_BASE(0x0200) +#define S5P_CLK_OTHER_CAM_MUX_SEL S5P_CLK_OTHER_BASE(0x0300) +#define S5P_CLK_OTHER_MIXER_OUT_SEL S5P_CLK_OTHER_BASE(0x0304) +#define S5P_CLK_OTHER_LPMP3_MODE_SEL S5P_CLK_OTHER_BASE(0x0308) +#define S5P_CLK_OTHER_MIPI_PHY_CON0 S5P_CLK_OTHER_BASE(0x0400) +#define S5P_CLK_OTHER_MIPI_PHY_CON1 S5P_CLK_OTHER_BASE(0x0414) +#define S5P_CLK_OTHER_HDMI_PHY_CON0 S5P_CLK_OTHER_BASE(0x0420) + + + +#define HPLL_LOCKTIME(a) (0xffff&a) + +#define HPLL_ENABLE (1<<31) +#define HPLL_DISABLE (0<<31) +#define HPLL_LOCKED(a) ((1<<30)&a) +#define MDIV(a) ((0xff&a)<<16) +#define PDIV(a) ((0x3f&a)<<8) +#define SDIV(a) (0x7&a) + +#define HREF_SEL_FIN_27M (0<<20) +#define HREF_SEL_SRCLK (1<<20) +#define HREF_SEL_MASK (~(1<<20)) +#define HPLL_SEL_CLK27M (0<<12) +#define HPLL_SEL_FOUT_HPLL (1<<12) +#define HPLL_SEL_MASK (~(1<<12)) + +#define VMIXER_SEL_CLK27M (0<<28) +#define VMIXER_SEL_VCLK_54 (1<<28) +#define VMIXER_SEL_MOUT_HPLL (2<<28) +#define VMIXER_SEL_MASK (~(3<<28)) + +#define HDMI_DIV_RATIO(a) ((0xf&((a)-1))<<28) +#define HDMI_DIV_RATIO_MASK (~(0xf<<28)) + +#define CLK_HCLK_HDMI_PASS (1<<3) +#define CLK_HCLK_VMIXER_PASS (1<<2) +#define CLK_HCLK_VP_PASS (1<<1) +#define CLK_HCLK_SDOUT_PASS (1<<0) +#define CLK_HCLK_MASK (~0xf) + +#define CLK_PCLK_IIC_HDMI_PASS (1<<5) +#define CLK_PCLK_IIC_HDMI_MASK (~(1<<5)) + +#define CLK_SCLK_HDMI_PASS (1<<7) +#define CLK_SCLK_VMIXER_PASS (1<<6) +#define CLK_SCLK_VDAC54_PASS (1<<5) +#define CLK_SCLK_TV54_PASS (1<<4) +#define CLK_SCLK_HDMI_MASK (~(1<<7)) +#define CLK_SCLK_VMIXER_MASK (~(1<<6)) +#define CLK_SCLK_VDAC54_MASK (~(1<<5)) +#define CLK_SCLK_TV54_MASK (~(1<<4)) + +#define VMIXER_OUT_SEL_SDOUT (0) +#define VMIXER_OUT_SEL_HDMI (1) + +#endif diff --git a/drivers/media/video/samsung/tv20/s5pc100/regs/regs-hdmi.h b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-hdmi.h new file mode 100644 index 0000000..96c1958 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-hdmi.h @@ -0,0 +1,978 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-hdmi.h + * + * Hdmi register header file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_HDMI_H + +#include <mach/map.h> + +#define S5P_HDMI_BASE(x) (x) + +#define S5P_HDMI_CON_0 S5P_HDMI_BASE(0x0000) +#define S5P_HDMI_CON_1 S5P_HDMI_BASE(0x0004) +#define S5P_HDMI_CON_2 S5P_HDMI_BASE(0x0008) +#define S5P_STATUS S5P_HDMI_BASE(0x0010) +#define S5P_STATUS_EN S5P_HDMI_BASE(0x0020) +#define S5P_HPD S5P_HDMI_BASE(0x0030) +#define S5P_MODE_SEL S5P_HDMI_BASE(0x0040) +#define S5P_ENC_EN S5P_HDMI_BASE(0x0044) +#define S5P_BLUE_SCREEN_0 S5P_HDMI_BASE(0x0050) +#define S5P_BLUE_SCREEN_1 S5P_HDMI_BASE(0x0054) +#define S5P_BLUE_SCREEN_2 S5P_HDMI_BASE(0x0058) +#define S5P_HDMI_YMAX S5P_HDMI_BASE(0x0060) +#define S5P_HDMI_YMIN S5P_HDMI_BASE(0x0064) +#define S5P_HDMI_CMAX S5P_HDMI_BASE(0x0068) +#define S5P_HDMI_CMIN S5P_HDMI_BASE(0x006C) +#define S5P_VBI_ST_MG S5P_HDMI_BASE(0x0080) +#define S5P_VBI_END_MG S5P_HDMI_BASE(0x0084) +#define S5P_VACT_ST_MG S5P_HDMI_BASE(0x0088) +#define S5P_VACT_END_MG S5P_HDMI_BASE(0x008C) +#define S5P_H_BLANK_0 S5P_HDMI_BASE(0x00A0) +#define S5P_H_BLANK_1 S5P_HDMI_BASE(0x00A4) +#define S5P_V_BLANK_0 S5P_HDMI_BASE(0x00B0) +#define S5P_V_BLANK_1 S5P_HDMI_BASE(0x00B4) +#define S5P_V_BLANK_2 S5P_HDMI_BASE(0x00B8) +#define S5P_H_V_LINE_0 S5P_HDMI_BASE(0x00C0) +#define S5P_H_V_LINE_1 S5P_HDMI_BASE(0x00C4) +#define S5P_H_V_LINE_2 S5P_HDMI_BASE(0x00C8) +#define S5P_SYNC_MODE S5P_HDMI_BASE(0x00E4) +#define S5P_INT_PRO_MODE S5P_HDMI_BASE(0x00E8) +#define S5P_SEND_PER_START0 S5P_HDMI_BASE(0x00f0) +#define S5P_SEND_PER_START1 S5P_HDMI_BASE(0x00f4) +#define S5P_SEND_PER_END0 S5P_HDMI_BASE(0x0100) +#define S5P_SEND_PER_END1 S5P_HDMI_BASE(0x0104) +#define S5P_SEND_PER_END2 S5P_HDMI_BASE(0x0108) +#define S5P_V_BLANK_F_0 S5P_HDMI_BASE(0x0110) +#define S5P_V_BLANK_F_1 S5P_HDMI_BASE(0x0114) +#define S5P_V_BLANK_F_2 S5P_HDMI_BASE(0x0118) +#define S5P_H_SYNC_GEN_0 S5P_HDMI_BASE(0x0120) +#define S5P_H_SYNC_GEN_1 S5P_HDMI_BASE(0x0124) +#define S5P_H_SYNC_GEN_2 S5P_HDMI_BASE(0x0128) +#define S5P_V_SYNC_GEN_1_0 S5P_HDMI_BASE(0x0130) +#define S5P_V_SYNC_GEN_1_1 S5P_HDMI_BASE(0x0134) +#define S5P_V_SYNC_GEN_1_2 S5P_HDMI_BASE(0x0138) +#define S5P_V_SYNC_GEN_2_0 S5P_HDMI_BASE(0x0140) +#define S5P_V_SYNC_GEN_2_1 S5P_HDMI_BASE(0x0144) +#define S5P_V_SYNC_GEN_2_2 S5P_HDMI_BASE(0x0148) +#define S5P_V_SYNC_GEN_3_0 S5P_HDMI_BASE(0x0150) +#define S5P_V_SYNC_GEN_3_1 S5P_HDMI_BASE(0x0154) +#define S5P_V_SYNC_GEN_3_2 S5P_HDMI_BASE(0x0158) +#define S5P_ASP_CON S5P_HDMI_BASE(0x0160) +#define S5P_ASP_SP_FLAT S5P_HDMI_BASE(0x0164) +#define S5P_ASP_CHCFG0 S5P_HDMI_BASE(0x0170) +#define S5P_ASP_CHCFG1 S5P_HDMI_BASE(0x0174) +#define S5P_ASP_CHCFG2 S5P_HDMI_BASE(0x0178) +#define S5P_ASP_CHCFG3 S5P_HDMI_BASE(0x017C) +#define S5P_ACR_CON S5P_HDMI_BASE(0x0180) +#define S5P_ACR_MCTS0 S5P_HDMI_BASE(0x0184) +#define S5P_ACR_MCTS1 S5P_HDMI_BASE(0x0188) +#define S5P_ACR_MCTS2 S5P_HDMI_BASE(0x018C) +#define S5P_ACR_CTS0 S5P_HDMI_BASE(0x0190) +#define S5P_ACR_CTS1 S5P_HDMI_BASE(0x0194) +#define S5P_ACR_CTS2 S5P_HDMI_BASE(0x0198) +#define S5P_ACR_N0 S5P_HDMI_BASE(0x01A0) +#define S5P_ACR_N1 S5P_HDMI_BASE(0x01A4) +#define S5P_ACR_N2 S5P_HDMI_BASE(0x01A8) +#define S5P_ACR_LSB2 S5P_HDMI_BASE(0x01B0) +#define S5P_ACR_TXCNT S5P_HDMI_BASE(0x01B4) +#define S5P_ACR_TXINTERVAL S5P_HDMI_BASE(0x01B8) +#define S5P_ACR_CTS_OFFSET S5P_HDMI_BASE(0x01BC) +#define S5P_GCP_CON S5P_HDMI_BASE(0x01C0) +#define S5P_GCP_BYTE1 S5P_HDMI_BASE(0x01D0) +#define S5P_ACP_CON S5P_HDMI_BASE(0x01E0) +#define S5P_ACP_TYPE S5P_HDMI_BASE(0x01E4) + +#define S5P_ACP_DATA0 S5P_HDMI_BASE(0x0200) +#define S5P_ACP_DATA1 S5P_HDMI_BASE(0x0204) +#define S5P_ACP_DATA2 S5P_HDMI_BASE(0x0208) +#define S5P_ACP_DATA3 S5P_HDMI_BASE(0x020c) +#define S5P_ACP_DATA4 S5P_HDMI_BASE(0x0210) +#define S5P_ACP_DATA5 S5P_HDMI_BASE(0x0214) +#define S5P_ACP_DATA6 S5P_HDMI_BASE(0x0218) +#define S5P_ACP_DATA7 S5P_HDMI_BASE(0x021c) +#define S5P_ACP_DATA8 S5P_HDMI_BASE(0x0220) +#define S5P_ACP_DATA9 S5P_HDMI_BASE(0x0224) +#define S5P_ACP_DATA10 S5P_HDMI_BASE(0x0228) +#define S5P_ACP_DATA11 S5P_HDMI_BASE(0x022c) +#define S5P_ACP_DATA12 S5P_HDMI_BASE(0x0230) +#define S5P_ACP_DATA13 S5P_HDMI_BASE(0x0234) +#define S5P_ACP_DATA14 S5P_HDMI_BASE(0x0238) +#define S5P_ACP_DATA15 S5P_HDMI_BASE(0x023c) +#define S5P_ACP_DATA16 S5P_HDMI_BASE(0x0240) + +#define S5P_ISRC_CON S5P_HDMI_BASE(0x0250) +#define S5P_ISRC1_HEADER1 S5P_HDMI_BASE(0x0264) + +#define S5P_ISRC1_DATA0 S5P_HDMI_BASE(0x0270) +#define S5P_ISRC1_DATA1 S5P_HDMI_BASE(0x0274) +#define S5P_ISRC1_DATA2 S5P_HDMI_BASE(0x0278) +#define S5P_ISRC1_DATA3 S5P_HDMI_BASE(0x027c) +#define S5P_ISRC1_DATA4 S5P_HDMI_BASE(0x0280) +#define S5P_ISRC1_DATA5 S5P_HDMI_BASE(0x0284) +#define S5P_ISRC1_DATA6 S5P_HDMI_BASE(0x0288) +#define S5P_ISRC1_DATA7 S5P_HDMI_BASE(0x028c) +#define S5P_ISRC1_DATA8 S5P_HDMI_BASE(0x0290) +#define S5P_ISRC1_DATA9 S5P_HDMI_BASE(0x0294) +#define S5P_ISRC1_DATA10 S5P_HDMI_BASE(0x0298) +#define S5P_ISRC1_DATA11 S5P_HDMI_BASE(0x029c) +#define S5P_ISRC1_DATA12 S5P_HDMI_BASE(0x02a0) +#define S5P_ISRC1_DATA13 S5P_HDMI_BASE(0x02a4) +#define S5P_ISRC1_DATA14 S5P_HDMI_BASE(0x02a8) +#define S5P_ISRC1_DATA15 S5P_HDMI_BASE(0x02ac) + +#define S5P_ISRC2_DATA0 S5P_HDMI_BASE(0x02b0) +#define S5P_ISRC2_DATA1 S5P_HDMI_BASE(0x02b4) +#define S5P_ISRC2_DATA2 S5P_HDMI_BASE(0x02b8) +#define S5P_ISRC2_DATA3 S5P_HDMI_BASE(0x02bc) +#define S5P_ISRC2_DATA4 S5P_HDMI_BASE(0x02c0) +#define S5P_ISRC2_DATA5 S5P_HDMI_BASE(0x02c4) +#define S5P_ISRC2_DATA6 S5P_HDMI_BASE(0x02c8) +#define S5P_ISRC2_DATA7 S5P_HDMI_BASE(0x02cc) +#define S5P_ISRC2_DATA8 S5P_HDMI_BASE(0x02d0) +#define S5P_ISRC2_DATA9 S5P_HDMI_BASE(0x02d4) +#define S5P_ISRC2_DATA10 S5P_HDMI_BASE(0x02d8) +#define S5P_ISRC2_DATA11 S5P_HDMI_BASE(0x02dc) +#define S5P_ISRC2_DATA12 S5P_HDMI_BASE(0x02e0) +#define S5P_ISRC2_DATA13 S5P_HDMI_BASE(0x02e4) +#define S5P_ISRC2_DATA14 S5P_HDMI_BASE(0x02e8) +#define S5P_ISRC2_DATA15 S5P_HDMI_BASE(0x02ec) + +#define S5P_AVI_CON S5P_HDMI_BASE(0x0300) +#define S5P_AVI_CHECK_SUM S5P_HDMI_BASE(0x0310) + +#define S5P_AVI_BYTE1 S5P_HDMI_BASE(0x0320) +#define S5P_AVI_BYTE2 S5P_HDMI_BASE(0x0324) +#define S5P_AVI_BYTE3 S5P_HDMI_BASE(0x0328) +#define S5P_AVI_BYTE4 S5P_HDMI_BASE(0x032c) +#define S5P_AVI_BYTE5 S5P_HDMI_BASE(0x0330) +#define S5P_AVI_BYTE6 S5P_HDMI_BASE(0x0334) +#define S5P_AVI_BYTE7 S5P_HDMI_BASE(0x0338) +#define S5P_AVI_BYTE8 S5P_HDMI_BASE(0x033c) +#define S5P_AVI_BYTE9 S5P_HDMI_BASE(0x0340) +#define S5P_AVI_BYTE10 S5P_HDMI_BASE(0x0344) +#define S5P_AVI_BYTE11 S5P_HDMI_BASE(0x0348) +#define S5P_AVI_BYTE12 S5P_HDMI_BASE(0x034c) +#define S5P_AVI_BYTE13 S5P_HDMI_BASE(0x0350) + +#define S5P_AUI_CON S5P_HDMI_BASE(0x0360) +#define S5P_AUI_CHECK_SUM S5P_HDMI_BASE(0x0370) + +#define S5P_AUI_BYTE1 S5P_HDMI_BASE(0x0380) +#define S5P_AUI_BYTE2 S5P_HDMI_BASE(0x0384) +#define S5P_AUI_BYTE3 S5P_HDMI_BASE(0x0388) +#define S5P_AUI_BYTE4 S5P_HDMI_BASE(0x038c) +#define S5P_AUI_BYTE5 S5P_HDMI_BASE(0x0390) + +#define S5P_MPG_CON S5P_HDMI_BASE(0x03A0) +#define S5P_MPG_CHECK_SUM S5P_HDMI_BASE(0x03B0) + +#define S5P_MPEG_BYTE1 S5P_HDMI_BASE(0x03c0) +#define S5P_MPEG_BYTE2 S5P_HDMI_BASE(0x03c4) +#define S5P_MPEG_BYTE3 S5P_HDMI_BASE(0x03c8) +#define S5P_MPEG_BYTE4 S5P_HDMI_BASE(0x03cc) +#define S5P_MPEG_BYTE5 S5P_HDMI_BASE(0x03d0) + +#define S5P_SPD_CON S5P_HDMI_BASE(0x0400) +#define S5P_SPD_HEADER0 S5P_HDMI_BASE(0x0410) +#define S5P_SPD_HEADER1 S5P_HDMI_BASE(0x0414) +#define S5P_SPD_HEADER2 S5P_HDMI_BASE(0x0418) + +#define S5P_SPD_DATA0 S5P_HDMI_BASE(0x0420) +#define S5P_SPD_DATA1 S5P_HDMI_BASE(0x0424) +#define S5P_SPD_DATA2 S5P_HDMI_BASE(0x0428) +#define S5P_SPD_DATA3 S5P_HDMI_BASE(0x042c) +#define S5P_SPD_DATA4 S5P_HDMI_BASE(0x0430) +#define S5P_SPD_DATA5 S5P_HDMI_BASE(0x0434) +#define S5P_SPD_DATA6 S5P_HDMI_BASE(0x0438) +#define S5P_SPD_DATA7 S5P_HDMI_BASE(0x043c) +#define S5P_SPD_DATA8 S5P_HDMI_BASE(0x0440) +#define S5P_SPD_DATA9 S5P_HDMI_BASE(0x0444) +#define S5P_SPD_DATA10 S5P_HDMI_BASE(0x0448) +#define S5P_SPD_DATA11 S5P_HDMI_BASE(0x044c) +#define S5P_SPD_DATA12 S5P_HDMI_BASE(0x0450) +#define S5P_SPD_DATA13 S5P_HDMI_BASE(0x0454) +#define S5P_SPD_DATA14 S5P_HDMI_BASE(0x0458) +#define S5P_SPD_DATA15 S5P_HDMI_BASE(0x045c) +#define S5P_SPD_DATA16 S5P_HDMI_BASE(0x0460) +#define S5P_SPD_DATA17 S5P_HDMI_BASE(0x0464) +#define S5P_SPD_DATA18 S5P_HDMI_BASE(0x0468) +#define S5P_SPD_DATA19 S5P_HDMI_BASE(0x046c) +#define S5P_SPD_DATA20 S5P_HDMI_BASE(0x0470) +#define S5P_SPD_DATA21 S5P_HDMI_BASE(0x0474) +#define S5P_SPD_DATA22 S5P_HDMI_BASE(0x0478) +#define S5P_SPD_DATA23 S5P_HDMI_BASE(0x048c) +#define S5P_SPD_DATA24 S5P_HDMI_BASE(0x0480) +#define S5P_SPD_DATA25 S5P_HDMI_BASE(0x0484) +#define S5P_SPD_DATA26 S5P_HDMI_BASE(0x0488) +#define S5P_SPD_DATA27 S5P_HDMI_BASE(0x048c) +#define S5P_HDMI_CSC_CON S5P_HDMI_BASE(0x0490) +#define S5P_HDMI_Y_G_COEF_L S5P_HDMI_BASE(0x04A0) +#define S5P_HDMI_Y_G_COEF_H S5P_HDMI_BASE(0x04A4) +#define S5P_HDMI_Y_B_COEF_L S5P_HDMI_BASE(0x04A8) +#define S5P_HDMI_Y_B_COEF_H S5P_HDMI_BASE(0x04AC) +#define S5P_HDMI_Y_R_COEF_L S5P_HDMI_BASE(0x04B0) +#define S5P_HDMI_Y_R_COEF_H S5P_HDMI_BASE(0x04B4) +#define S5P_HDMI_CB_G_COEF_L S5P_HDMI_BASE(0x04B8) +#define S5P_HDMI_CB_G_COEF_H S5P_HDMI_BASE(0x04BC) +#define S5P_HDMI_CB_B_COEF_L S5P_HDMI_BASE(0x04C0) +#define S5P_HDMI_CB_B_COEF_H S5P_HDMI_BASE(0x04C4) +#define S5P_HDMI_CB_R_COEF_L S5P_HDMI_BASE(0x04C8) +#define S5P_HDMI_CB_R_COEF_H S5P_HDMI_BASE(0x04CC) +#define S5P_HDMI_CR_G_COEF_L S5P_HDMI_BASE(0x04D0) +#define S5P_HDMI_CR_G_COEF_H S5P_HDMI_BASE(0x04D4) +#define S5P_HDMI_CR_B_COEF_L S5P_HDMI_BASE(0x04D8) +#define S5P_HDMI_CR_B_COEF_H S5P_HDMI_BASE(0x04DC) +#define S5P_HDMI_CR_R_COEF_L S5P_HDMI_BASE(0x04E0) +#define S5P_HDMI_CR_R_COEF_H S5P_HDMI_BASE(0x04E4) + +#define S5P_HDCP_RX_SHA1_0_0 S5P_HDMI_BASE(0x0600) +#define S5P_HDCP_RX_SHA1_0_1 S5P_HDMI_BASE(0x0604) +#define S5P_HDCP_RX_SHA1_0_2 S5P_HDMI_BASE(0x0608) +#define S5P_HDCP_RX_SHA1_0_3 S5P_HDMI_BASE(0x060C) +#define S5P_HDCP_RX_SHA1_1_0 S5P_HDMI_BASE(0x0610) +#define S5P_HDCP_RX_SHA1_1_1 S5P_HDMI_BASE(0x0614) +#define S5P_HDCP_RX_SHA1_1_2 S5P_HDMI_BASE(0x0618) +#define S5P_HDCP_RX_SHA1_1_3 S5P_HDMI_BASE(0x061C) +#define S5P_HDCP_RX_SHA1_2_0 S5P_HDMI_BASE(0x0620) +#define S5P_HDCP_RX_SHA1_2_1 S5P_HDMI_BASE(0x0624) +#define S5P_HDCP_RX_SHA1_2_2 S5P_HDMI_BASE(0x0628) +#define S5P_HDCP_RX_SHA1_2_3 S5P_HDMI_BASE(0x062C) +#define S5P_HDCP_RX_SHA1_3_0 S5P_HDMI_BASE(0x0630) +#define S5P_HDCP_RX_SHA1_3_1 S5P_HDMI_BASE(0x0634) +#define S5P_HDCP_RX_SHA1_3_2 S5P_HDMI_BASE(0x0638) +#define S5P_HDCP_RX_SHA1_3_3 S5P_HDMI_BASE(0x063C) +#define S5P_HDCP_RX_SHA1_4_0 S5P_HDMI_BASE(0x0640) +#define S5P_HDCP_RX_SHA1_4_1 S5P_HDMI_BASE(0x0644) +#define S5P_HDCP_RX_SHA1_4_2 S5P_HDMI_BASE(0x0648) +#define S5P_HDCP_RX_SHA1_4_3 S5P_HDMI_BASE(0x064C) +#define S5P_HDCP_RX_KSV_0_0 S5P_HDMI_BASE(0x0650) +#define S5P_HDCP_RX_KSV_0_1 S5P_HDMI_BASE(0x0654) +#define S5P_HDCP_RX_KSV_0_2 S5P_HDMI_BASE(0x0658) +#define S5P_HDCP_RX_KSV_0_3 S5P_HDMI_BASE(0x065C) +#define S5P_HDCP_RX_KSV_0_4 S5P_HDMI_BASE(0x0660) +#define S5P_HDCP_RX_KSV_LIST_CTRL S5P_HDMI_BASE(0x0664) +#define S5P_HDCP_AUTH_STATUS S5P_HDMI_BASE(0x0670) +#define S5P_HDCP_CTRL S5P_HDMI_BASE(0x0680) +#define S5P_HDCP_CHECK_RESULT S5P_HDMI_BASE(0x0690) + +#define S5P_HDCP_BKSV_0_0 S5P_HDMI_BASE(0x06A0) +#define S5P_HDCP_BKSV_0_1 S5P_HDMI_BASE(0x06A4) +#define S5P_HDCP_BKSV_0_2 S5P_HDMI_BASE(0x06A8) +#define S5P_HDCP_BKSV_0_3 S5P_HDMI_BASE(0x06AC) +#define S5P_HDCP_BKSV_1 S5P_HDMI_BASE(0x06B0) +#define S5P_HDCP_AKSV_0_0 S5P_HDMI_BASE(0x06C0) +#define S5P_HDCP_AKSV_0_1 S5P_HDMI_BASE(0x06C4) +#define S5P_HDCP_AKSV_0_2 S5P_HDMI_BASE(0x06C8) +#define S5P_HDCP_AKSV_0_3 S5P_HDMI_BASE(0x06CC) +#define S5P_HDCP_AKSV_1 S5P_HDMI_BASE(0x06D0) +#define S5P_HDCP_An_0_0 S5P_HDMI_BASE(0x06E0) +#define S5P_HDCP_An_0_1 S5P_HDMI_BASE(0x06E4) +#define S5P_HDCP_An_0_2 S5P_HDMI_BASE(0x06E8) +#define S5P_HDCP_An_0_3 S5P_HDMI_BASE(0x06EC) +#define S5P_HDCP_An_1_0 S5P_HDMI_BASE(0x06F0) +#define S5P_HDCP_An_1_1 S5P_HDMI_BASE(0x06F4) +#define S5P_HDCP_An_1_2 S5P_HDMI_BASE(0x06F8) +#define S5P_HDCP_An_1_3 S5P_HDMI_BASE(0x06FC) +#define S5P_HDCP_BCAPS S5P_HDMI_BASE(0x0700) +#define S5P_HDCP_BSTATUS_0 S5P_HDMI_BASE(0x0710) +#define S5P_HDCP_BSTATUS_1 S5P_HDMI_BASE(0x0714) +#define S5P_HDCP_Ri_0 S5P_HDMI_BASE(0x0740) +#define S5P_HDCP_Ri_1 S5P_HDMI_BASE(0x0744) +#define S5P_HDCP_Pj S5P_HDMI_BASE(0x0750) +#define S5P_HDCP_OFFSET_TX_0 S5P_HDMI_BASE(0x0760) +#define S5P_HDCP_OFFSET_TX_1 S5P_HDMI_BASE(0x0764) +#define S5P_HDCP_OFFSET_TX_2 S5P_HDMI_BASE(0x0768) +#define S5P_HDCP_OFFSET_TX_3 S5P_HDMI_BASE(0x076C) +#define S5P_HDCP_CYCLE_AA S5P_HDMI_BASE(0x0770) +#define S5P_TG_CMD S5P_HDMI_BASE(0x1000) +#define S5P_TG_H_FSZ_L S5P_HDMI_BASE(0x1018) +#define S5P_TG_H_FSZ_H S5P_HDMI_BASE(0x101C) +#define S5P_TG_HACT_ST_L S5P_HDMI_BASE(0x1020) +#define S5P_TG_HACT_ST_H S5P_HDMI_BASE(0x1024) +#define S5P_TG_HACT_SZ_L S5P_HDMI_BASE(0x1028) +#define S5P_TG_HACT_SZ_H S5P_HDMI_BASE(0x102C) +#define S5P_TG_V_FSZ_L S5P_HDMI_BASE(0x1030) +#define S5P_TG_V_FSZ_H S5P_HDMI_BASE(0x1034) +#define S5P_TG_VSYNC_L S5P_HDMI_BASE(0x1038) +#define S5P_TG_VSYNC_H S5P_HDMI_BASE(0x103C) +#define S5P_TG_VSYNC2_L S5P_HDMI_BASE(0x1040) +#define S5P_TG_VSYNC2_H S5P_HDMI_BASE(0x1044) +#define S5P_TG_VACT_ST_L S5P_HDMI_BASE(0x1048) +#define S5P_TG_VACT_ST_H S5P_HDMI_BASE(0x104C) +#define S5P_TG_VACT_SZ_L S5P_HDMI_BASE(0x1050) +#define S5P_TG_VACT_SZ_H S5P_HDMI_BASE(0x1054) +#define S5P_TG_FIELD_CHG_L S5P_HDMI_BASE(0x1058) +#define S5P_TG_FIELD_CHG_H S5P_HDMI_BASE(0x105C) +#define S5P_TG_VACT_ST2_L S5P_HDMI_BASE(0x1060) +#define S5P_TG_VACT_ST2_H S5P_HDMI_BASE(0x1064) +#define S5P_TG_VSYNC_TOP_HDMI_L S5P_HDMI_BASE(0x1078) +#define S5P_TG_VSYNC_TOP_HDMI_H S5P_HDMI_BASE(0x107C) +#define S5P_TG_VSYNC_BOT_HDMI_L S5P_HDMI_BASE(0x1080) +#define S5P_TG_VSYNC_BOT_HDMI_H S5P_HDMI_BASE(0x1084) +#define S5P_TG_FIELD_TOP_HDMI_L S5P_HDMI_BASE(0x1088) +#define S5P_TG_FIELD_TOP_HDMI_H S5P_HDMI_BASE(0x108C) +#define S5P_TG_FIELD_BOT_HDMI_L S5P_HDMI_BASE(0x1090) +#define S5P_TG_FIELD_BOT_HDMI_H S5P_HDMI_BASE(0x1094) +#define S5P_SPDIFIN_CLK_CTRL S5P_HDMI_BASE(0x5000) +#define S5P_SPDIFIN_OP_CTRL S5P_HDMI_BASE(0x5004) +#define S5P_SPDIFIN_IRQ_MASK S5P_HDMI_BASE(0x5008) +#define S5P_SPDIFIN_IRQ_STATUS S5P_HDMI_BASE(0x500C) +#define S5P_SPDIFIN_CONFIG_1 S5P_HDMI_BASE(0x5010) +#define S5P_SPDIFIN_CONFIG_2 S5P_HDMI_BASE(0x5014) +#define S5P_SPDIFIN_USER_VALUE_1 S5P_HDMI_BASE(0x5020) +#define S5P_SPDIFIN_USER_VALUE_2 S5P_HDMI_BASE(0x5024) +#define S5P_SPDIFIN_USER_VALUE_3 S5P_HDMI_BASE(0x5028) +#define S5P_SPDIFIN_USER_VALUE_4 S5P_HDMI_BASE(0x502C) +#define S5P_SPDIFIN_CH_STATUS_0_1 S5P_HDMI_BASE(0x5030) +#define S5P_SPDIFIN_CH_STATUS_0_2 S5P_HDMI_BASE(0x5034) +#define S5P_SPDIFIN_CH_STATUS_0_3 S5P_HDMI_BASE(0x5038) +#define S5P_SPDIFIN_CH_STATUS_0_4 S5P_HDMI_BASE(0x503C) +#define S5P_SPDIFIN_CH_STATUS_1 S5P_HDMI_BASE(0x5040) +#define S5P_SPDIFIN_FRAME_PERIOD_1 S5P_HDMI_BASE(0x5048) +#define S5P_SPDIFIN_FRAME_PERIOD_2 S5P_HDMI_BASE(0x504C) +#define S5P_SPDIFIN_Pc_INFO_1 S5P_HDMI_BASE(0x5050) +#define S5P_SPDIFIN_Pc_INFO_2 S5P_HDMI_BASE(0x5054) +#define S5P_SPDIFIN_Pd_INFO_1 S5P_HDMI_BASE(0x5058) +#define S5P_SPDIFIN_Pd_INFO_2 S5P_HDMI_BASE(0x505C) +#define S5P_SPDIFIN_DATA_BUF_0_1 S5P_HDMI_BASE(0x5060) +#define S5P_SPDIFIN_DATA_BUF_0_2 S5P_HDMI_BASE(0x5064) +#define S5P_SPDIFIN_DATA_BUF_0_3 S5P_HDMI_BASE(0x5068) +#define S5P_SPDIFIN_USER_BUF_0 S5P_HDMI_BASE(0x506C) +#define S5P_SPDIFIN_DATA_BUF_1_1 S5P_HDMI_BASE(0x5070) +#define S5P_SPDIFIN_DATA_BUF_1_2 S5P_HDMI_BASE(0x5074) +#define S5P_SPDIFIN_DATA_BUF_1_3 S5P_HDMI_BASE(0x5078) +#define S5P_SPDIFIN_USER_BUF_1 S5P_HDMI_BASE(0x507C) +#define S5P_HAES_CON S5P_HDMI_BASE(0x6000) +#define S5P_HAES_DATA_SIZE_L S5P_HDMI_BASE(0x6020) +#define S5P_HAES_DATA_SIZE_H S5P_HDMI_BASE(0x6024) +#define S5P_HAES_DATA S5P_HDMI_BASE(0x6030) + +#define HDMI_TPGEN_0 S5P_HDMI_BASE(0x500) +#define HDMI_TPGEN_1 S5P_HDMI_BASE(0x504) +#define HDMI_TPGEN_2 S5P_HDMI_BASE(0x508) +#define HDMI_TPGEN_3 S5P_HDMI_BASE(0x50c) +#define HDMI_TPGEN_4 S5P_HDMI_BASE(0x510) +#define HDMI_TPGEN_5 S5P_HDMI_BASE(0x514) +#define HDMI_TPGEN_6 S5P_HDMI_BASE(0x518) + +#define BLUE_SCR_EN (1<<5) +#define BLUE_SCR_DIS (0<<5) +#define ASP_EN (1<<2) +#define ASP_DIS (0<<2) +#define PWDN_ENB_NORMAL (1<<1) +#define PWDN_ENB_PD (0<<1) +#define HDMI_EN (1<<0) +#define HDMI_DIS (~HDMI_EN) + +#define PX_LMT_CTRL_BYPASS (0<<5) +#define PX_LMT_CTRL_RGB (1<<5) +#define PX_LMT_CTRL_YPBPR (2<<5) +#define PX_LMT_CTRL_RESERVED (3<<5) + +#define VID_PREAMBLE_EN (0<<5) +#define VID_PREAMBLE_DIS (1<<5) +#define GUARD_BAND_EN (0<<1) +#define GUARD_BAND_DIS (1<<1) + + +#define AUTHEN_ACK_AUTH (1<<7) +#define AUTHEN_ACK_NOT (0<<7) +#define AUD_FIFO_OVF_FULL (1<<6) +#define AUD_FIFO_OVF_NOT (0<<6) +#define UPDATE_RI_INT_OCC (1<<4) +#define UPDATE_RI_INT_NOT (0<<4) +#define UPDATE_RI_INT_CLEAR (1<<4) +#define UPDATE_PJ_INT_OCC (1<<3) +#define UPDATE_PJ_INT_NOT (0<<3) +#define UPDATE_PJ_INT_CLEAR (1<<3) +#define EXCHANGEKSV_INT_OCC (1<<2) +#define EXCHANGEKSV_INT_NOT (0<<2) +#define EXCHANGEKSV_INT_CLEAR (1<<2) +#define WATCHDOG_INT_OCC (1<<1) +#define WATCHDOG_INT_NOT (0<<1) +#define WATCHDOG_INT_CLEAR (1<<1) +#define WTFORACTIVERX_INT_OCC (1) +#define WTFORACTIVERX_INT_NOT (0) +#define WTFORACTIVERX_INT_CLEAR (1) + +#define AUD_FIFO_OVF_EN (1<<6) +#define AUD_FIFO_OVF_DIS (0<<6) +#define UPDATE_RI_INT_EN (1<<4) +#define UPDATE_RI_INT_DIS (0<<4) +#define UPDATE_PJ_INT_EN (1<<3) +#define UPDATE_PJ_INT_DIS (0<<3) +#define EXCHANGEKSV_INT_EN (1<<2) +#define EXCHANGEKSV_INT_DIS (0<<2) +#define WATCHDOG_INT_EN (1<<1) +#define WATCHDOG_INT_DIS (0<<1) +#define WTFORACTIVERX_INT_EN (1) +#define WTFORACTIVERX_INT_DIS (0) +#define HDCP_STATUS_EN_ALL (UPDATE_RI_INT_EN|\ + UPDATE_PJ_INT_DIS|\ + EXCHANGEKSV_INT_EN|\ + WATCHDOG_INT_EN|\ + WTFORACTIVERX_INT_EN) + +#define HDCP_STATUS_DIS_ALL (~0x1f) + +#define SW_HPD_PLUGGED (1<<1) +#define SW_HPD_UNPLUGGED (0<<1) + +#define HDMI_MODE_EN (1<<1) +#define HDMI_MODE_DIS (0<<1) +#define DVI_MODE_EN (1) +#define DVI_MODE_DIS (0) + +#define HDCP_ENC_ENABLE (1) +#define HDCP_ENC_DISABLE (0) + +#define SET_BLUESCREEN_0(a) (0xff&(a)) + +#define SET_BLUESCREEN_1(a) (0xff&(a)) + +#define SET_BLUESCREEN_2(a) (0xff&(a)) + +#define SET_HDMI_YMAX(a) (0xff&(a)) + +#define SET_HDMI_YMIN(a) (0xff&(a)) + +#define SET_HDMI_CMAX(a) (0xff&(a)) + +#define SET_HDMI_CMIN(a) (0xff&(a)) + + +#define SET_VBI_ST_MG(a) (0xff&(a)) + +#define SET_VBI_END_MG(a) (0xff&(a)) + +#define SET_VACT_ST_MG(a) (0xff&(a)) + + +#define SET_H_BLANK_L(a) (0xff&(a)) + +#define SET_H_BLANK_H(a) (0x7&((a)>>8)) + +#define SET_V2_BLANK_L(a) (0xff&(a)) + +#define SET_V1_BLANK_L(a) ((0x1f&(a))<<3) +#define SET_V2_BLANK_H(a) (0x7&((a)>>8)) + +#define SET_V1_BLANK_H(a) (0x3f&((a)>>5)) + +#define SET_V_LINE_L(a) (0xff&(a)) + +#define SET_H_LINE_L(a) ((0xf&(a))<<4) +#define SET_V_LINE_H(a) (0xf&((a)>>8)) + +#define SET_H_LINE_H(a) (0xff&((a)>>4)) + +#define V_SYNC_POL_ACT_LOW (1) +#define V_SYNC_POL_ACT_HIGH (0) + +#define INT_PRO_MODE_INTERLACE (1) +#define INT_PRO_MODE_PROGRESSIVE (0) + +#define SET_V_BOT_ST_L(a) (0xff&(a)) + +#define SET_V_BOT_END_L(a) ((0x1f&(a))<<3) +#define SET_V_BOT_ST_H(a) (0x7&((a)>>8)) + +#define SET_V_BOT_END_H(a) (0x3f&((a)>>5)) + + +#define SET_HSYNC_START_L(a) (0xff&(a)) + +#define SET_HSYNC_END_L(a) ((0x3f&(a))<<2) +#define SET_HSYNC_START_H(a) (0x3&((a)>>8)) + +#define SET_HSYNC_POL_ACT_LOW (1<<4) +#define SET_HSYNC_POL_ACT_HIGH (0<<4) +#define SET_HSYNC_END_H(a) (0xf&((a)>>6)) + +#define SET_VSYNC_T_END_L(a) (0xff&(a)) + +#define SET_VSYNC_T_ST_L(a) ((0xf&(a))<<4) +#define SET_VSYNC_T_END_H(a) (0xf&((a)>>8)) + +#define SET_VSYNC_T_ST_H(a) (0xff&((a)>>4)) + +#define SET_VSYNC_B_END_L(a) (0xff&(a)) + +#define SET_VSYNC_B_ST_L(a) ((0xf&(a))<<4) +#define SET_VSYNC_B_END_H(a) (0xf&((a)>>8)) + +#define SET_VSYNC_B_ST_H(a) (0xff&((a)>>4)) + + +#define SET_VSYNC_H_POST_END_L(a) (0xff&(a)) + +#define SET_VSYNC_H_POST_ST_L(a) ((0xf&(a))<<4) +#define SET_VSYNC_H_POST_END_H(a) (0xf&((a)>>8)) + +#define SET_VSYNC_H_POST_ST_H(a) (0xff&((a)>>4)) + + +#define SACD_EN (1<<5) +#define SACD_DIS (0<<5) +#define AUD_MODE_MULTI_CH (1<<4) +#define AUD_MODE_2_CH (0<<4) +#define SET_SP_PRE(a) (0xf&(a)) + +#define SET_SP_FLAT(a) (0xf&(a)) + + +#define SPK3R_SEL_I_PCM0L (0<<27) +#define SPK3R_SEL_I_PCM0R (1<<27) +#define SPK3R_SEL_I_PCM1L (2<<27) +#define SPK3R_SEL_I_PCM1R (3<<27) +#define SPK3R_SEL_I_PCM2L (4<<27) +#define SPK3R_SEL_I_PCM2R (5<<27) +#define SPK3R_SEL_I_PCM3L (6<<27) +#define SPK3R_SEL_I_PCM3R (7<<27) +#define SPK3L_SEL_I_PCM0L (0<<24) +#define SPK3L_SEL_I_PCM0R (1<<24) +#define SPK3L_SEL_I_PCM1L (2<<24) +#define SPK3L_SEL_I_PCM1R (3<<24) +#define SPK3L_SEL_I_PCM2L (4<<24) +#define SPK3L_SEL_I_PCM2R (5<<24) +#define SPK3L_SEL_I_PCM3L (6<<24) +#define SPK3L_SEL_I_PCM3R (7<<24) +#define SPK2R_SEL_I_PCM0L (0<<19) +#define SPK2R_SEL_I_PCM0R (1<<19) +#define SPK2R_SEL_I_PCM1L (2<<19) +#define SPK2R_SEL_I_PCM1R (3<<19) +#define SPK2R_SEL_I_PCM2L (4<<19) +#define SPK2R_SEL_I_PCM2R (5<<19) +#define SPK2R_SEL_I_PCM3L (6<<19) +#define SPK2R_SEL_I_PCM3R (7<<19) +#define SPK2L_SEL_I_PCM0L (0<<16) +#define SPK2L_SEL_I_PCM0R (1<<16) +#define SPK2L_SEL_I_PCM1L (2<<16) +#define SPK2L_SEL_I_PCM1R (3<<16) +#define SPK2L_SEL_I_PCM2L (4<<16) +#define SPK2L_SEL_I_PCM2R (5<<16) +#define SPK2L_SEL_I_PCM3L (6<<16) +#define SPK2L_SEL_I_PCM3R (7<<16) +#define SPK1R_SEL_I_PCM0L (0<<11) +#define SPK1R_SEL_I_PCM0R (1<<11) +#define SPK1R_SEL_I_PCM1L (2<<11) +#define SPK1R_SEL_I_PCM1R (3<<11) +#define SPK1R_SEL_I_PCM2L (4<<11) +#define SPK1R_SEL_I_PCM2R (5<<11) +#define SPK1R_SEL_I_PCM3L (6<<11) +#define SPK1R_SEL_I_PCM3R (7<<11) +#define SPK1L_SEL_I_PCM0L (0<<8) +#define SPK1L_SEL_I_PCM0R (1<<8) +#define SPK1L_SEL_I_PCM1L (2<<8) +#define SPK1L_SEL_I_PCM1R (3<<8) +#define SPK1L_SEL_I_PCM2L (4<<8) +#define SPK1L_SEL_I_PCM2R (5<<8) +#define SPK1L_SEL_I_PCM3L (6<<8) +#define SPK1L_SEL_I_PCM3R (7<<8) +#define SPK0R_SEL_I_PCM0L (0<<3) +#define SPK0R_SEL_I_PCM0R (1<<3) +#define SPK0R_SEL_I_PCM1L (2<<3) +#define SPK0R_SEL_I_PCM1R (3<<3) +#define SPK0R_SEL_I_PCM2L (4<<3) +#define SPK0R_SEL_I_PCM2R (5<<3) +#define SPK0R_SEL_I_PCM3L (6<<3) +#define SPK0R_SEL_I_PCM3R (7<<3) +#define SPK0L_SEL_I_PCM0L (0) +#define SPK0L_SEL_I_PCM0R (1) +#define SPK0L_SEL_I_PCM1L (2) +#define SPK0L_SEL_I_PCM1R (3) +#define SPK0L_SEL_I_PCM2L (4) +#define SPK0L_SEL_I_PCM2R (5) +#define SPK0L_SEL_I_PCM3L (6) +#define SPK0L_SEL_I_PCM3R (7) + +#define ALT_CTS_RATE_CTS_1 (0<<3) +#define ALT_CTS_RATE_CTS_11 (1<<3) +#define ALT_CTS_RATE_CTS_21 (2<<3) +#define ALT_CTS_RATE_CTS_31 (3<<3) +#define ACR_TX_MODE_NO_TX (0) +#define ACR_TX_MODE_TX_ONCE (1) +#define ACR_TX_MODE_TXCNT_VBI (2) +#define ACR_TX_MODE_TX_VPC (3) +#define ACR_TX_MODE_MESURE_CTS (4) + + +#define SET_ACR_MCTS(a) (0xfffff&(a)) + + +#define SET_ACR_CTS(a) (0xfffff&(a)) + + +#define SET_ACR_N(a) (0xfffff&(a)) + +#define SET_ACR_LSB2(a) (0xff&(a)) + +#define SET_ACR_TXCNT(a) (0x1f&(a)) + +#define SET_ACR_TX_INTERNAL(a) (0xff&(a)) + +#define SET_ACR_CTS_OFFSET(a) (0xff&(a)) + +#define GCP_CON_NO_TRAN (0) +#define GCP_CON_TRANS_ONCE (1) +#define GCP_CON_TRANS_EVERY_VSYNC (2) + +#define SET_GCP_BYTE1(a) (0xff&(a)) + + +#define SET_ACP_FR_RATE(a) ((0x1f&(a))<<3) +#define ACP_CON_NO_TRAN (0) +#define ACP_CON_TRANS_ONCE (1) +#define ACP_CON_TRANS_EVERY_VSYNC (2) + +#define SET_ACP_TYPE(a) (0xff&(a)) + +#define SET_ACP_DATA(a) (0xff&(a)) + +#define SET_ISRC_FR_RATE(a) ((0x1f&(a))<<3) +#define ISRC_EN (1<<2) +#define ISRC_DIS (0<<2) +#define ISRC_TX_CON_NO_TRANS (0) +#define ISRC_TX_CON_TRANS_ONCE (1) +#define ISRC_TX_CON_TRANS_EVERY_VSYNC (2) + +#define SET_ISRC1_HEADER(a) (0xff&(a)) + +#define SET_ISRC1_DATA(a) (0xff&(a)) + +#define SET_ISRC2_DATA(a) (0xff&(a)) + + +#define AVI_TX_CON_NO_TRANS (0) +#define AVI_TX_CON_TRANS_ONCE (1) +#define AVI_TX_CON_TRANS_EVERY_VSYNC (2) + + +#define SET_AVI_CHECK_SUM(a) (0xff&(a)) + +#define SET_AVI_BYTE(a) (0xff&(a)) + + +#define AUI_TX_CON_NO_TRANS (0) +#define AUI_TX_CON_TRANS_ONCE (1) +#define AUI_TX_CON_TRANS_EVERY_VSYNC (2) + + +#define SET_AUI_CHECK_SUM(a) (0xff&(a)) + +#define SET_AUI_BYTE(a) (0xff&(a)) + + +#define MPG_TX_CON_NO_TRANS (0) +#define MPG_TX_CON_TRANS_ONCE (1) +#define MPG_TX_CON_TRANS_EVERY_VSYNC (2) + + +#define SET_MPG_CHECK_SUM(a) (0xff&(a)) + + +#define SET_MPG_BYTE(a) (0xff&(a)) + + +#define SPD_TX_CON_NO_TRANS (0) +#define SPD_TX_CON_TRANS_ONCE (1) +#define SPD_TX_CON_TRANS_EVERY_VSYNC (2) + + +#define SET_SPD_HEADER(a) (0xff&(a)) + +#define SET_SPD_DATA(a) (0xff&(a)) + + +#define OUT_OFFSET_SEL_RGB_FR (0<<4) +#define OUT_OFFSET_SEL_RGB_LR (2<<4) +#define OUT_OFFSET_SEL_YCBCR (3<<4) +#define IN_CLIP_EN (1<<2) +#define IN_CLIP_DIS (0<<2) +#define IN_OFFSET_SEL_RGB_FR (0) +#define IN_OFFSET_SEL_RGB_LR (2) +#define IN_OFFSET_SEL_YCBCR (3) + +#define SET_HDMI_CSC_COEF_L(a) (0xff&(a)) +#define SET_HDMI_CSC_COEF_H(a) (0x3&((a)>>8)) + +#define SET_HDMI_SHA1(a) (0xff&(a)) + +#define GETSYNC_TYPE_EN (1<<4) +#define GETSYNC_TYPE_DIS (0<<4) +#define GETSYNC_EN (1<<3) +#define GETSYNC_DIS (0<<3) +#define FIELD_EN (1<<2) +#define FIELD_DIS (0<<2) +#define TG_EN (1) +#define TG_DIS (0) + +#define SET_TG_H_FSZ_L(a) (0xff&(a)) + +#define SET_TG_H_FSZ_H(a) (0x1f&((a)>>8)) + +#define SET_TG_HACT_ST_L(a) (0xff&(a)) + +#define SET_TG_HACT_ST_H(a) (0xf&((a)>>8)) + +#define SET_TG_HACT_SZ_L(a) (0xff&(a)) + +#define SET_TG_HACT_SZ_H(a) (0xf&((a)>>8)) + +#define SET_TG_V_FSZ_L(a) (0xff&(a)) + +#define SET_TG_V_FSZ_H(a) (0x7&((a)>>8)) + +#define SET_TG_VSYNC_L(a) (0xff&(a)) + +#define SET_TG_VSYNC_H(a) (0x7&((a)>>8)) + +#define SET_TG_VSYNC2_L(a) (0xff&(a)) + +#define SET_TG_VSYNC2_H(a) (0x7&((a)>>8)) + +#define SET_TG_VACT_ST_L(a) (0xff&(a)) + +#define SET_TG_VACT_ST_H(a) (0x7&((a)>>8)) + +#define SET_TG_VACT_SZ_L(a) (0xff&(a)) + +#define SET_TG_VACT_SZ_H(a) (0x7&((a)>>8)) + +#define SET_TG_FIELD_CHG_L(a) (0xff&(a)) + +#define SET_TG_FIELD_CHG_H(a) (0x7&((a)>>8)) + +#define SET_TG_VACT_ST2_L(a) (0xff&(a)) + +#define SET_TG_VACT_ST2_H(a) (0x7&((a)>>8)) + +#define SET_TG_VSYNC_TOP_HDMI_L(a) (0xff&(a)) + +#define SET_TG_VSYNC_TOP_HDMI_H(a) (0x7&((a)>>8)) + +#define SET_TG_VSYNC_BOT_HDMI_L(a) (0xff&(a)) + +#define SET_TG_VSYNC_BOT_HDMI_H(a) (0x7&((a)>>8)) + +#define SET_TG_FIELD_TOP_HDMI_L(a) (0xff&(a)) + +#define SET_TG_FIELD_TOP_HDMI_H(a) (0x7&((a)>>8)) + +#define SET_TG_FIELD_BOT_HDMI_L(a) (0xff&(a)) + +#define SET_TG_FIELD_BOT_HDMI_H(a) (0x7&((a)>>8)) + + +#define IRQ_WRONG_SIGNAL_ENABLE (1<<0) +#define IRQ_CH_STATUS_RECOVERED_ENABLE (1<<1) +#define IRQ_WRONG_PREAMBLE_ENABLE (1<<2) +#define IRQ_STREAM_HEADER_NOT_DETECTED_ENABLE (1<<3) +#define IRQ_STREAM_HEADER_DETECTED_ENABLE (1<<4) +#define IRQ_STREAM_HEADER_NOT_DETECTED_AT_RIGHTTIME_ENABLE (1<<5) +#define IRQ_ABNORMAL_PD_ENABLE (1<<6) +#define IRQ_BUFFER_OVERFLOW_ENABLE (1<<7) + +#define CONFIG_FILTER_3_SAMPLE (0<<6) +#define CONFIG_FILTER_2_SAMPLE (1<<6) +#define CONFIG_LINEAR_PCM_TYPE (0<<5) +#define CONFIG_NON_LINEAR_PCM_TYPE (1<<5) +#define CONFIG_PCPD_AUTO_SET (0<<4) +#define CONFIG_PCPD_MANUAL_SET (1<<4) +#define CONFIG_WORD_LENGTH_AUTO_SET (0<<3) +#define CONFIG_WORD_LENGTH_MANUAL_SET (1<<3) +#define CONFIG_U_V_C_P_NEGLECT (0<<2) +#define CONFIG_U_V_C_P_REPORT (1<<2) +#define CONFIG_BURST_SIZE_1 (0<<1) +#define CONFIG_BURST_SIZE_2 (1<<1) +#define CONFIG_DATA_ALIGN_16BIT (0<<0) +#define CONFIG_DATA_ALIGN_32BIT (1<<0) + + +#define AUTHEN_ACK_POS 7 +#define AUD_FIFO_OVF_POS 6 + +#define UPDATE_RI_INT_POS 4 +#define UPDATE_PJ_INT_POS 3 +#define EXCHANGEKSV_INT_POS 2 +#define WATCHDOG_INT_POS 1 +#define WTFORACTIVERX_INT_POS 0 + +#define AUTHENTICATED (0x1<<7) +#define NOT_YET_AUTHENTICATED (0x0<<7) +#define AUD_FIFO_OVF_INT_OCCURRED (0x1<<6) +#define AUD_FIFO_OVF_INT_NOT_OCCURRED (0x0<<6) + +#define UPDATE_RI_INT_OCCURRED (0x1<<4) +#define UPDATE_RI_INT_NOT_OCCURRED (0x0<<4) +#define UPDATE_PJ_INT_OCCURRED (0x1<<3) +#define UPDATE_PJ_INT_NOT_OCCURRED (0x0<<3) +#define EXCHANGEKSV_INT_OCCURRED (0x1<<2) +#define EXCHANGEKSV_INT_NOT_OCCURRED (0x0<<2) +#define WATCHDOG_INT_OCCURRED (0x1<<1) +#define WATCHDOG_INT_NOT_OCCURRED (0x0<<1) +#define WTFORACTIVERX_INT_OCCURRED (0x1<<0) +#define WTFORACTIVERX_INT_NOT_OCCURRED (0x0<<0) + +#define AUD_FIFO_OVF_INT_EN (0x1<<6) +#define AUD_FIFO_OVF_INT_DIS (0x0<<6) + + + +#define EN_PJ_EN (0x1<<4) +#define EN_PJ_DIS (~EN_PJ_EN) + +#define SET_REPEATER_TIMEOUT (0x1<<2) +#define CLEAR_REPEATER_TIMEOUT (~SET_REPEATER_TIMEOUT) +#define CP_DESIRED_EN (0x1<<1) +#define CP_DESIRED_DIS (~CP_DESIRED_EN) +#define ENABLE_1_DOT_1_FEATURE_EN (0x1<<0) +#define ENABLE_1_DOT_1_FEATURE_DIS (~ENABLE_1_DOT_1_FEATURE_EN) + +#define Pi_MATCH_RESULT__YES ((0x1<<3)<<(0x1<<2)) +#define Pi_MATCH_RESULT__NO ((0x1<<3)<<(0x0<<2)) +#define Ri_MATCH_RESULT__YES ((0x1<<1)<<(0x1<<0)) +#define Ri_MATCH_RESULT__NO ((0x1<<1)<<(0x0<<0)) +#define CLEAR_ALL_RESULTS 0x0 + +#define HDCP_ENC_DIS (0x0<<0) + +#define REPEATER_SET (0x1<<6) +#define REPEATERP_CLEAR (0x1<<6) +#define READY_SET (0x1<<5) +#define READY_CLEAR (0x1<<5) +#define FAST_SET (0x1<<4) +#define FAST_CLEAR (0x1<<4) + +#define ONE_DOT_ONE_FEATURES_SET (0x1<<1) +#define ONE_DOT_ONE_FEATURES_CLEAR (0x1<<1) +#define FAST_REAUTHENTICATION_SET (0x1<<0) +#define FAST_REAUTHENTICATION_CLEAR (0x1<<0) + + +#define SCRAMBLER_KEY_START_EN (0x1<<7) +#define SCRAMBLER_KEY_START_DIS (~SCRAMBLER_KEY_START_EN) +#define SCRAMBLER_KEY_DONE (0x1<<6) +#define SCRAMBLER_KEY_GENERATING (0x0<<6) +#define HAES_START_EN (0x1<<0) +#define HAES_DECRYPTION_DONE (0x0<<0) + + +#define AN_SIZE 8 +#define AKSV_SIZE 5 +#define BKSV_SIZE 5 +#define HDCPLink_Addr 0x74 + + +#define CABLE_PLUGGED (1<<1) +#define CABLE_UNPLUGGED (0<<1) + +#define DDC_Addr 0xA0 +#define eDDC_Addr 0x60 +#define HDCPLink_Addr 0x74 + +#define HDCP_Bksv 0x00 +#define HDCP_Aksv 0x10 +#define HDCP_Ainfo 0x15 +#define HDCP_An 0x18 +#define HDCP_Ri 0x08 +#define HDCP_Bcaps 0x40 +#define HDCP_BStatus 0x41 +#define HDCP_Pj 0x0a + +#define HDCP_KSVFIFO 0x43 +#define HDCP_SHA1 0x20 + +#define HDMI_MODE_HDMI 0 +#define HDMI_MODE_DVI 1 + +#define EDID_SEGMENT_ID 0x60 +#define EDID_SEGMENT0 0x00 +#define EDID_SEGMENT1 0x01 + +#define EDID_DEVICE_ID 0xA0 +#define EDID_ADDR_START 0x00 +#define EDID_ADDR_EXT 0x80 +#define EDID_RCOUNT 127 + +#define EDID_POS_EXTENSION 0x7E +#define EDID_POS_CHECKSUM 0x7F +#define VALID_EDID 0xA5 +#define NO_VALID_EDID 0 + +#define EDID_POS_RBUFFER0 0x00 +#define EDID_POS_RBUFFER1 0x80 +#define EDID_POS_RBUFFER2 0x100 +#define EDID_POS_RBUFFER3 0x180 + +#define EDID_TIMING_EXT_TAG_ADDR_POS 0x80 +#define EDID_TIMING_EXT_REV_NUMBER 0x81 +#define EDID_DETAILED_TIMING_OFFSET_POS 0x82 +#define EDID_COLOR_SPACE_ADDR 0x83 +#define EDID_DATA_BLOCK_ADDRESS 0x84 +#define EDID_TIMING_EXT_TAG_VAL 0x02 +#define EDID_YCBCR444_CS_MASK 0x20 +#define EDID_YCBCR422_CS_MASK 0x10 +#define EDID_TAG_CODE_MASK 0xE0 +#define EDID_DATA_BLOCK_SIZE_MASK 0x1F +#define EDID_NATIVE_RESOLUTION_MASK 0x80 + +#define EDID_SHORT_AUD_DEC_TAG 0x20 +#define EDID_SHORT_VID_DEC_TAG 0x40 +#define EDID_HDMI_VSDB_TAG 0x60 +#define EDID_SPEAKER_ALLOCATION_TAG 0x80 + +#define COLOR_SPACE_RGB 0 +#define COLOR_SPACE_YCBCR444 1 +#define COLOR_SPACE_YCBCR422 2 + +#define SHORT_VID_720_480P_4_3_NT 0x01 +#define SHORT_VID_720_480P_16_9_NT 0x02 +#define SHORT_VID_1280_720P_16_9_NT 0x04 +#define SHORT_VID_1920_1080i_16_9_NT 0x08 +#define SHORT_VID_720_576P_4_3_PAL 0x10 +#define SHORT_VID_720_576P_16_9_PAL 0x20 +#define SHORT_VID_1280_720P_16_9_PAL 0x40 +#define SHORT_VID_1920_1080i_16_9_PAL 0x80 + +#define SET_HDMI_RESOLUTION_480P 0x00 +#define SET_HDMI_RESOLUTION_720P 0x01 +#define SET_HDMI_RESOLUTION_1080i 0x02 + + +#define HDMI_WAIT_TIMEOUT 20 +#define AUTHENTICATION_SUCCESS 0 +#define AUTHENTICATION_FAILURE 1 +#define AUTHENTICATION_FAIL_CNT 2 + + +#define HDCP_MAX_DEVS 128 +#define HDCP_KSV_SIZE 5 + +#define CMD_IIC_ADDRMODE_CHANGE 0xFF + +#define IIC_ADDRMODE_1 0 +#define IIC_ADDRMODE_2 1 +#define IIC_ADDRMODE_3 2 +#define HDMI_IIC_ADDRMODE IIC_ADDRMODE_1 + +#define IIC_ACK 0 +#define IIC_NOACK 1 + +#define EDID_POS_ERROR 512 +#define R_VAL_RETRY_CNT 5 + +#define CABLE_INSERT 1 +#define CABLE_REMOVE (~CABLE_INSERT) + +#endif + + diff --git a/drivers/media/video/samsung/tv20/s5pc100/regs/regs-sdaout.h b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-sdaout.h new file mode 100644 index 0000000..02dacd0 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-sdaout.h @@ -0,0 +1,455 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-sdout.h + * + * TV Encoder register header file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_SDAOUT_H + +#include <mach/map.h> + +#define S5P_SDAOUT_BASE(x) (x) + +#define S5P_SDO_CLKCON S5P_SDAOUT_BASE(0x0000) +#define S5P_SDO_CONFIG S5P_SDAOUT_BASE(0x0008) +#define S5P_SDO_SCALE S5P_SDAOUT_BASE(0x000C) +#define S5P_SDO_SYNC S5P_SDAOUT_BASE(0x0010) +#define S5P_SDO_VBI S5P_SDAOUT_BASE(0x0014) +#define S5P_SDO_SCALE_CH0 S5P_SDAOUT_BASE(0x001C) +#define S5P_SDO_SCALE_CH1 S5P_SDAOUT_BASE(0x0020) +#define S5P_SDO_SCALE_CH2 S5P_SDAOUT_BASE(0x0024) +#define S5P_SDO_YCDELAY S5P_SDAOUT_BASE(0x0034) +#define S5P_SDO_SCHLOCK S5P_SDAOUT_BASE(0x0038) +#define S5P_SDO_DAC S5P_SDAOUT_BASE(0x003C) +#define S5P_SDO_FINFO S5P_SDAOUT_BASE(0x0040) +#define S5P_SDO_Y0 S5P_SDAOUT_BASE(0x0044) +#define S5P_SDO_Y1 S5P_SDAOUT_BASE(0x0048) +#define S5P_SDO_Y2 S5P_SDAOUT_BASE(0x004C) +#define S5P_SDO_Y3 S5P_SDAOUT_BASE(0x0050) +#define S5P_SDO_Y4 S5P_SDAOUT_BASE(0x0054) +#define S5P_SDO_Y5 S5P_SDAOUT_BASE(0x0058) +#define S5P_SDO_Y6 S5P_SDAOUT_BASE(0x005C) +#define S5P_SDO_Y7 S5P_SDAOUT_BASE(0x0060) +#define S5P_SDO_Y8 S5P_SDAOUT_BASE(0x0064) +#define S5P_SDO_Y9 S5P_SDAOUT_BASE(0x0068) +#define S5P_SDO_Y10 S5P_SDAOUT_BASE(0x006C) +#define S5P_SDO_Y11 S5P_SDAOUT_BASE(0x0070) +#define S5P_SDO_CB0 S5P_SDAOUT_BASE(0x0080) +#define S5P_SDO_CB1 S5P_SDAOUT_BASE(0x0084) +#define S5P_SDO_CB2 S5P_SDAOUT_BASE(0x0088) +#define S5P_SDO_CB3 S5P_SDAOUT_BASE(0x008C) +#define S5P_SDO_CB4 S5P_SDAOUT_BASE(0x0090) +#define S5P_SDO_CB5 S5P_SDAOUT_BASE(0x0094) +#define S5P_SDO_CB6 S5P_SDAOUT_BASE(0x0098) +#define S5P_SDO_CB7 S5P_SDAOUT_BASE(0x009C) +#define S5P_SDO_CB8 S5P_SDAOUT_BASE(0x00A0) +#define S5P_SDO_CB9 S5P_SDAOUT_BASE(0x00A4) +#define S5P_SDO_CB10 S5P_SDAOUT_BASE(0x00A8) +#define S5P_SDO_CB11 S5P_SDAOUT_BASE(0x00AC) +#define S5P_SDO_CR0 S5P_SDAOUT_BASE(0x00C0) +#define S5P_SDO_CR1 S5P_SDAOUT_BASE(0x00C4) +#define S5P_SDO_CR2 S5P_SDAOUT_BASE(0x00C8) +#define S5P_SDO_CR3 S5P_SDAOUT_BASE(0x00CC) +#define S5P_SDO_CR4 S5P_SDAOUT_BASE(0x00D0) +#define S5P_SDO_CR5 S5P_SDAOUT_BASE(0x00D4) +#define S5P_SDO_CR6 S5P_SDAOUT_BASE(0x00D8) +#define S5P_SDO_CR7 S5P_SDAOUT_BASE(0x00DC) +#define S5P_SDO_CR8 S5P_SDAOUT_BASE(0x00E0) +#define S5P_SDO_CR9 S5P_SDAOUT_BASE(0x00E4) +#define S5P_SDO_CR10 S5P_SDAOUT_BASE(0x00E8) +#define S5P_SDO_CR11 S5P_SDAOUT_BASE(0x00EC) +#define S5P_SDO_MV_ON S5P_SDAOUT_BASE(0x0100) +#define S5P_SDO_MV_SLINE_FIRST_EVEN S5P_SDAOUT_BASE(0x0104) +#define S5P_SDO_MV_SLINE_FIRST_SPACE_EVEN S5P_SDAOUT_BASE(0x0108) +#define S5P_SDO_MV_SLINE_FIRST_ODD S5P_SDAOUT_BASE(0x010C) +#define S5P_SDO_MV_SLINE_FIRST_SPACE_ODD S5P_SDAOUT_BASE(0x0110) +#define S5P_SDO_MV_SLINE_SPACING S5P_SDAOUT_BASE(0x0114) +#define S5P_SDO_MV_STRIPES_NUMBER S5P_SDAOUT_BASE(0x0118) +#define S5P_SDO_MV_STRIPES_THICKNESS S5P_SDAOUT_BASE(0x011C) +#define S5P_SDO_MV_PSP_DURATION S5P_SDAOUT_BASE(0x0120) +#define S5P_SDO_MV_PSP_FIRST S5P_SDAOUT_BASE(0x0124) +#define S5P_SDO_MV_PSP_SPACING S5P_SDAOUT_BASE(0x0128) +#define S5P_SDO_MV_SEL_LINE_PSP_AGC S5P_SDAOUT_BASE(0x012C) +#define S5P_SDO_MV_SEL_FORMAT_PSP_AGC S5P_SDAOUT_BASE(0x0130) +#define S5P_SDO_MV_PSP_AGC_A_ON S5P_SDAOUT_BASE(0x0134) +#define S5P_SDO_MV_PSP_AGC_B_ON S5P_SDAOUT_BASE(0x0138) +#define S5P_SDO_MV_BACK_PORCH S5P_SDAOUT_BASE(0x013C) +#define S5P_SDO_MV_BURST_ADVANCED_ON S5P_SDAOUT_BASE(0x0140) +#define S5P_SDO_MV_BURST_DURATION_ZONE1 S5P_SDAOUT_BASE(0x0144) +#define S5P_SDO_MV_BURST_DURATION_ZONE2 S5P_SDAOUT_BASE(0x0148) +#define S5P_SDO_MV_BURST_DURATION_ZONE3 S5P_SDAOUT_BASE(0x014C) +#define S5P_SDO_MV_BURST_PHASE_ZONE S5P_SDAOUT_BASE(0x0150) +#define S5P_SDO_MV_SLICE_PHASE_LINE S5P_SDAOUT_BASE(0x0154) +#define S5P_SDO_MV_RGB_PROTECTION_ON S5P_SDAOUT_BASE(0x0158) +#define S5P_SDO_MV_480P_PROTECTION_ON S5P_SDAOUT_BASE(0x015C) +#define S5P_SDO_CCCON S5P_SDAOUT_BASE(0x0180) +#define S5P_SDO_YSCALE S5P_SDAOUT_BASE(0x0184) +#define S5P_SDO_CBSCALE S5P_SDAOUT_BASE(0x0188) +#define S5P_SDO_CRSCALE S5P_SDAOUT_BASE(0x018C) +#define S5P_SDO_CB_CR_OFFSET S5P_SDAOUT_BASE(0x0190) +#define S5P_SDO_RGB_CC S5P_SDAOUT_BASE(0x0194) +#define S5P_SDO_CVBS_CC_Y1 S5P_SDAOUT_BASE(0x0198) +#define S5P_SDO_CVBS_CC_Y2 S5P_SDAOUT_BASE(0x019C) +#define S5P_SDO_CVBS_CC_C S5P_SDAOUT_BASE(0x01A0) +#define S5P_SDO_YC_CC_Y S5P_SDAOUT_BASE(0x01A4) +#define S5P_SDO_YC_CC_C S5P_SDAOUT_BASE(0x01A8) +#define S5P_SDO_CSC_525_PORCH S5P_SDAOUT_BASE(0x01B0) +#define S5P_SDO_CSC_625_PORCH S5P_SDAOUT_BASE(0x01B4) +#define S5P_SDO_RGBSYNC S5P_SDAOUT_BASE(0x01C0) +#define S5P_SDO_OSFC00_0 S5P_SDAOUT_BASE(0x0200) +#define S5P_SDO_OSFC01_0 S5P_SDAOUT_BASE(0x0204) +#define S5P_SDO_OSFC02_0 S5P_SDAOUT_BASE(0x0208) +#define S5P_SDO_OSFC03_0 S5P_SDAOUT_BASE(0x020C) +#define S5P_SDO_OSFC04_0 S5P_SDAOUT_BASE(0x0210) +#define S5P_SDO_OSFC05_0 S5P_SDAOUT_BASE(0x0214) +#define S5P_SDO_OSFC06_0 S5P_SDAOUT_BASE(0x0218) +#define S5P_SDO_OSFC07_0 S5P_SDAOUT_BASE(0x021C) +#define S5P_SDO_OSFC08_0 S5P_SDAOUT_BASE(0x0220) +#define S5P_SDO_OSFC09_0 S5P_SDAOUT_BASE(0x0224) +#define S5P_SDO_OSFC10_0 S5P_SDAOUT_BASE(0x0228) +#define S5P_SDO_OSFC11_0 S5P_SDAOUT_BASE(0x022C) +#define S5P_SDO_OSFC12_0 S5P_SDAOUT_BASE(0x0230) +#define S5P_SDO_OSFC13_0 S5P_SDAOUT_BASE(0x0234) +#define S5P_SDO_OSFC14_0 S5P_SDAOUT_BASE(0x0238) +#define S5P_SDO_OSFC15_0 S5P_SDAOUT_BASE(0x023C) +#define S5P_SDO_OSFC16_0 S5P_SDAOUT_BASE(0x0240) +#define S5P_SDO_OSFC17_0 S5P_SDAOUT_BASE(0x0244) +#define S5P_SDO_OSFC18_0 S5P_SDAOUT_BASE(0x0248) +#define S5P_SDO_OSFC19_0 S5P_SDAOUT_BASE(0x024C) +#define S5P_SDO_OSFC20_0 S5P_SDAOUT_BASE(0x0250) +#define S5P_SDO_OSFC21_0 S5P_SDAOUT_BASE(0x0254) +#define S5P_SDO_OSFC22_0 S5P_SDAOUT_BASE(0x0258) +#define S5P_SDO_OSFC23_0 S5P_SDAOUT_BASE(0x025C) +#define S5P_SDO_XTALK0 S5P_SDAOUT_BASE(0x0260) +#define S5P_SDO_XTALK1 S5P_SDAOUT_BASE(0x0264) +#define S5P_SDO_XTALK2 S5P_SDAOUT_BASE(0x0268) +#define S5P_SDO_BB_CTRL S5P_SDAOUT_BASE(0x026C) +#define S5P_SDO_IRQ S5P_SDAOUT_BASE(0x0280) +#define S5P_SDO_IRQMASK S5P_SDAOUT_BASE(0x0284) +#define S5P_SDO_OSFC00_1 S5P_SDAOUT_BASE(0x02C0) +#define S5P_SDO_OSFC01_1 S5P_SDAOUT_BASE(0x02C4) +#define S5P_SDO_OSFC02_1 S5P_SDAOUT_BASE(0x02C8) +#define S5P_SDO_OSFC03_1 S5P_SDAOUT_BASE(0x02CC) +#define S5P_SDO_OSFC04_1 S5P_SDAOUT_BASE(0x02D0) +#define S5P_SDO_OSFC05_1 S5P_SDAOUT_BASE(0x02D4) +#define S5P_SDO_OSFC06_1 S5P_SDAOUT_BASE(0x02D8) +#define S5P_SDO_OSFC07_1 S5P_SDAOUT_BASE(0x02DC) +#define S5P_SDO_OSFC08_1 S5P_SDAOUT_BASE(0x02E0) +#define S5P_SDO_OSFC09_1 S5P_SDAOUT_BASE(0x02E4) +#define S5P_SDO_OSFC10_1 S5P_SDAOUT_BASE(0x02E8) +#define S5P_SDO_OSFC11_1 S5P_SDAOUT_BASE(0x02EC) +#define S5P_SDO_OSFC12_1 S5P_SDAOUT_BASE(0x02E0) +#define S5P_SDO_OSFC13_1 S5P_SDAOUT_BASE(0x02F4) +#define S5P_SDO_OSFC14_1 S5P_SDAOUT_BASE(0x02F8) +#define S5P_SDO_OSFC15_1 S5P_SDAOUT_BASE(0x02FC) +#define S5P_SDO_OSFC16_1 S5P_SDAOUT_BASE(0x0300) +#define S5P_SDO_OSFC17_1 S5P_SDAOUT_BASE(0x0304) +#define S5P_SDO_OSFC18_1 S5P_SDAOUT_BASE(0x0308) +#define S5P_SDO_OSFC19_1 S5P_SDAOUT_BASE(0x030C) +#define S5P_SDO_OSFC20_1 S5P_SDAOUT_BASE(0x0310) +#define S5P_SDO_OSFC21_1 S5P_SDAOUT_BASE(0x0314) +#define S5P_SDO_OSFC22_1 S5P_SDAOUT_BASE(0x0318) +#define S5P_SDO_OSFC23_1 S5P_SDAOUT_BASE(0x031C) +#define S5P_SDO_OSFC00_2 S5P_SDAOUT_BASE(0x0320) +#define S5P_SDO_OSFC01_2 S5P_SDAOUT_BASE(0x0324) +#define S5P_SDO_OSFC02_2 S5P_SDAOUT_BASE(0x0328) +#define S5P_SDO_OSFC03_2 S5P_SDAOUT_BASE(0x032C) +#define S5P_SDO_OSFC04_2 S5P_SDAOUT_BASE(0x0330) +#define S5P_SDO_OSFC05_2 S5P_SDAOUT_BASE(0x0334) +#define S5P_SDO_OSFC06_2 S5P_SDAOUT_BASE(0x0338) +#define S5P_SDO_OSFC07_2 S5P_SDAOUT_BASE(0x033C) +#define S5P_SDO_OSFC08_2 S5P_SDAOUT_BASE(0x0340) +#define S5P_SDO_OSFC09_2 S5P_SDAOUT_BASE(0x0344) +#define S5P_SDO_OSFC10_2 S5P_SDAOUT_BASE(0x0348) +#define S5P_SDO_OSFC11_2 S5P_SDAOUT_BASE(0x034C) +#define S5P_SDO_OSFC12_2 S5P_SDAOUT_BASE(0x0350) +#define S5P_SDO_OSFC13_2 S5P_SDAOUT_BASE(0x0354) +#define S5P_SDO_OSFC14_2 S5P_SDAOUT_BASE(0x0358) +#define S5P_SDO_OSFC15_2 S5P_SDAOUT_BASE(0x035C) +#define S5P_SDO_OSFC16_2 S5P_SDAOUT_BASE(0x0360) +#define S5P_SDO_OSFC17_2 S5P_SDAOUT_BASE(0x0364) +#define S5P_SDO_OSFC18_2 S5P_SDAOUT_BASE(0x0368) +#define S5P_SDO_OSFC19_2 S5P_SDAOUT_BASE(0x036C) +#define S5P_SDO_OSFC20_2 S5P_SDAOUT_BASE(0x0370) +#define S5P_SDO_OSFC21_2 S5P_SDAOUT_BASE(0x0374) +#define S5P_SDO_OSFC22_2 S5P_SDAOUT_BASE(0x0378) +#define S5P_SDO_OSFC23_2 S5P_SDAOUT_BASE(0x037C) +#define S5P_SDO_ARMCC S5P_SDAOUT_BASE(0x03C0) +#define S5P_SDO_ARMWSS525 S5P_SDAOUT_BASE(0x03C4) +#define S5P_SDO_ARMWSS625 S5P_SDAOUT_BASE(0x03C8) +#define S5P_SDO_ARMCGMS525 S5P_SDAOUT_BASE(0x03CC) +#define S5P_SDO_ARMCGMS625 S5P_SDAOUT_BASE(0x03D4) +#define S5P_SDO_VERSION S5P_SDAOUT_BASE(0x03D8) +#define S5P_SDO_CC S5P_SDAOUT_BASE(0x0380) +#define S5P_SDO_WSS525 S5P_SDAOUT_BASE(0x0384) +#define S5P_SDO_WSS625 S5P_SDAOUT_BASE(0x0388) +#define S5P_SDO_CGMS525 S5P_SDAOUT_BASE(0x038C) +#define S5P_SDO_CGMS625 S5P_SDAOUT_BASE(0x0394) + +#define SDO_TVOUT_SW_RESET (1<<4) +#define SDO_TVOUT_CLOCK_ON (1) +#define SDO_TVOUT_CLOCK_OFF (0) + +#define SDO_DAC2_Y_G (0<<20) +#define SDO_DAC2_PB_B (1<<20) +#define SDO_DAC2_PR_R (2<<20) +#define SDO_DAC1_Y_G (0<<18) +#define SDO_DAC1_PB_B (1<<18) +#define SDO_DAC1_PR_R (2<<18) +#define SDO_DAC0_Y_G (0<<16) +#define SDO_DAC0_PB_B (1<<16) +#define SDO_DAC0_PR_R (2<<16) +#define SDO_DAC2_CVBS (0<<12) +#define SDO_DAC2_Y (1<<12) +#define SDO_DAC2_C (2<<12) +#define SDO_DAC1_CVBS (0<<10) +#define SDO_DAC1_Y (1<<10) +#define SDO_DAC1_C (2<<10) +#define SDO_DAC0_CVBS (0<<8) +#define SDO_DAC0_Y (1<<8) +#define SDO_DAC0_C (2<<8) +#define SDO_COMPOSITE (0<<6) +#define SDO_COMPONENT (1<<6) +#define SDO_RGB (0<<5) +#define SDO_YPBPR (1<<5) +#define SDO_INTERLACED (0<<4) +#define SDO_PROGRESSIVE (1<<4) +#define SDO_NTSC_M (0) +#define SDO_PAL_M (1) +#define SDO_PAL_BGHID (2) +#define SDO_PAL_N (3) +#define SDO_PAL_NC (4) +#define SDO_NTSC_443 (8) +#define SDO_PAL_60 (9) + +#define SDO_COMPONENT_LEVEL_SEL_0IRE (0<<3) +#define SDO_COMPONENT_LEVEL_SEL_75IRE (1<<3) +#define SDO_COMPONENT_VTOS_RATIO_10_4 (0<<2) +#define SDO_COMPONENT_VTOS_RATIO_7_3 (1<<2) +#define SDO_COMPOSITE_LEVEL_SEL_0IRE (0<<1) +#define SDO_COMPOSITE_LEVEL_SEL_75IRE (1<<1) +#define SDO_COMPOSITE_VTOS_RATIO_10_4 (0<<0) +#define SDO_COMPOSITE_VTOS_RATIO_7_3 (1<<0) + +#define SDO_COMPONENT_SYNC_ABSENT (0) +#define SDO_COMPONENT_SYNC_YG (1) +#define SDO_COMPONENT_SYNC_ALL (3) + +#define SDO_CVBS_NO_WSS (0<<14) +#define SDO_CVBS_WSS_INS (1<<14) +#define SDO_CVBS_NO_CLOSED_CAPTION (0<<12) +#define SDO_CVBS_21H_CLOSED_CAPTION (1<<12) +#define SDO_CVBS_21H_284H_CLOSED_CAPTION (2<<12) +#define SDO_CVBS_USE_OTHERS (3<<12) +#define SDO_SVIDEO_NO_WSS (0<<10) +#define SDO_SVIDEO_WSS_INS (1<<10) +#define SDO_SVIDEO_NO_CLOSED_CAPTION (0<<8) +#define SDO_SVIDEO_21H_CLOSED_CAPTION (1<<8) +#define SDO_SVIDEO_21H_284H_CLOSED_CAPTION (2<<8) +#define SDO_SVIDEO_USE_OTHERS (3<<8) +#define SDO_RGB_NO_CGMSA (0<<7) +#define SDO_RGB_CGMSA_INS (1<<7) +#define SDO_RGB_NO_WSS (0<<6) +#define SDO_RGB_WSS_INS (1<<6) +#define SDO_RGB_NO_CLOSED_CAPTION (0<<4) +#define SDO_RGB_21H_CLOSED_CAPTION (1<<4) +#define SDO_RGB_21H_284H_CLOSED_CAPTION (2<<4) +#define SDO_RGB_USE_OTHERS (3<<4) +#define SDO_YPBPR_NO_CGMSA (0<<3) +#define SDO_YPBPR_CGMSA_INS (1<<3) +#define SDO_YPBPR_NO_WSS (0<<2) +#define SDO_YPBPR_WSS_INS (1<<2) +#define SDO_YPBPR_NO_CLOSED_CAPTION (0) +#define SDO_YPBPR_21H_CLOSED_CAPTION (1) +#define SDO_YPBPR_21H_284H_CLOSED_CAPTION (2) +#define SDO_YPBPR_USE_OTHERS(3) + +#define SDO_SCALE_CONV_OFFSET(a) ((0x3ff&a)<<16) +#define SDO_SCALE_CONV_GAIN(a) (0xfff&a) + +#define SDO_DELAY_YTOC(a) ((0xf&a)<<16) +#define SDO_ACTIVE_START_OFFSET(a) ((0xff&a)<<8) +#define SDO_ACTIVE_END_OFFSET(a) (0xff&a) + +#define SDO_COLOR_SC_PHASE_ADJ (1) +#define SDO_COLOR_SC_PHASE_NOADJ (0) + +#define SDO_POWER_ON_DAC2 (1<<2) +#define SDO_POWER_DOWN_DAC2 (0<<2) +#define SDO_POWER_ON_DAC1 (1<<1) +#define SDO_POWER_DOWN_DAC1 (0<<1) +#define SDO_POWER_ON_DAC0 (1<<0) +#define SDO_POWER_DOWN_DAC0 (0<<0) + +#define SDO_FIELD_MOD_1001(a) (((0x3ff<<16)&a)>>16) +#define SDO_FIELD_ID_BOTTOM(a) ((1<<1)&a) +#define SDO_FIELD_ID_BOTTOM_PI_INCATION(a) (1) + +#define SDO_MV_AGC_103_ON (1) + +#define SDO_COMPONENT_BHS_ADJ_ON (0<<4) +#define SDO_COMPONENT_BHS_ADJ_OFF (1<<4) +#define SDO_COMPONENT_YPBPR_COMP_ON (0<<3) +#define SDO_COMPONENT_YPBPR_COMP_OFF (1<<3) +#define SDO_COMPONENT_RGB_COMP_ON (0<<2) +#define SDO_COMPONENT_RGB_COMP_OFF (1<<2) +#define SDO_COMPONENT_YC_COMP_ON (0<<1) +#define SDO_COMPONENT_YC_COMP_OFF (1<<1) +#define SDO_COMPONENT_CVBS_COMP_ON (0) +#define SDO_COMPONENT_CVBS_COMP_OFF (1) + +#define SDO_BRIGHTNESS_GAIN(a) ((0xff&a)<<16) +#define SDO_BRIGHTNESS_OFFSET(a) (0xff&a) + +#define SDO_HS_CB_GAIN0(a) ((0x1ff&a)<<16) +#define SDO_HS_CB_GAIN1(a) (0x1ff&a) + +#define SDO_HS_CR_GAIN0(a) ((0x1ff&a)<<16) +#define SDO_HS_CR_GAIN1(a) (0x1ff&a) + +#define SDO_HS_CR_OFFSET(a) ((0x3ff&a)<<16) +#define SDO_HS_CB_OFFSET(a) (0x3ff&a) + +#define SDO_MAX_RGB_CUBE(a) ((0xff&a)<<8) +#define SDO_MIN_RGB_CUBE(a) (0xff&a) + +#define SDO_Y_LOWER_MID_CVBS_CORN(a) ((0x3ff&a)<<16) +#define SDO_Y_BOTTOM_CVBS_CORN(a) (0x3ff&a) + +#define SDO_Y_TOP_CVBS_CORN(a) ((0x3ff&a)<<16) +#define SDO_Y_UPPER_MID_CVBS_CORN(a) (0x3ff&a) + +#define SDO_RADIUS_CVBS_CORN(a) (0x1ff&a) + +#define SDO_Y_TOP_YC_CYLINDER(a) ((0x3ff&a)<<16) +#define SDO_Y_BOTOM_YC_CYLINDER(a) (0x3ff&a) + +#define SDO_RADIUS_YC_CYLINDER(a) (0x1ff&a) + +#define SDO_COMPONENT_525_BP(a) ((0x3ff&a)<<16) +#define SDO_COMPONENT_525_FP(a) (0x3ff&a) + +#define SDO_COMPONENT_625_BP(a) ((0x3ff&a)<<16) +#define SDO_COMPONENT_625_FP(a) (0x3ff&a) + +#define SDO_RGB_SYNC_COMPOSITE (0<<8) +#define SDO_RGB_SYNC_SEPERATE (1<<8) +#define SDO_RGB_VSYNC_LOW_ACT (0<<4) +#define SDO_RGB_VSYNC_HIGH_ACT (1<<4) +#define SDO_RGB_HSYNC_LOW_ACT 0 +#define SDO_RGB_HSYNC_HIGH_ACT 1 + +#define SDO_OSF_COEF_ODD(a) ((0xfff&a)<<16) +#define SDO_OSF_COEF_EVEN(a) (0xfff&a) + +#define SDO_XTALK_COEF02(a) ((0xff&a)<<16) +#define SDO_XTALK_COEF01(a) (0xff&a) + +#define SDO_REF_BB_LEVEL_NTSC (0x11a<<8) +#define SDO_REF_BB_LEVEL_PAL (0xfb<<8) +#define SDO_SEL_BB_CJAN_CVBS0_BB1_BB2 (0<<4) +#define SDO_SEL_BB_CJAN_BB0_CVBS1_BB2 (1<<4) +#define SDO_SEL_BB_CJAN_BB0_BB1_CVBS2 (2<<4) +#define SDO_BB_MODE_ENABLE (1) +#define SDO_BB_MODE_DISABLE (0) + +#define SDO_VSYNC_IRQ_PEND (1) +#define SDO_VSYNC_NO_IRQ (0) + +#define SDO_VSYNC_IRQ_ENABLE (0) +#define SDO_VSYNC_IRQ_DISABLE (1) + +#define SDO_DISPLAY_CC_CAPTION(a) ((0xff&a)<<16) +#define SDO_NON_DISPLAY_CC_CAPTION(a) (0xff&a) + +#define SDO_CRC_WSS525(a) ((0x3f&a)<<14) +#define SDO_WORD2_WSS525_COPY_PERMIT (0<<6) +#define SDO_WORD2_WSS525_ONECOPY_PERMIT (1<<6) +#define SDO_WORD2_WSS525_NOCOPY_PERMIT (3<<6) +#define SDO_WORD2_WSS525_MV_PSP_OFF (0<<8) +#define SDO_WORD2_WSS525_MV_PSP_ON_2LINE_BURST (1<<8) +#define SDO_WORD2_WSS525_MV_PSP_ON_BURST_OFF (2<<8) +#define SDO_WORD2_WSS525_MV_PSP_ON_4LINE_BURST (3<<8) +#define SDO_WORD2_WSS525_ANALOG_OFF (0<<10) +#define SDO_WORD2_WSS525_ANALOG_ON (1<<10) +#define SDO_WORD1_WSS525_COPY_INFO (0<<2) +#define SDO_WORD1_WSS525_DEFAULT (0xf<<2) +#define SDO_WORD0_WSS525_4_3_NORMAL (0) +#define SDO_WORD0_WSS525_16_9_ANAMORPIC (1) +#define SDO_WORD0_WSS525_4_3_LETTERBOX (2) + +#define SDO_WSS625_SURROUND_SOUND_DISABLE (0<<11) +#define SDO_WSS625_SURROUND_SOUND_ENABLE (1<<11) +#define SDO_WSS625_NO_COPYRIGHT (0<<12) +#define SDO_WSS625_COPYRIGHT (1<<12) +#define SDO_WSS625_COPY_NOT_RESTRICTED (0<<13) +#define SDO_WSS625_COPY_RESTRICTED (1<<13) +#define SDO_WSS625_TELETEXT_NO_SUBTITLES (0<<8) +#define SDO_WSS625_TELETEXT_SUBTITLES (1<<8) +#define SDO_WSS625_NO_OPEN_SUBTITLES (0<<9) +#define SDO_WSS625_INACT_OPEN_SUBTITLES (1<<9) +#define SDO_WSS625_OUTACT_OPEN_SUBTITLES (2<<9) +#define SDO_WSS625_CAMERA (0<<4) +#define SDO_WSS625_FILM (1<<4) +#define SDO_WSS625_NORMAL_PAL (0<<5) +#define SDO_WSS625_MOTION_ADAPTIVE_COLORPLUS (1<<5) +#define SDO_WSS625_HELPER_NO_SIG (0<<6) +#define SDO_WSS625_HELPER_SIG (1<<6) +#define SDO_WSS625_4_3_FULL_576 (0x8) +#define SDO_WSS625_14_9_LETTERBOX_CENTER_504 (0x1) +#define SDO_WSS625_14_9_LETTERBOX_TOP_504 (0x2) +#define SDO_WSS625_16_9_LETTERBOX_CENTER_430 (0xb) +#define SDO_WSS625_16_9_LETTERBOX_TOP_430 (0x4) +#define SDO_WSS625_16_9_LETTERBOX_CENTER (0xd) +#define SDO_WSS625_14_9_FULL_CENTER_576 (0xe) +#define SDO_WSS625_16_9_ANAMORPIC_576 (0x7) + +#define SDO_CRC_CGMS525(a) ((0x3f&a)<<14) +#define SDO_WORD2_CGMS525_COPY_PERMIT (0<<6) +#define SDO_WORD2_CGMS525_ONECOPY_PERMIT (1<<6) +#define SDO_WORD2_CGMS525_NOCOPY_PERMIT (3<<6) +#define SDO_WORD2_CGMS525_MV_PSP_OFF (0<<8) +#define SDO_WORD2_CGMS525_MV_PSP_ON_2LINE_BURST (1<<8) +#define SDO_WORD2_CGMS525_MV_PSP_ON_BURST_OFF (2<<8) +#define SDO_WORD2_CGMS525_MV_PSP_ON_4LINE_BURST (3<<8) +#define SDO_WORD2_CGMS525_ANALOG_OFF (0<<10) +#define SDO_WORD2_CGMS525_ANALOG_ON (1<<10) +#define SDO_WORD1_CGMS525_COPY_INFO (0<<2) +#define SDO_WORD1_CGMS525_DEFAULT (0xf<<2) +#define SDO_WORD0_CGMS525_4_3_NORMAL (0) +#define SDO_WORD0_CGMS525_16_9_ANAMORPIC (1) +#define SDO_WORD0_CGMS525_4_3_LETTERBOX (2) + +#define SDO_CGMS625_SURROUND_SOUND_DISABLE (0<<11) +#define SDO_CGMS625_SURROUND_SOUND_ENABLE (1<<11) +#define SDO_CGMS625_NO_COPYRIGHT (0<<12) +#define SDO_CGMS625_COPYRIGHT (1<<12) +#define SDO_CGMS625_COPY_NOT_RESTRICTED (0<<13) +#define SDO_CGMS625_COPY_RESTRICTED (1<<13) +#define SDO_CGMS625_TELETEXT_NO_SUBTITLES (0<<8) +#define SDO_CGMS625_TELETEXT_SUBTITLES (1<<8) +#define SDO_CGMS625_NO_OPEN_SUBTITLES (0<<9) +#define SDO_CGMS625_INACT_OPEN_SUBTITLES (1<<9) +#define SDO_CGMS625_OUTACT_OPEN_SUBTITLES (2<<9) +#define SDO_CGMS625_CAMERA (0<<4) +#define SDO_CGMS625_FILM (1<<4) +#define SDO_CGMS625_NORMAL_PAL (0<<5) +#define SDO_CGMS625_MOTION_ADAPTIVE_COLORPLUS (1<<5) +#define SDO_CGMS625_HELPER_NO_SIG (0<<6) +#define SDO_CGMS625_HELPER_SIG (1<<6) +#define SDO_CGMS625_4_3_FULL_576 (0x8) +#define SDO_CGMS625_14_9_LETTERBOX_CENTER_504 (0x1) +#define SDO_CGMS625_14_9_LETTERBOX_TOP_504 (0x2) +#define SDO_CGMS625_16_9_LETTERBOX_CENTER_430 (0xb) +#define SDO_CGMS625_16_9_LETTERBOX_TOP_430 (0x4) +#define SDO_CGMS625_16_9_LETTERBOX_CENTER (0xd) +#define SDO_CGMS625_14_9_FULL_CENTER_576 (0xe) +#define SDO_CGMS625_16_9_ANAMORPIC_576 (0x7) + +#endif diff --git a/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vmx.h b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vmx.h new file mode 100644 index 0000000..bd104342 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vmx.h @@ -0,0 +1,209 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vmx.h + * + * Mixer register header file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <mach/map.h> + +#define S5P_MIXER_BASE(x) (x) + +#define S5P_MXR_STATUS S5P_MIXER_BASE(0x0000) +#define S5P_MXR_CFG S5P_MIXER_BASE(0x0004) +#define S5P_MXR_INT_EN S5P_MIXER_BASE(0x0008) +#define S5P_MXR_INT_STATUS S5P_MIXER_BASE(0x000C) +#define S5P_MXR_LAYER_CFG S5P_MIXER_BASE(0x0010) +#define S5P_MXR_VIDEO_CFG S5P_MIXER_BASE(0x0014) +#define S5P_MXR_GRAPHIC0_CFG S5P_MIXER_BASE(0x0020) +#define S5P_MXR_GRAPHIC0_BASE S5P_MIXER_BASE(0x0024) +#define S5P_MXR_GRAPHIC0_SPAN S5P_MIXER_BASE(0x0028) +#define S5P_MXR_GRAPHIC0_SXY S5P_MIXER_BASE(0x002C) +#define S5P_MXR_GRAPHIC0_WH S5P_MIXER_BASE(0x0030) +#define S5P_MXR_GRAPHIC0_DXY S5P_MIXER_BASE(0x0034) +#define S5P_MXR_GRAPHIC0_BLANK S5P_MIXER_BASE(0x0038) +#define S5P_MXR_GRAPHIC1_CFG S5P_MIXER_BASE(0x0040) +#define S5P_MXR_GRAPHIC1_BASE S5P_MIXER_BASE(0x0044) +#define S5P_MXR_GRAPHIC1_SPAN S5P_MIXER_BASE(0x0048) +#define S5P_MXR_GRAPHIC1_SXY S5P_MIXER_BASE(0x004C) +#define S5P_MXR_GRAPHIC1_WH S5P_MIXER_BASE(0x0050) +#define S5P_MXR_GRAPHIC1_DXY S5P_MIXER_BASE(0x0054) +#define S5P_MXR_GRAPHIC1_BLANK S5P_MIXER_BASE(0x0058) +#define S5P_MXR_BG_CFG S5P_MIXER_BASE(0x0060) +#define S5P_MXR_BG_COLOR0 S5P_MIXER_BASE(0x0064) +#define S5P_MXR_BG_COLOR1 S5P_MIXER_BASE(0x0068) +#define S5P_MXR_BG_COLOR2 S5P_MIXER_BASE(0x006C) +#define S5P_MXR_CM_COEFF_Y S5P_MIXER_BASE(0x0080) +#define S5P_MXR_CM_COEFF_CB S5P_MIXER_BASE(0x0084) +#define S5P_MXR_CM_COEFF_CR S5P_MIXER_BASE(0x0088) +#define S5P_MXR_VER S5P_MIXER_BASE(0x0100) + + +#define S5P_MXR_STATUS_S S5P_MIXER_BASE(0x2000) +#define S5P_MXR_CFG_S S5P_MIXER_BASE(0x2004) +#define S5P_MXR_LAYER_CFG_S S5P_MIXER_BASE(0x2010) +#define S5P_MXR_VIDEO_CFG_S S5P_MIXER_BASE(0x2014) +#define S5P_MXR_GRAPHIC0_CFG_S S5P_MIXER_BASE(0x2020) +#define S5P_MXR_GRAPHIC0_BASE_S S5P_MIXER_BASE(0x2024) +#define S5P_MXR_GRAPHIC0_SPAN_S S5P_MIXER_BASE(0x2028) +#define S5P_MXR_GRAPHIC0_SXY_S S5P_MIXER_BASE(0x202C) +#define S5P_MXR_GRAPHIC0_WH_S S5P_MIXER_BASE(0x2030) +#define S5P_MXR_GRAPHIC0_DXY_S S5P_MIXER_BASE(0x2034) +#define S5P_MXR_GRAPHIC0_BLANK_PIXEL_S S5P_MIXER_BASE(0x2038) +#define S5P_MXR_GRAPHIC1_CFG_S S5P_MIXER_BASE(0x2040) +#define S5P_MXR_GRAPHIC1_BASE_S S5P_MIXER_BASE(0x2044) +#define S5P_MXR_GRAPHIC1_SPAN_S S5P_MIXER_BASE(0x2048) +#define S5P_MXR_GRAPHIC1_SXY_S S5P_MIXER_BASE(0x204C) +#define S5P_MXR_GRAPHIC1_WH_S S5P_MIXER_BASE(0x2050) +#define S5P_MXR_GRAPHIC1_DXY_S S5P_MIXER_BASE(0x2054) +#define S5P_MXR_GRAPHIC1_BLANK_PIXEL_S S5P_MIXER_BASE(0x2058) +#define S5P_MXR_BG_COLOR0_S S5P_MIXER_BASE(0x2064) +#define S5P_MXR_BG_COLOR1_S S5P_MIXER_BASE(0x2068) +#define S5P_MXR_BG_COLOR2_S S5P_MIXER_BASE(0x206C) + +#define S5P_MXR_STATUS_RUN (1<<0) +#define S5P_MXR_STATUS_STOP (0<<0) +#define S5P_MXR_STATUS_SYNC_DISABLE (0<<2) +#define S5P_MXR_STATUS_SYNC_ENABLE (1<<2) +#define S5P_MXR_STATUS_LITTLE (0<<3) +#define S5P_MXR_STATUS_BIT (1<<3) +#define S5P_MXR_STATUS_8_BURST (0<<7) +#define S5P_MXR_STATUS_16_BURST (1<<7) + +#define S5P_MXR_CFG_SD (0<<0) +#define S5P_MXR_CFG_HD (1<<0) +#define S5P_MXR_CFG_NTSC (0<<1) +#define S5P_MXR_CFG_PAL (1<<1) +#define S5P_MXR_CFG_INTERLACE (0<<2) +#define S5P_MXR_CFG_PROGRASSIVE (1<<2) +#define S5P_MXR_CFG_VIDEO_DISABLE (0<<3) +#define S5P_MXR_CFG_VIDEO_ENABLE (1<<4) +#define S5P_MXR_CFG_GRAPHIC0_DISABLE (0<<4) +#define S5P_MXR_CFG_GRAPHIC0_ENABLE (1<<4) +#define S5P_MXR_CFG_GRAPHIC1_DISABLE (0<<5) +#define S5P_MXR_CFG_GRAPHIC1_ENABLE (1<<5) +#define S5P_MXR_CFG_HD_720P (0<<6) +#define S5P_MXR_CFG_HD_1080I (1<<6) + +#define S5P_MXR_INT_EN_GRP0_DISABLE (0<<8) +#define S5P_MXR_INT_EN_GRP0_ENABLE (1<<8) +#define S5P_MXR_INT_EN_GRP1_DISABLE (0<<9) +#define S5P_MXR_INT_EN_GRP1_ENABLE (1<<9) +#define S5P_MXR_INT_EN_VP_DISABLE (0<<10) +#define S5P_MXR_INT_EN_VP_ENABLE (1<<10) + +#define S5P_MXR_STATUS_EN_GRP0_N_FIRED (0<<8) +#define S5P_MXR_STATUS_EN_GRP0_FIRED (1<<8) +#define S5P_MXR_STATUS_EN_GRP1_N_FIRED (0<<9) +#define S5P_MXR_STATUS_EN_GRP1_FIRED (1<<9) +#define S5P_MXR_STATUS_EN_VP_N_FIRED (0<<10) +#define S5P_MXR_STATUS_EN_VP_FIRED (1<<10) + +#define S5P_MXR_LAYER_CFG_VP_HIDE (0<<0) +#define S5P_MXR_LAYER_CFG_GRP0_HIDE (0<<4) +#define S5P_MXR_LAYER_CFG_GRP1_HIDE (0<<8) + +#define S5P_MXR_VIDEO_CFG_BLEND_EN (1<<16) + + +#define S5P_MXR_BURST16_MODE (1<<7) +#define S5P_MXR_BURST8_MODE (0<<7) +#define S5P_MXR_BIG_ENDIAN_SOURCE_FORMAT (1<<3) +#define S5P_MXR_LITTLE_ENDIAN_SOURCE_FORMAT (0<<3) +#define S5P_MXR_MIXER_RESERVED (1<<2) +#define S5P_MXR_CMU_STOP_CLOCK (1<<1) +#define S5P_MXR_CMU_CANNOT_STOP_CLOCK (0<<1) +#define S5P_MXR_MIXER_START (1<<0) +#define S5P_MXR_MIXER_STOP (0<<0) + +#define S5P_MXR_HD_1080I_MODE (1<<6) +#define S5P_MXR_HD_720P_MODE (0<<6) +#define S5P_MXR_GRAPHIC1_LAYER_SHOW (1<<5) +#define S5P_MXR_GRAPHIC1_LAYER_HIDE (0<<5) +#define S5P_MXR_GRAPHIC0_LAYER_SHOW (1<<4) +#define S5P_MXR_GRAPHIC0_LAYER_HIDE (0<<4) +#define S5P_MXR_VIDEO_LAYER_SHOW (1<<3) +#define S5P_MXR_VIDEO_LAYER_HIDE (0<<3) +#define S5P_MXR_PROGRESSVE_MODE (1<<2) +#define S5P_MXR_INTERLACE_MODE (0<<2) +#define S5P_MXR_PAL (1<<1) +#define S5P_MXR_NTSC (0<<1) +#define S5P_MXR_HD (1<<0) +#define S5P_MXR_SD (0<<0) + +#define S5P_MXR_VP_INT_ENABLE (1<<10) +#define S5P_MXR_VP_INT_DISABLE (0<<10) +#define S5P_MXR_GRP1_INT_ENABLE (1<<9) +#define S5P_MXR_GRP1_INT_DISABLE (0<<9) +#define S5P_MXR_GRP0_INT_ENABLE (1<<8) +#define S5P_MXR_GRP0_INT_DISABLE (0<<8) + +#define S5P_MXR_VP_INT_FIRED (1<<10) +#define S5P_MXR_GRP1_INT_FIRED (1<<9) +#define S5P_MXR_GRP0_INT_FIRED (1<<8) +#define S5P_MXR_INT_FIRED (1<<0) + +#define S5P_MXR_ALPHA (0xff) + +#define S5P_MXR_GRP1_LAYER_PRIORITY(a) ((0xf&a)<<8) +#define S5P_MXR_GRP0_LAYER_PRIORITY(a) ((0xf&a)<<4) +#define S5P_MXR_VP_LAYER_PRIORITY(a) ((0xf&a)<<0) +#define S5P_MXR_GRP1_LAYER_PRIORITY_CLEAR(a) ((~(0xf<<8))&a) +#define S5P_MXR_GRP0_LAYER_PRIORITY_CLEAR(a) ((~(0xf<<4))&a) +#define S5P_MXR_VP_LAYER_PRIORITY_CLEAR(a) ((~(0xf<<0))&a) +#define S5P_MXR_GRP1_LAYER_PRIORITY_INFO(a) ((0xf<<8)&a) +#define S5P_MXR_GRP0_LAYER_PRIORITY_INFO(a) ((0xf<<4)&a) +#define S5P_MXR_VP_LAYER_PRIORITY_INFO(a) ((0xf<<0)&a) + +#define S5P_MXR_VP_BLEND_ENABLE (1<<16) +#define S5P_MXR_VP_BLEND_DISABLE (0<<16) +#define S5P_MXR_VP_ALPHA_VALUE(a) ((0xff&a)<<0) +#define S5P_MXR_VP_ALPHA_VALUE_CLEAR(a) ((~(0xff<<0))&a) + +#define S5P_MXR_BLANK_CHANGE_NEW_PIXEL (1<<21) +#define S5P_MXR_BLANK_NOT_CHANGE_NEW_PIXEL (0<<21) +#define S5P_MXR_PRE_MUL_MODE (1<<20) +#define S5P_MXR_NORMAL_MODE (0<<20) +#define S5P_MXR_WIN_BLEND_ENABLE (1<<17) +#define S5P_MXR_WIN_BLEND_DISABLE (0<<17) +#define S5P_MXR_PIXEL_BLEND_ENABLE (1<<16) +#define S5P_MXR_PIXEL_BLEND_DISABLE (0<<16) +#define S5P_MXR_EG_COLOR_FORMAT(a) ((0xf&a)<<8) +#define S5P_MXR_EG_COLOR_FORMAT_CLEAR(a) ((~(0xf<<8))&a) +#define S5P_MXR_GRP_ALPHA_VALUE(a) ((0xff&a)<<0) +#define S5P_MXR_GRP_ALPHA_VALUE_CLEAR(a) ((~(0xff<<0))&a) + +#define S5P_MXR_GPR_BASE(a) (0xffffffff&a) +#define S5P_MXR_GRP_ADDR_ILLEGAL(a) (0x3&a) + +#define S5P_MXR_GRP_SPAN(a) (0x7fff&a) + +#define S5P_MXR_GRP_WIDTH(a) ((0x7ff&a)<<16) +#define S5P_MXR_GRP_HEIGHT(a) ((0x7ff&a)<<0) + +#define S5P_MXR_GRP_STARTX(a) ((0x7ff&a)<<16) +#define S5P_MXR_GRP_STARTY(a) ((0x7ff&a)<<0) + +#define S5P_MXR_GRP_DESTX(a) ((0x7ff&a)<<16) +#define S5P_MXR_GRP_DESTY(a) ((0x7ff&a)<<0) + +#define S5P_MXR_GPR_BLANK_COLOR(a) (0xffffffff&a) + +#define S5P_MXR_BG_CR_DIHER_EN (1<<19) +#define S5P_MXR_BG_CB_DIHER_EN (1<<18) +#define S5P_MXR_BG_Y_DIHER_EN (1<<17) + +#define S5P_MXR_BG_COLOR_Y(a) ((0xff&a)<<16) +#define S5P_MXR_BG_COLOR_CB(a) ((0xff&a)<<8) +#define S5P_MXR_BG_COLOR_CR(a) ((0xff&a)<<0) + +#define S5P_MXR_BG_COLOR_WIDE (1<<30) +#define S5P_MXR_BG_COLOR_NARROW (0<<30) +#define S5P_MXR_BG_COEFF_0(a) ((0x3f&a)<<20) +#define S5P_MXR_BG_COEFF_1(a) ((0x3f&a)<<10) +#define S5P_MXR_BG_COEFF_2(a) ((0x3f&a)<<0) + diff --git a/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vprocessor.h b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vprocessor.h new file mode 100644 index 0000000..34c1d97 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vprocessor.h @@ -0,0 +1,366 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vprocessor.h + * + * Video Processor register header file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_VPROCESSOR_H + +#include <mach/map.h> + +#define S5P_VPROCESSOR_BASE(x) (x) + +#define S5P_VP_ENABLE S5P_VPROCESSOR_BASE(0x0000) +#define S5P_VP_SRESET S5P_VPROCESSOR_BASE(0x0004) +#define S5P_VP_SHADOW_UPDATE S5P_VPROCESSOR_BASE(0x0008) +#define S5P_VP_FIELD_ID S5P_VPROCESSOR_BASE(0x000C) +#define S5P_VP_MODE S5P_VPROCESSOR_BASE(0x0010) +#define S5P_VP_IMG_SIZE_Y S5P_VPROCESSOR_BASE(0x0014) +#define S5P_VP_IMG_SIZE_C S5P_VPROCESSOR_BASE(0x0018) +#define S5P_VP_PER_RATE_CTRL S5P_VPROCESSOR_BASE(0x001C) +#define S5P_VP_TOP_Y_PTR S5P_VPROCESSOR_BASE(0x0028) +#define S5P_VP_BOT_Y_PTR S5P_VPROCESSOR_BASE(0x002C) +#define S5P_VP_TOP_C_PTR S5P_VPROCESSOR_BASE(0x0030) +#define S5P_VP_BOT_C_PTR S5P_VPROCESSOR_BASE(0x0034) +#define S5P_VP_ENDIAN_MODE S5P_VPROCESSOR_BASE(0x03CC) +#define S5P_VP_SRC_H_POSITION S5P_VPROCESSOR_BASE(0x0044) +#define S5P_VP_SRC_V_POSITION S5P_VPROCESSOR_BASE(0x0048) +#define S5P_VP_SRC_WIDTH S5P_VPROCESSOR_BASE(0x004C) +#define S5P_VP_SRC_HEIGHT S5P_VPROCESSOR_BASE(0x0050) +#define S5P_VP_DST_H_POSITION S5P_VPROCESSOR_BASE(0x0054) +#define S5P_VP_DST_V_POSITION S5P_VPROCESSOR_BASE(0x0058) +#define S5P_VP_DST_WIDTH S5P_VPROCESSOR_BASE(0x005C) +#define S5P_VP_DST_HEIGHT S5P_VPROCESSOR_BASE(0x0060) +#define S5P_VP_H_RATIO S5P_VPROCESSOR_BASE(0x0064) +#define S5P_VP_V_RATIO S5P_VPROCESSOR_BASE(0x0068) +#define S5P_VP_POLY8_Y0_LL S5P_VPROCESSOR_BASE(0x006C) +#define S5P_VP_POLY8_Y0_LH S5P_VPROCESSOR_BASE(0x0070) +#define S5P_VP_POLY8_Y0_HL S5P_VPROCESSOR_BASE(0x0074) +#define S5P_VP_POLY8_Y0_HH S5P_VPROCESSOR_BASE(0x0078) +#define S5P_VP_POLY8_Y1_LL S5P_VPROCESSOR_BASE(0x007C) +#define S5P_VP_POLY8_Y1_LH S5P_VPROCESSOR_BASE(0x0080) +#define S5P_VP_POLY8_Y1_HL S5P_VPROCESSOR_BASE(0x0084) +#define S5P_VP_POLY8_Y1_HH S5P_VPROCESSOR_BASE(0x0088) +#define S5P_VP_POLY8_Y2_LL S5P_VPROCESSOR_BASE(0x008C) +#define S5P_VP_POLY8_Y2_LH S5P_VPROCESSOR_BASE(0x0090) +#define S5P_VP_POLY8_Y2_HL S5P_VPROCESSOR_BASE(0x0094) +#define S5P_VP_POLY8_Y2_HH S5P_VPROCESSOR_BASE(0x0098) +#define S5P_VP_POLY8_Y3_LL S5P_VPROCESSOR_BASE(0x009C) +#define S5P_VP_POLY8_Y3_LH S5P_VPROCESSOR_BASE(0x00A0) +#define S5P_VP_POLY8_Y3_HL S5P_VPROCESSOR_BASE(0x00A4) +#define S5P_VP_POLY8_Y3_HH S5P_VPROCESSOR_BASE(0x00A8) +#define S5P_VP_POLY4_Y0_LL S5P_VPROCESSOR_BASE(0x00EC) +#define S5P_VP_POLY4_Y0_LH S5P_VPROCESSOR_BASE(0x00F0) +#define S5P_VP_POLY4_Y0_HL S5P_VPROCESSOR_BASE(0x00F4) +#define S5P_VP_POLY4_Y0_HH S5P_VPROCESSOR_BASE(0x00F8) +#define S5P_VP_POLY4_Y1_LL S5P_VPROCESSOR_BASE(0x00FC) +#define S5P_VP_POLY4_Y1_LH S5P_VPROCESSOR_BASE(0x0100) +#define S5P_VP_POLY4_Y1_HL S5P_VPROCESSOR_BASE(0x0104) +#define S5P_VP_POLY4_Y1_HH S5P_VPROCESSOR_BASE(0x0108) +#define S5P_VP_POLY4_Y2_LL S5P_VPROCESSOR_BASE(0x010C) +#define S5P_VP_POLY4_Y2_LH S5P_VPROCESSOR_BASE(0x0110) +#define S5P_VP_POLY4_Y2_HL S5P_VPROCESSOR_BASE(0x0114) +#define S5P_VP_POLY4_Y2_HH S5P_VPROCESSOR_BASE(0x0118) +#define S5P_VP_POLY4_Y3_LL S5P_VPROCESSOR_BASE(0x011C) +#define S5P_VP_POLY4_Y3_LH S5P_VPROCESSOR_BASE(0x0120) +#define S5P_VP_POLY4_Y3_HL S5P_VPROCESSOR_BASE(0x0124) +#define S5P_VP_POLY4_Y3_HH S5P_VPROCESSOR_BASE(0x0128) +#define S5P_VP_POLY4_C0_LL S5P_VPROCESSOR_BASE(0x012C) +#define S5P_VP_POLY4_C0_LH S5P_VPROCESSOR_BASE(0x0130) +#define S5P_VP_POLY4_C0_HL S5P_VPROCESSOR_BASE(0x0134) +#define S5P_VP_POLY4_C0_HH S5P_VPROCESSOR_BASE(0x0138) +#define S5P_VP_POLY4_C1_LL S5P_VPROCESSOR_BASE(0x013C) +#define S5P_VP_POLY4_C1_LH S5P_VPROCESSOR_BASE(0x0140) +#define S5P_VP_POLY4_C1_HL S5P_VPROCESSOR_BASE(0x0144) +#define S5P_VP_POLY4_C1_HH S5P_VPROCESSOR_BASE(0x0148) +#define S5P_PP_CSC_Y2Y_COEF S5P_VPROCESSOR_BASE(0x01D4) +#define S5P_PP_CSC_CB2Y_COEF S5P_VPROCESSOR_BASE(0x01D8) +#define S5P_PP_CSC_CR2Y_COEF S5P_VPROCESSOR_BASE(0x01DC) +#define S5P_PP_CSC_Y2CB_COEF S5P_VPROCESSOR_BASE(0x01E0) +#define S5P_PP_CSC_CB2CB_COEF S5P_VPROCESSOR_BASE(0x01E4) +#define S5P_PP_CSC_CR2CB_COEF S5P_VPROCESSOR_BASE(0x01E8) +#define S5P_PP_CSC_Y2CR_COEF S5P_VPROCESSOR_BASE(0x01EC) +#define S5P_PP_CSC_CB2CR_COEF S5P_VPROCESSOR_BASE(0x01F0) +#define S5P_PP_CSC_CR2CR_COEF S5P_VPROCESSOR_BASE(0x01F4) +#define S5P_PP_BYPASS S5P_VPROCESSOR_BASE(0x0200) +#define S5P_PP_SATURATION S5P_VPROCESSOR_BASE(0x020C) +#define S5P_PP_SHARPNESS S5P_VPROCESSOR_BASE(0x0210) +#define S5P_PP_LINE_EQ0 S5P_VPROCESSOR_BASE(0x0218) +#define S5P_PP_LINE_EQ1 S5P_VPROCESSOR_BASE(0x021C) +#define S5P_PP_LINE_EQ2 S5P_VPROCESSOR_BASE(0x0220) +#define S5P_PP_LINE_EQ3 S5P_VPROCESSOR_BASE(0x0224) +#define S5P_PP_LINE_EQ4 S5P_VPROCESSOR_BASE(0x0228) +#define S5P_PP_LINE_EQ5 S5P_VPROCESSOR_BASE(0x022C) +#define S5P_PP_LINE_EQ6 S5P_VPROCESSOR_BASE(0x0230) +#define S5P_PP_LINE_EQ7 S5P_VPROCESSOR_BASE(0x0234) +#define S5P_PP_BRIGHT_OFFSET S5P_VPROCESSOR_BASE(0x0238) +#define S5P_PP_CSC_EN S5P_VPROCESSOR_BASE(0x023C) +#define S5P_VP_VERSION_INFO S5P_VPROCESSOR_BASE(0x03FC) + + +#define S5P_VP_FIELD_ID_S S5P_VPROCESSOR_BASE(0x016C) +#define S5P_VP_MODE_S S5P_VPROCESSOR_BASE(0x0170) +#define S5P_VP_IMG_SIZE_Y_S S5P_VPROCESSOR_BASE(0x0174) +#define S5P_VP_IMG_SIZE_C_S S5P_VPROCESSOR_BASE(0x0178) +#define S5P_VP_TOP_Y_PTR_S S5P_VPROCESSOR_BASE(0x0190) +#define S5P_VP_BOT_Y_PTR_S S5P_VPROCESSOR_BASE(0x0194) +#define S5P_VP_TOP_C_PTR_S S5P_VPROCESSOR_BASE(0x0198) +#define S5P_VP_BOT_C_PTR_S S5P_VPROCESSOR_BASE(0x019C) +#define S5P_VP_ENDIAN_MODE_S S5P_VPROCESSOR_BASE(0x03EC) +#define S5P_VP_SRC_H_POSITION_S S5P_VPROCESSOR_BASE(0x01AC) +#define S5P_VP_SRC_V_POSITION_S S5P_VPROCESSOR_BASE(0x01B0) +#define S5P_VP_SRC_WIDTH_S S5P_VPROCESSOR_BASE(0x01B4) +#define S5P_VP_SRC_HEIGHT_S S5P_VPROCESSOR_BASE(0x01B8) +#define S5P_VP_DST_H_POSITION_S S5P_VPROCESSOR_BASE(0x01BC) +#define S5P_VP_DST_V_POSITION_S S5P_VPROCESSOR_BASE(0x01C0) +#define S5P_VP_DST_WIDTH_S S5P_VPROCESSOR_BASE(0x01C4) +#define S5P_VP_DST_HEIGHT_S S5P_VPROCESSOR_BASE(0x01C8) +#define S5P_VP_H_RATIO_S S5P_VPROCESSOR_BASE(0x01CC) +#define S5P_VP_V_RATIO_S S5P_VPROCESSOR_BASE(0x01D0) +#define S5P_PP_BYPASS_S S5P_VPROCESSOR_BASE(0x0258) +#define S5P_PP_SATURATION_S S5P_VPROCESSOR_BASE(0x025C) +#define S5P_PP_SHARPNESS_S S5P_VPROCESSOR_BASE(0x0260) +#define S5P_PP_LINE_EQ0_S S5P_VPROCESSOR_BASE(0x0268) +#define S5P_PP_LINE_EQ1_S S5P_VPROCESSOR_BASE(0x026C) +#define S5P_PP_LINE_EQ2_S S5P_VPROCESSOR_BASE(0x0270) +#define S5P_PP_LINE_EQ3_S S5P_VPROCESSOR_BASE(0x0274) +#define S5P_PP_LINE_EQ4_S S5P_VPROCESSOR_BASE(0x0278) +#define S5P_PP_LINE_EQ5_S S5P_VPROCESSOR_BASE(0x027C) +#define S5P_PP_LINE_EQ6_S S5P_VPROCESSOR_BASE(0x0280) +#define S5P_PP_LINE_EQ7_S S5P_VPROCESSOR_BASE(0x0284) +#define S5P_PP_BRIGHT_OFFSET_S S5P_VPROCESSOR_BASE(0x0288) +#define S5P_PP_CSC_EN_S S5P_VPROCESSOR_BASE(0x028C) +#define S5P_PP_CSC_Y2Y_COEF_S S5P_VPROCESSOR_BASE(0x0290) +#define S5P_PP_CSC_CB2Y_COEF_S S5P_VPROCESSOR_BASE(0x0294) +#define S5P_PP_CSC_CR2Y_COEF_S S5P_VPROCESSOR_BASE(0x0298) +#define S5P_PP_CSC_Y2CB_COEF_S S5P_VPROCESSOR_BASE(0x029C) +#define S5P_PP_CSC_CB2CB_COEF_S S5P_VPROCESSOR_BASE(0x02A0) +#define S5P_PP_CSC_CR2CB_COEF_S S5P_VPROCESSOR_BASE(0x02A4) +#define S5P_PP_CSC_Y2CR_COEF_S S5P_VPROCESSOR_BASE(0x02A8) +#define S5P_PP_CSC_CB2CR_COEF_S S5P_VPROCESSOR_BASE(0x02AC) +#define S5P_PP_CSC_CR2CR_COEF_S S5P_VPROCESSOR_BASE(0x02B0) + + +#define S5P_VP_ENABLE_ON (1<<0) +#define S5P_VP_ENABLE_ON_S (1<<2) + +#define S5P_VP_SRESET_LAST_COMPLETE (0<<0) +#define S5P_VP_SRESET_PROCESSING (1<<0) + +#define S5P_VP_SHADOW_UPDATE_DISABLE (0<<0) +#define S5P_VP_SHADOW_UPDATE_ENABLE (1<<0) + +#define S5P_VP_FIELD_ID_TOP (0<<0) +#define S5P_VP_FIELD_ID_BOTTOM (1<<0) + +#define S5P_VP_MODE_2D_IPC_ENABLE (1<<1) +#define S5P_VP_MODE_2D_IPC_DISABLE (0<<1) +#define S5P_VP_MODE_FIELD_ID_MAN_TOGGLING (0<<2) +#define S5P_VP_MODE_FIELD_ID_AUTO_TOGGLING (1<<2) +#define S5P_VP_MODE_CROMA_EXPANSION_C_TOP_PTR (0<<3) +#define S5P_VP_MODE_CROMA_EXPANSION_C_TOPBOTTOM_PTR (1<<3) +#define S5P_VP_MODE_MEM_MODE_LINEAR (0<<4) +#define S5P_VP_MODE_MEM_MODE_2D_TILE (1<<4) +#define S5P_VP_MODE_LINE_SKIP_OFF (0<<5) +#define S5P_VP_MODE_LINE_SKIP_ON (1<<5) + +#define S5P_VP_ENDIAN_MODE_BIG (0<<0) +#define S5P_VP_ENDIAN_MODE_LITTLE (1<<0) + + +#define VP_ON_SW_RESET (1<<2) +#define VP_POWER_DOWN_RDY (1<<1) +#define VP_ON_ENABLE (1<<0) +#define VP_ON_DISABLE (0<<0) + +#define VP_SOFT_RESET (1<<0) + +#define VP_SHADOW_UPDATE_ENABLE (1<<0) +#define VP_SHADOW_UPDATE_DISABLE (0<<0) + +#define VP_FIELD_ID_BOTTOM (1<<0) +#define VP_FIELD_ID_TOP (0<<0) + +#define VP_LINE_SKIP_ON (1<<5) +#define VP_LINE_SKIP_OFF (0<<5) +#define VP_MEM_2D_MODE (1<<4) +#define VP_MEM_LINEAR_MODE (0<<4) +#define VP_CHROMA_USE_TOP_BOTTOM (1<<3) +#define VP_CHROMA_USE_TOP (0<<3) +#define VP_FIELD_ID_TOGGLE_VSYNC (1<<2) +#define VP_FIELD_ID_TOGGLE_USER (0<<2) +#define VP_2D_IPC_ON (1<<1) +#define VP_2D_IPC_OFF (0<<1) + +#define VP_IMG_HSIZE(a) ((0x3fff&a)<<16) +#define VP_IMG_VSIZE(a) ((0x3fff&a)<<0) +#define VP_IMG_SIZE_ILLEGAL(a) (0x7&a) + +#define VP_PEL_RATE_CTRL(a) ((0x3&a)<<0) + + +#define VP_PTR_ILLEGAL(a) (0x7&a) + +#define VP_LITTLE_ENDIAN_MODE (1<<0) +#define VP_BIG_ENDIAN_MODE (0<<0) + +#define VP_SRC_H_POSITION(a) ((0x7ff&a)<<4) +#define VP_SRC_X_FRACT_STEP(a) (0xf&a) + +#define VP_SRC_V_POSITION(a) (0x3ff&a) + +#define VP_SRC_WIDTH(a) (0x7ff&a) + +#define VP_SRC_HEIGHT(a) (0x3ff&a) + +#define VP_DST_H_POSITION(a) (0x7ff&a) + +#define VP_DST_V_POSITION(a) (0x3ff&a) + +#define VP_DST_WIDTH(a) (0x7ff&a) + +#define VP_DST_HEIGHT(a) (0x3ff&a) + +#define VP_H_RATIO(a) (0x7ffff&a) + +#define VP_V_RATIO(a) (0x7ffff&a) + +#define VP_POLY8_Y0_x0(a) ((0x7&a)<<24) +#define VP_POLY8_Y0_x1(a) ((0x7&a)<<16) +#define VP_POLY8_Y0_x2(a) ((0x7&a)<<8) +#define VP_POLY8_Y0_x3(a) ((0x7&a)<<0) + +#define VP_POLY8_Y1_x0(a) ((0x1f&a)<<24) +#define VP_POLY8_Y1_x1(a) ((0x1f&a)<<16) +#define VP_POLY8_Y1_x2(a) ((0x1f&a)<<8) +#define VP_POLY8_Y1_x3(a) ((0x1f&a)<<0) + +#define VP_POLY8_Y2_x0(a) ((0x7f&a)<<24) +#define VP_POLY8_Y2_x1(a) ((0x7f&a)<<16) +#define VP_POLY8_Y2_x2(a) ((0x7f&a)<<8) +#define VP_POLY8_Y2_x3(a) ((0x7f&a)<<0) + +#define VP_POLY8_Y3_x0(a) ((0x7f&a)<<24) +#define VP_POLY8_Y3_x1(a) ((0x7f&a)<<16) +#define VP_POLY8_Y3_x2(a) ((0x7f&a)<<8) +#define VP_POLY8_Y3_x3(a) ((0x7f&a)<<0) + +#define VP_POLY4_Y0_x0(a) ((0x3f&a)<<24) +#define VP_POLY4_Y0_x1(a) ((0x3f&a)<<16) +#define VP_POLY4_Y0_x2(a) ((0x3f&a)<<8) +#define VP_POLY4_Y0_x3(a) ((0x3f&a)<<0) + +#define VP_POLY4_Y1_x0(a) ((0x7f&a)<<24) +#define VP_POLY4_Y1_x1(a) ((0x7f&a)<<16) +#define VP_POLY4_Y1_x2(a) ((0x7f&a)<<8) +#define VP_POLY4_Y1_x3(a) ((0x7f&a)<<0) + +#define VP_POLY4_Y2_x0(a) ((0x7f&a)<<24) +#define VP_POLY4_Y2_x1(a) ((0x7f&a)<<16) +#define VP_POLY4_Y2_x2(a) ((0x7f&a)<<8) +#define VP_POLY4_Y2_x3(a) ((0x7f&a)<<0) + +#define VP_POLY4_Y3_x0(a) ((0x3f&a)<<24) +#define VP_POLY4_Y3_x1(a) ((0x3f&a)<<16) +#define VP_POLY4_Y3_x2(a) ((0x3f&a)<<8) +#define VP_POLY4_Y3_x3(a) ((0x3f&a)<<0) + +#define VP_POLY4_C0_PH0(a) ((0x7f&a)<<24) +#define VP_POLY4_C0_PH1(a) ((0x7f&a)<<16) +#define VP_POLY4_C0_PH2(a) ((0x7f&a)<<8) +#define VP_POLY4_C0_PH3(a) ((0x7f&a)<<0) + +#define VP_POLY4_C0_PH4(a) ((0x3f&a)<<24) +#define VP_POLY4_C0_PH5(a) ((0x3f&a)<<16) +#define VP_POLY4_C0_PH6(a) ((0x3f&a)<<8) +#define VP_POLY4_C0_PH7(a) ((0x3f&a)<<0) + +#define VP_POLY4_C0_PH8(a) ((0x3f&a)<<24) +#define VP_POLY4_C0_PH9(a) ((0x3f&a)<<16) +#define VP_POLY4_C0_PH10(a) ((0x3f&a)<<8) +#define VP_POLY4_C0_PH11(a) ((0x3f&a)<<0) + +#define VP_POLY4_C0_PH12(a) ((0x1f&a)<<24) +#define VP_POLY4_C0_PH13(a) ((0x1f&a)<<16) +#define VP_POLY4_C0_PH14(a) ((0x1f&a)<<8) +#define VP_POLY4_C0_PH15(a) ((0x1f&a)<<0) + +#define VP_POLY4_C1_PH0(a) ((0xff&a)<<24) +#define VP_POLY4_C1_PH1(a) ((0xff&a)<<16) +#define VP_POLY4_C1_PH2(a) ((0xff&a)<<8) +#define VP_POLY4_C1_PH3(a) ((0xff&a)<<0) + +#define VP_POLY4_C1_PH4(a) ((0xff&a)<<24) +#define VP_POLY4_C1_PH5(a) ((0xff&a)<<16) +#define VP_POLY4_C1_PH6(a) ((0xff&a)<<8) +#define VP_POLY4_C1_PH7(a) ((0xff&a)<<0) + +#define VP_POLY4_C1_PH8(a) ((0xff&a)<<24) +#define VP_POLY4_C1_PH9(a) ((0xff&a)<<16) +#define VP_POLY4_C1_PH10(a) ((0xff&a)<<8) +#define VP_POLY4_C1_PH11(a) ((0xff&a)<<0) + +#define VP_POLY4_C1_PH12(a) ((0x7f&a)<<24) +#define VP_POLY4_C1_PH13(a) ((0x7f&a)<<16) +#define VP_POLY4_C1_PH14(a) ((0x7f&a)<<8) +#define VP_POLY4_C1_PH15(a) ((0x7f&a)<<0) + +#define VP_CSC_COEF(a) (0xfff&a) + +#define VP_BY_PASS_ENABLE (0) +#define VP_BY_PASS_DISABLE (1) + +#define VP_SATURATION(a) (0xff&a) + +#define VP_TH_HNOISE(a) ((0xf&a)<<8) +#define VP_SHARPNESS(a) (0x3&a) + +#define VP_LINE_INTC(a) ((0xffff&a)<<8) +#define VP_LINE_SLOPE(a) (0xff&a) +#define VP_LINE_INTC_CLEAR(a) (~(0xffff<<8)&a) +#define VP_LINE_SLOPE_CLEAR(a) (~0xff&a) + +#define VP_BRIGHT_OFFSET(a) (0x1ff&a) + +#define VP_SUB_Y_OFFSET_ENABLE (1<<1) +#define VP_SUB_Y_OFFSET_DISABLE (0<<1) +#define VP_CSC_ENABLE (1) +#define VP_CSC_DISABLE (0) + +static unsigned int g_vp_contrast_brightness; + +#define Y2Y_COEF_601_TO_709 0x400 +#define CB2Y_COEF_601_TO_709 0x879 +#define CR2Y_COEF_601_TO_709 0x8d9 + +#define Y2CB_COEF_601_TO_709 0x0 +#define CB2CB_COEF_601_TO_709 0x413 +#define CR2CB_COEF_601_TO_709 0x875 + +#define Y2CR_COEF_601_TO_709 0x0 +#define CB2CR_COEF_601_TO_709 0x04d +#define CR2CR_COEF_601_TO_709 0x41a + +#define Y2Y_COEF_709_TO_601 0x400 +#define CB2Y_COEF_709_TO_601 0x068 +#define CR2Y_COEF_709_TO_601 0x0c9 + +#define Y2CB_COEF_709_TO_601 0x0 +#define CB2CB_COEF_709_TO_601 0x3f6 +#define CR2CB_COEF_709_TO_601 0x871 + +#define Y2CR_COEF_709_TO_601 0x0 +#define CB2CR_COEF_709_TO_601 0x84a +#define CR2CR_COEF_709_TO_601 0xbef + +#define TILE_WIDTH 0x40 +#define MAX_NUM_OF_FRM 34 + +#endif + diff --git a/drivers/media/video/samsung/tv20/s5pc100/sdout_s5pc100.c b/drivers/media/video/samsung/tv20/s5pc100/sdout_s5pc100.c new file mode 100644 index 0000000..4346348 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/sdout_s5pc100.c @@ -0,0 +1,2031 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/sdout_s5pc100.c + * + * tv encoder raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/sizes.h> +#include <linux/memory.h> + +#include "tv_out_s5pc100.h" + +#include "regs/regs-sdaout.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_SDAOUT_DEBUG 1 +#endif + +#ifdef S5P_SDAOUT_DEBUG +#define SDPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[SDOUT] %s: " fmt, __func__ , ## args) +#else +#define SDPRINTK(fmt, args...) +#endif + +static struct resource *sdout_mem; +void __iomem *sdout_base; + +/* +* initialization - iniization functions are only called under stopping SDOUT +*/ +enum s5p_tv_sd_err __s5p_sdout_init_video_scale_cfg( + enum s5p_sd_level component_level, + enum s5p_sd_vsync_ratio component_ratio, + enum s5p_sd_level composite_level, + enum s5p_sd_vsync_ratio composite_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d\n\r", component_level, component_ratio, + composite_level, composite_ratio); + + switch (component_level) { + + case S5P_TV_SD_LEVEL_0IRE: + temp_reg = SDO_COMPONENT_LEVEL_SEL_0IRE; + break; + + case S5P_TV_SD_LEVEL_75IRE: + temp_reg = SDO_COMPONENT_LEVEL_SEL_75IRE; + break; + + default: + SDPRINTK("invalid component_level parameter(%d)\n\r", + component_level); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (composite_level) { + + case SDOUT_VTOS_RATIO_10_4: + temp_reg |= SDO_COMPONENT_VTOS_RATIO_10_4; + break; + + case SDOUT_VTOS_RATIO_7_3: + temp_reg |= SDO_COMPONENT_VTOS_RATIO_7_3; + break; + + default: + SDPRINTK(" invalid composite_level parameter(%d)\n\r", + composite_level); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (composite_level) { + + case S5P_TV_SD_LEVEL_0IRE: + temp_reg |= SDO_COMPOSITE_LEVEL_SEL_0IRE; + break; + + case S5P_TV_SD_LEVEL_75IRE: + temp_reg |= SDO_COMPOSITE_LEVEL_SEL_75IRE; + break; + + default: + SDPRINTK("invalid composite_ratio parameter(%d)\n\r", + composite_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (composite_ratio) { + + case SDOUT_VTOS_RATIO_10_4: + temp_reg |= SDO_COMPOSITE_VTOS_RATIO_10_4; + break; + + case SDOUT_VTOS_RATIO_7_3: + temp_reg |= SDO_COMPOSITE_VTOS_RATIO_7_3; + break; + + default: + SDPRINTK("invalid component_ratio parameter(%d)\n\r", + component_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_SCALE); + + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_SCALE)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_sync_signal_pin( + enum s5p_sd_sync_sig_pin pin) +{ + SDPRINTK("%d\n\r", pin); + + switch (pin) { + + case SDOUT_SYNC_SIG_NO: + writel(SDO_COMPONENT_SYNC_ABSENT, sdout_base + S5P_SDO_SYNC); + break; + + case SDOUT_SYNC_SIG_YG: + writel(SDO_COMPONENT_SYNC_YG, sdout_base + S5P_SDO_SYNC); + break; + + case SDOUT_SYNC_SIG_ALL: + writel(SDO_COMPONENT_SYNC_ALL, sdout_base + S5P_SDO_SYNC); + break; + + default: + SDPRINTK("invalid pin parameter(%d)\n\r", pin); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_SYNC)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_vbi(bool wss_cvbs, + enum s5p_sd_closed_caption_type caption_cvbs, + bool wss_y_sideo, + enum s5p_sd_closed_caption_type caption_y_sideo, + bool cgmsa_rgb, + bool wss_rgb, + enum s5p_sd_closed_caption_type caption_rgb, + bool cgmsa_y_ppr, + bool wss_y_ppr, + enum s5p_sd_closed_caption_type caption_y_ppr) +{ + u32 temp_reg = 0; + + SDPRINTK(" %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n\r", + wss_cvbs, caption_cvbs, wss_y_sideo, caption_y_sideo, + cgmsa_rgb, wss_rgb, caption_rgb, cgmsa_y_ppr, wss_y_ppr, + caption_y_ppr); + + if (wss_cvbs) + temp_reg = SDO_CVBS_WSS_INS; + else + temp_reg = SDO_CVBS_NO_WSS; + + + switch (caption_cvbs) { + + case SDOUT_NO_INS: + temp_reg |= SDO_CVBS_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_CVBS_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_CVBS_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_CVBS_USE_OTHERS; + break; + + default: + SDPRINTK(" invalid caption_cvbs parameter(%d)\n\r", + caption_cvbs); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (wss_y_sideo) + temp_reg |= SDO_SVIDEO_WSS_INS; + else + temp_reg |= SDO_SVIDEO_NO_WSS; + + + switch (caption_y_sideo) { + + case SDOUT_NO_INS: + temp_reg |= SDO_SVIDEO_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_SVIDEO_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_SVIDEO_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_SVIDEO_USE_OTHERS; + break; + + default: + SDPRINTK("invalid caption_y_sideo parameter(%d)\n\r", + caption_y_sideo); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (cgmsa_rgb) + temp_reg |= SDO_RGB_CGMSA_INS; + else + temp_reg |= SDO_RGB_NO_CGMSA; + + + if (wss_rgb) + temp_reg |= SDO_RGB_WSS_INS; + else + temp_reg |= SDO_RGB_NO_WSS; + + + switch (caption_rgb) { + + case SDOUT_NO_INS: + temp_reg |= SDO_RGB_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_RGB_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_RGB_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_RGB_USE_OTHERS; + break; + + default: + SDPRINTK(" invalid caption_rgb parameter(%d)\n\r", + caption_rgb); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (cgmsa_y_ppr) + temp_reg |= SDO_YPBPR_CGMSA_INS; + else + temp_reg |= SDO_YPBPR_NO_CGMSA; + + if (wss_y_ppr) + temp_reg |= SDO_YPBPR_WSS_INS; + else + temp_reg |= SDO_YPBPR_NO_WSS; + + + switch (caption_y_ppr) { + + case SDOUT_NO_INS: + temp_reg |= SDO_YPBPR_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_YPBPR_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_YPBPR_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_YPBPR_USE_OTHERS; + break; + + default: + SDPRINTK("invalid caption_y_ppr parameter(%d)\n\r", + caption_y_ppr); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_VBI); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_VBI)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_offset_gain( + enum s5p_sd_channel_sel channel, + u32 offset, u32 gain) +{ + SDPRINTK("%d, %d, %d\n\r", channel, offset, gain); + + switch (channel) { + + case SDOUT_CHANNEL_0: + writel(SDO_SCALE_CONV_OFFSET(offset) | + SDO_SCALE_CONV_GAIN(gain), + sdout_base + S5P_SDO_SCALE_CH0); + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_SCALE_CH0)); + break; + + case SDOUT_CHANNEL_1: + writel(SDO_SCALE_CONV_OFFSET(offset) | + SDO_SCALE_CONV_GAIN(gain), + sdout_base + S5P_SDO_SCALE_CH1); + SDPRINTK(" 0x%08x\n\r", readl(sdout_base + S5P_SDO_SCALE_CH1)); + break; + + case SDOUT_CHANNEL_2: + writel(SDO_SCALE_CONV_OFFSET(offset) | + SDO_SCALE_CONV_GAIN(gain), + sdout_base + S5P_SDO_SCALE_CH2); + SDPRINTK(" 0x%08x\n\r", readl(sdout_base + S5P_SDO_SCALE_CH2)); + break; + + default: + SDPRINTK(" invalid channel parameter(%d)\n\r", channel); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_delay(u32 delay_y, + u32 offset_video_start, + u32 offset_video_end) +{ + SDPRINTK("%d, %d, %d\n\r", delay_y, + offset_video_start, offset_video_end); + + writel(SDO_DELAY_YTOC(delay_y) | + SDO_ACTIVE_START_OFFSET(offset_video_start) | + SDO_ACTIVE_END_OFFSET(offset_video_end), + sdout_base + S5P_SDO_YCDELAY); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_YCDELAY)); +} + +void __s5p_sdout_init_schlock(bool color_sucarrier_pha_adj) +{ + SDPRINTK("%d\n\r", color_sucarrier_pha_adj); + + if (color_sucarrier_pha_adj) + writel(SDO_COLOR_SC_PHASE_ADJ, sdout_base + S5P_SDO_SCHLOCK); + else + writel(SDO_COLOR_SC_PHASE_NOADJ, sdout_base + S5P_SDO_SCHLOCK); + + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_SCHLOCK)); +} + +enum s5p_tv_sd_err __s5p_sdout_init_dac_power_onoff( + enum s5p_sd_channel_sel channel, bool dac_on) +{ + u32 temp_on_off; + + SDPRINTK("%d, %d)\n\r", channel, dac_on); + + switch (channel) { + + case SDOUT_CHANNEL_0: + temp_on_off = SDO_POWER_ON_DAC0; + break; + + case SDOUT_CHANNEL_1: + temp_on_off = SDO_POWER_ON_DAC1; + break; + + case SDOUT_CHANNEL_2: + temp_on_off = SDO_POWER_ON_DAC2; + break; + + default: + SDPRINTK("invalid channel parameter(%d)\n\r", channel); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (dac_on) + writel(readl(sdout_base + S5P_SDO_DAC) | temp_on_off, + sdout_base + S5P_SDO_DAC); + else + writel(readl(sdout_base + S5P_SDO_DAC) & ~temp_on_off, + sdout_base + S5P_SDO_DAC); + + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_DAC)); + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_color_compensaton_onoff(bool bright_hue_saturation_adj, + bool y_ppr_color_compensation, + bool rgcolor_compensation, + bool y_c_color_compensation, + bool y_cvbs_color_compensation) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d, %d)\n\r", bright_hue_saturation_adj, + y_ppr_color_compensation, rgcolor_compensation, + y_c_color_compensation, y_cvbs_color_compensation); + + if (bright_hue_saturation_adj) + temp_reg &= ~SDO_COMPONENT_BHS_ADJ_OFF; + else + temp_reg |= SDO_COMPONENT_BHS_ADJ_OFF; + + + if (y_ppr_color_compensation) + temp_reg &= ~SDO_COMPONENT_YPBPR_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_YPBPR_COMP_OFF; + + + if (rgcolor_compensation) + temp_reg &= ~SDO_COMPONENT_RGB_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_RGB_COMP_OFF; + + + if (y_c_color_compensation) + temp_reg &= ~SDO_COMPONENT_YC_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_YC_COMP_OFF; + + + if (y_cvbs_color_compensation) + temp_reg &= ~SDO_COMPONENT_CVBS_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_CVBS_COMP_OFF; + + + writel(temp_reg, sdout_base + S5P_SDO_CCCON); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_CCCON)); +} + +void __s5p_sdout_init_brightness_hue_saturation(u32 gain_brightness, + u32 offset_brightness, + u32 gain0_cb_hue_saturation, + u32 gain1_cb_hue_saturation, + u32 gain0_cr_hue_saturation, + u32 gain1_cr_hue_saturation, + u32 offset_cb_hue_saturation, + u32 offset_cr_hue_saturation) +{ + SDPRINTK(" %d, %d, %d, %d, %d, %d, %d, %d)\n\r", gain_brightness, + offset_brightness, gain0_cb_hue_saturation, + gain1_cb_hue_saturation, gain0_cr_hue_saturation, + gain1_cr_hue_saturation, offset_cb_hue_saturation, + offset_cr_hue_saturation); + + writel(SDO_BRIGHTNESS_GAIN(gain_brightness) | + SDO_BRIGHTNESS_OFFSET(offset_brightness), + sdout_base + S5P_SDO_YSCALE); + + writel(SDO_HS_CB_GAIN0(gain0_cb_hue_saturation) | + SDO_HS_CB_GAIN1(gain1_cb_hue_saturation), + sdout_base + S5P_SDO_CBSCALE); + + writel(SDO_HS_CR_GAIN0(gain0_cr_hue_saturation) | + SDO_HS_CR_GAIN1(gain1_cr_hue_saturation), + sdout_base + S5P_SDO_CRSCALE); + + writel(SDO_HS_CR_OFFSET(offset_cr_hue_saturation) | + SDO_HS_CB_OFFSET(offset_cb_hue_saturation), + sdout_base + S5P_SDO_CB_CR_OFFSET); + + SDPRINTK("0x%08x, 0x%08x, 0x%08x, 0x%08x)\n\r", + readl(sdout_base + S5P_SDO_YSCALE), + readl(sdout_base + S5P_SDO_CBSCALE), + readl(sdout_base + S5P_SDO_CRSCALE), + readl(sdout_base + S5P_SDO_CB_CR_OFFSET)); +} + +void __s5p_sdout_init_rgb_color_compensation(u32 max_rgbcube, + u32 min_rgbcube) +{ + SDPRINTK("0x%08x, 0x%08x\n\r", max_rgbcube, min_rgbcube); + + writel(SDO_MAX_RGB_CUBE(max_rgbcube) | SDO_MIN_RGB_CUBE(min_rgbcube), + sdout_base + S5P_SDO_RGB_CC); + + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_RGB_CC)); +} + +void __s5p_sdout_init_cvbs_color_compensation(u32 y_lower_mid, + u32 y_bottom, + u32 y_top, + u32 y_upper_mid, + u32 radius) +{ + SDPRINTK("%d, %d, %d, %d, %d\n\r", y_lower_mid, y_bottom, + y_top, y_upper_mid, radius); + + writel(SDO_Y_LOWER_MID_CVBS_CORN(y_lower_mid) | + SDO_Y_BOTTOM_CVBS_CORN(y_bottom), + sdout_base + S5P_SDO_CVBS_CC_Y1); + writel(SDO_Y_TOP_CVBS_CORN(y_top) | + SDO_Y_UPPER_MID_CVBS_CORN(y_upper_mid), + sdout_base + S5P_SDO_CVBS_CC_Y2); + writel(SDO_RADIUS_CVBS_CORN(radius), sdout_base + S5P_SDO_CVBS_CC_C); + + SDPRINTK("0x%08x, 0x%08x, 0x%08x)\n\r", + readl(sdout_base + S5P_SDO_CVBS_CC_Y1), + readl(sdout_base + S5P_SDO_CVBS_CC_Y2), + readl(sdout_base + S5P_SDO_CVBS_CC_C)); +} + +void __s5p_sdout_init_svideo_color_compensation(u32 y_top, + u32 y_bottom, + u32 y_c_cylinder) +{ + SDPRINTK(" %d, %d, %d)\n\r", y_top, y_bottom, y_c_cylinder); + + writel(SDO_Y_TOP_YC_CYLINDER(y_top) | + SDO_Y_BOTOM_YC_CYLINDER(y_bottom), + sdout_base + S5P_SDO_YC_CC_Y); + writel(SDO_RADIUS_YC_CYLINDER(y_c_cylinder), + sdout_base + S5P_SDO_YC_CC_C); + + SDPRINTK("0x%08x, 0x%08x)\n\r", readl(sdout_base + S5P_SDO_YC_CC_Y), + readl(sdout_base + S5P_SDO_YC_CC_C)); +} + +void __s5p_sdout_init_component_porch(u32 back_525, + u32 front_525, + u32 back_625, + u32 front_625) +{ + SDPRINTK(" %d, %d, %d, %d)\n\r", back_525, + front_525, back_625, front_625); + + writel(SDO_COMPONENT_525_BP(back_525) | + SDO_COMPONENT_525_FP(front_525), + sdout_base + S5P_SDO_CSC_525_PORCH); + writel(SDO_COMPONENT_625_BP(back_625) | + SDO_COMPONENT_625_FP(front_625), + sdout_base + S5P_SDO_CSC_625_PORCH); + + SDPRINTK(" 0x%08x, 0x%08x)\n\r", + readl(sdout_base + S5P_SDO_CSC_525_PORCH), + readl(sdout_base + S5P_SDO_CSC_625_PORCH)); +} + +enum s5p_tv_sd_err __s5p_sdout_init_vesa_rgb_sync( + enum s5p_sd_vesa_rgb_sync_type sync_type, + enum s5p_tv_active_polarity v_sync_active, + enum s5p_tv_active_polarity h_sync_active) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d\n\r", sync_type, v_sync_active, h_sync_active); + + switch (sync_type) { + + case SDOUT_VESA_RGB_SYNC_COMPOSITE: + temp_reg |= SDO_RGB_SYNC_COMPOSITE; + break; + + case SDOUT_VESA_RGB_SYNC_SEPARATE: + temp_reg |= SDO_RGB_SYNC_SEPERATE; + break; + + default: + SDPRINTK(" invalid sync_type parameter(%d)\n\r", sync_type); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (v_sync_active) { + + case TVOUT_POL_ACTIVE_LOW: + temp_reg |= SDO_RGB_VSYNC_LOW_ACT; + break; + + case TVOUT_POL_ACTIVE_HIGH: + temp_reg |= SDO_RGB_VSYNC_HIGH_ACT; + break; + + default: + SDPRINTK(" invalid v_sync_active parameter(%d)\n\r", + v_sync_active); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (h_sync_active) { + + case TVOUT_POL_ACTIVE_LOW: + temp_reg |= SDO_RGB_HSYNC_LOW_ACT; + break; + + case TVOUT_POL_ACTIVE_HIGH: + temp_reg |= SDO_RGB_HSYNC_HIGH_ACT; + break; + + default: + SDPRINTK(" invalid h_sync_active parameter(%d)\n\r", + h_sync_active); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_RGBSYNC); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_RGBSYNC)); + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_oversampling_filter_coeff(u32 size, + u32 *coeff, + u32 *coeff1, + u32 *coeff2) +{ + u32 *temp_reg = 0; + + SDPRINTK(" %d, 0x%x, 0x%x, 0x%x\n\r", (u32)size, (u32)coeff, + (u32)coeff1, (u32)coeff2); + + if (coeff != NULL) { + temp_reg = (u32 *)readl(sdout_base + S5P_SDO_OSFC00_0); + memcpy((void *)temp_reg, (const void *)coeff, size*4); + } + + if (coeff1 != NULL) { + temp_reg = (u32 *)readl(sdout_base + S5P_SDO_OSFC00_1); + memcpy((void *)temp_reg, (const void *)coeff1, size*4); + } + + if (coeff2 != NULL) { + temp_reg = (u32 *)readl(sdout_base + S5P_SDO_OSFC00_2); + memcpy((void *)temp_reg, (const void *)coeff2, size*4); + } + + SDPRINTK(" ()\n\r"); +} + +enum s5p_tv_sd_err __s5p_sdout_init_ch_xtalk_cancel_coef( + enum s5p_sd_channel_sel channel, + u32 coeff2, u32 coeff1) +{ + SDPRINTK(" %d, %d, %d\n\r", channel, coeff2, coeff1); + + switch (channel) { + + case SDOUT_CHANNEL_0: + writel(SDO_XTALK_COEF02(coeff2) | SDO_XTALK_COEF01(coeff1), + sdout_base + S5P_SDO_XTALK0); + SDPRINTK(" 0x%08x)\n\r", readl(sdout_base + S5P_SDO_XTALK0)); + break; + + case SDOUT_CHANNEL_1: + writel(SDO_XTALK_COEF02(coeff2) | SDO_XTALK_COEF01(coeff1), + sdout_base + S5P_SDO_XTALK1); + SDPRINTK(" 0x%08x)\n\r", readl(sdout_base + S5P_SDO_XTALK1)); + break; + + case SDOUT_CHANNEL_2: + writel(SDO_XTALK_COEF02(coeff2) | SDO_XTALK_COEF01(coeff1), + sdout_base + S5P_SDO_XTALK2); + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_XTALK2)); + break; + + default: + SDPRINTK(" invalid channel parameter(%d)\n\r", channel); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_closed_caption(u32 display_cc, u32 non_display_cc) +{ + SDPRINTK("%d, %d\n\r", display_cc, non_display_cc); + + writel(SDO_DISPLAY_CC_CAPTION(display_cc) | + SDO_NON_DISPLAY_CC_CAPTION(non_display_cc), + sdout_base + S5P_SDO_ARMCC); + + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_ARMCC)); +} + + +static u32 __s5p_sdout_init_wss_cgms_crc(u32 value) +{ + u8 i; + u8 CGMS[14], CRC[6], OLD_CRC; + u32 temp_in; + + temp_in = value; + + for (i = 0; i < 14; i++) + CGMS[i] = (u8)(temp_in >> i) & 0x1 ; + + for (i = 0; i < 6; i++) + CRC[i] = 0x1; + + for (i = 0; i < 14; i++) { + OLD_CRC = CRC[0]; + CRC[0] = CRC[1]; + CRC[1] = CRC[2]; + CRC[2] = CRC[3]; + CRC[3] = CRC[4]; + CRC[4] = OLD_CRC ^ CGMS[i] ^ CRC[5]; + CRC[5] = OLD_CRC ^ CGMS[i]; + } + + temp_in &= 0x3fff; + + for (i = 0; i < 6; i++) + temp_in |= ((u32)(CRC[i] & 0x1) << i); + + + return temp_in; +} + + +enum s5p_tv_sd_err __s5p_sdout_init_wss525_data( + enum s5p_sd_525_copy_permit copy_permit, + enum s5p_sd_525_mv_psp mv_psp, + enum s5p_sd_525_copy_info copy_info, + bool analog_on, + enum s5p_sd_525_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d\n\r", copy_permit, mv_psp, copy_info, + display_ratio); + + switch (copy_permit) { + + case SDO_525_COPY_PERMIT: + temp_reg = SDO_WORD2_WSS525_COPY_PERMIT; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg = SDO_WORD2_WSS525_ONECOPY_PERMIT; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg = SDO_WORD2_WSS525_NOCOPY_PERMIT; + break; + + default: + SDPRINTK(" invalid copy_permit parameter(%d)\n\r", + copy_permit); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (mv_psp) { + + case SDO_525_MV_PSP_OFF: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_OFF; + break; + + case SDO_525_MV_PSP_ON_2LINE_BURST: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_ON_2LINE_BURST; + break; + + case SDO_525_MV_PSP_ON_BURST_OFF: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_ON_BURST_OFF; + break; + + case SDO_525_MV_PSP_ON_4LINE_BURST: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_ON_4LINE_BURST; + break; + + default: + SDPRINTK(" invalid mv_psp parameter(%d)\n\r", mv_psp); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (copy_info) { + + case SDO_525_COPY_INFO: + temp_reg |= SDO_WORD1_WSS525_COPY_INFO; + break; + + case SDO_525_DEFAULT: + temp_reg |= SDO_WORD1_WSS525_DEFAULT; + break; + + default: + SDPRINTK(" invalid copy_info parameter(%d)\n\r", copy_info); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (analog_on) + temp_reg |= SDO_WORD2_WSS525_ANALOG_ON; + else + temp_reg |= SDO_WORD2_WSS525_ANALOG_OFF; + + + switch (display_ratio) { + + case SDO_525_COPY_PERMIT: + temp_reg |= SDO_WORD0_WSS525_4_3_NORMAL; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg |= SDO_WORD0_WSS525_16_9_ANAMORPIC; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg |= SDO_WORD0_WSS525_4_3_LETTERBOX; + break; + + default: + SDPRINTK(" invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg | SDO_CRC_WSS525( + __s5p_sdout_init_wss_cgms_crc(temp_reg)), + sdout_base + S5P_SDO_WSS525); + + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_WSS525)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_wss625_data(bool surround_sound, + bool copyright, + bool copy_protection, + bool text_subtitles, + enum s5p_sd_625_subtitles open_subtitles, + enum s5p_sd_625_camera_film camera_film, + enum s5p_sd_625_color_encoding color_encoding, + bool helper_signal, + enum s5p_sd_625_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d, %d, %d, %d, %d, %d\n\r", + surround_sound, copyright, copy_protection, + text_subtitles, open_subtitles, camera_film, + color_encoding, helper_signal, display_ratio); + + if (surround_sound) + temp_reg = SDO_WSS625_SURROUND_SOUND_ENABLE; + else + temp_reg = SDO_WSS625_SURROUND_SOUND_DISABLE; + + + if (copyright) + temp_reg |= SDO_WSS625_COPYRIGHT; + else + temp_reg |= SDO_WSS625_NO_COPYRIGHT; + + + if (copy_protection) + temp_reg |= SDO_WSS625_COPY_RESTRICTED; + else + temp_reg |= SDO_WSS625_COPY_NOT_RESTRICTED; + + + if (text_subtitles) + temp_reg |= SDO_WSS625_TELETEXT_SUBTITLES; + else + temp_reg |= SDO_WSS625_TELETEXT_NO_SUBTITLES; + + + switch (open_subtitles) { + + case SDO_625_NO_OPEN_SUBTITLES: + temp_reg |= SDO_WSS625_NO_OPEN_SUBTITLES; + break; + + case SDO_625_INACT_OPEN_SUBTITLES: + temp_reg |= SDO_WSS625_INACT_OPEN_SUBTITLES; + break; + + case SDO_625_OUTACT_OPEN_SUBTITLES: + temp_reg |= SDO_WSS625_OUTACT_OPEN_SUBTITLES; + break; + + default: + SDPRINTK(" invalid open_subtitles parameter(%d)\n\r", + open_subtitles); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (camera_film) { + + case SDO_625_CAMERA: + temp_reg |= SDO_WSS625_CAMERA; + break; + + case SDO_625_FILM: + temp_reg |= SDO_WSS625_FILM; + break; + + default: + SDPRINTK("invalid camera_film parameter(%d)\n\r", camera_film); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (color_encoding) { + + case SDO_625_NORMAL_PAL: + temp_reg |= SDO_WSS625_NORMAL_PAL; + break; + + case SDO_625_MOTION_ADAPTIVE_COLORPLUS: + temp_reg |= SDO_WSS625_MOTION_ADAPTIVE_COLORPLUS; + break; + + default: + SDPRINTK("invalid color_encoding parameter(%d)\n\r", + color_encoding); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (helper_signal) + temp_reg |= SDO_WSS625_HELPER_SIG; + else + temp_reg |= SDO_WSS625_HELPER_NO_SIG; + + + switch (display_ratio) { + + case SDO_625_4_3_FULL_576: + temp_reg |= SDO_WSS625_4_3_FULL_576; + break; + + case SDO_625_14_9_LETTERBOX_CENTER_504: + temp_reg |= SDO_WSS625_14_9_LETTERBOX_CENTER_504; + break; + + case SDO_625_14_9_LETTERBOX_TOP_504: + temp_reg |= SDO_WSS625_14_9_LETTERBOX_TOP_504; + break; + + case SDO_625_16_9_LETTERBOX_CENTER_430: + temp_reg |= SDO_WSS625_16_9_LETTERBOX_CENTER_430; + break; + + case SDO_625_16_9_LETTERBOX_TOP_430: + temp_reg |= SDO_WSS625_16_9_LETTERBOX_TOP_430; + break; + + case SDO_625_16_9_LETTERBOX_CENTER: + temp_reg |= SDO_WSS625_16_9_LETTERBOX_CENTER; + break; + + case SDO_625_14_9_FULL_CENTER_576: + temp_reg |= SDO_WSS625_14_9_FULL_CENTER_576; + break; + + case SDO_625_16_9_ANAMORPIC_576: + temp_reg |= SDO_WSS625_16_9_ANAMORPIC_576; + break; + + default: + SDPRINTK("invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_WSS625); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_WSS625)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_cgmsa525_data( + enum s5p_sd_525_copy_permit copy_permit, + enum s5p_sd_525_mv_psp mv_psp, + enum s5p_sd_525_copy_info copy_info, + bool analog_on, + enum s5p_sd_525_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d)\n\r", copy_permit, mv_psp, + copy_info, display_ratio); + + switch (copy_permit) { + + case SDO_525_COPY_PERMIT: + temp_reg = SDO_WORD2_CGMS525_COPY_PERMIT; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg = SDO_WORD2_CGMS525_ONECOPY_PERMIT; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg = SDO_WORD2_CGMS525_NOCOPY_PERMIT; + break; + + default: + SDPRINTK("invalid copy_permit parameter(%d)\n\r", copy_permit); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (mv_psp) { + + case SDO_525_MV_PSP_OFF: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_OFF; + break; + + case SDO_525_MV_PSP_ON_2LINE_BURST: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_ON_2LINE_BURST; + break; + + case SDO_525_MV_PSP_ON_BURST_OFF: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_ON_BURST_OFF; + break; + + case SDO_525_MV_PSP_ON_4LINE_BURST: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_ON_4LINE_BURST; + break; + + default: + SDPRINTK(" invalid mv_psp parameter(%d)\n\r", mv_psp); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (copy_info) { + + case SDO_525_COPY_INFO: + temp_reg |= SDO_WORD1_CGMS525_COPY_INFO; + break; + + case SDO_525_DEFAULT: + temp_reg |= SDO_WORD1_CGMS525_DEFAULT; + break; + + default: + SDPRINTK("invalid copy_info parameter(%d)\n\r", copy_info); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (analog_on) + temp_reg |= SDO_WORD2_CGMS525_ANALOG_ON; + else + temp_reg |= SDO_WORD2_CGMS525_ANALOG_OFF; + + + switch (display_ratio) { + + case SDO_525_COPY_PERMIT: + temp_reg |= SDO_WORD0_CGMS525_4_3_NORMAL; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg |= SDO_WORD0_CGMS525_16_9_ANAMORPIC; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg |= SDO_WORD0_CGMS525_4_3_LETTERBOX; + break; + + default: + SDPRINTK(" invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg | + SDO_CRC_CGMS525(__s5p_sdout_init_wss_cgms_crc(temp_reg)), + sdout_base + S5P_SDO_CGMS525); + + SDPRINTK(" 0x%08x)\n\r", readl(sdout_base + S5P_SDO_CGMS525)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_cgmsa625_data(bool surround_sound, + bool copyright, + bool copy_protection, + bool text_subtitles, + enum s5p_sd_625_subtitles open_subtitles, + enum s5p_sd_625_camera_film camera_film, + enum s5p_sd_625_color_encoding color_encoding, + bool helper_signal, + enum s5p_sd_625_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d, %d, %d, %d, %d, %d)\n\r", + surround_sound, copyright, copy_protection, + text_subtitles, open_subtitles, camera_film, + color_encoding, helper_signal, display_ratio); + + if (surround_sound) + temp_reg = SDO_CGMS625_SURROUND_SOUND_ENABLE; + else + temp_reg = SDO_CGMS625_SURROUND_SOUND_DISABLE; + + + if (copyright) + temp_reg |= SDO_CGMS625_COPYRIGHT; + else + temp_reg |= SDO_CGMS625_NO_COPYRIGHT; + + + if (copy_protection) + temp_reg |= SDO_CGMS625_COPY_RESTRICTED; + else + temp_reg |= SDO_CGMS625_COPY_NOT_RESTRICTED; + + + if (text_subtitles) + temp_reg |= SDO_CGMS625_TELETEXT_SUBTITLES; + else + temp_reg |= SDO_CGMS625_TELETEXT_NO_SUBTITLES; + + switch (open_subtitles) { + + case SDO_625_NO_OPEN_SUBTITLES: + temp_reg |= SDO_CGMS625_NO_OPEN_SUBTITLES; + break; + + case SDO_625_INACT_OPEN_SUBTITLES: + temp_reg |= SDO_CGMS625_INACT_OPEN_SUBTITLES; + break; + + case SDO_625_OUTACT_OPEN_SUBTITLES: + temp_reg |= SDO_CGMS625_OUTACT_OPEN_SUBTITLES; + break; + + default: + SDPRINTK("invalid open_subtitles parameter(%d)\n\r", + open_subtitles); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (camera_film) { + + case SDO_625_CAMERA: + temp_reg |= SDO_CGMS625_CAMERA; + break; + + case SDO_625_FILM: + temp_reg |= SDO_CGMS625_FILM; + break; + + default: + SDPRINTK(" invalid camera_film parameter(%d)\n\r", + camera_film); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (color_encoding) { + + case SDO_625_NORMAL_PAL: + temp_reg |= SDO_CGMS625_NORMAL_PAL; + break; + + case SDO_625_MOTION_ADAPTIVE_COLORPLUS: + temp_reg |= SDO_CGMS625_MOTION_ADAPTIVE_COLORPLUS; + break; + + default: + SDPRINTK(" invalid color_encoding parameter(%d)\n\r", + color_encoding); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (helper_signal) + temp_reg |= SDO_CGMS625_HELPER_SIG; + else + temp_reg |= SDO_CGMS625_HELPER_NO_SIG; + + + switch (display_ratio) { + + case SDO_625_4_3_FULL_576: + temp_reg |= SDO_CGMS625_4_3_FULL_576; + break; + + case SDO_625_14_9_LETTERBOX_CENTER_504: + temp_reg |= SDO_CGMS625_14_9_LETTERBOX_CENTER_504; + break; + + case SDO_625_14_9_LETTERBOX_TOP_504: + temp_reg |= SDO_CGMS625_14_9_LETTERBOX_TOP_504; + break; + + case SDO_625_16_9_LETTERBOX_CENTER_430: + temp_reg |= SDO_CGMS625_16_9_LETTERBOX_CENTER_430; + break; + + case SDO_625_16_9_LETTERBOX_TOP_430: + temp_reg |= SDO_CGMS625_16_9_LETTERBOX_TOP_430; + break; + + case SDO_625_16_9_LETTERBOX_CENTER: + temp_reg |= SDO_CGMS625_16_9_LETTERBOX_CENTER; + break; + + case SDO_625_14_9_FULL_CENTER_576: + temp_reg |= SDO_CGMS625_14_9_FULL_CENTER_576; + break; + + case SDO_625_16_9_ANAMORPIC_576: + temp_reg |= SDO_CGMS625_16_9_ANAMORPIC_576; + break; + + default: + SDPRINTK("invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_CGMS625); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_CGMS625)); + + return SDOUT_NO_ERROR; +} + + +static enum s5p_tv_sd_err __s5p_sdout_init_antialias_filter_coeff_default( + enum s5p_sd_level composite_level, + enum s5p_sd_vsync_ratio composite_ratio, + enum s5p_tv_o_mode out_mode) +{ + SDPRINTK("%d, %d, %d\n\r", composite_level, composite_ratio, out_mode); + + switch (composite_level) { + + case S5P_TV_SD_LEVEL_0IRE: + + switch (composite_ratio) { + + case SDOUT_VTOS_RATIO_10_4: + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + writel(0x00000000 , sdout_base + S5P_SDO_Y3); + writel(0x00000000 , sdout_base + S5P_SDO_Y4); + writel(0x00000000 , sdout_base + S5P_SDO_Y5); + writel(0x00000000 , sdout_base + S5P_SDO_Y6); + writel(0x00000000 , sdout_base + S5P_SDO_Y7); + writel(0x00000000 , sdout_base + S5P_SDO_Y8); + writel(0x00000000 , sdout_base + S5P_SDO_Y9); + writel(0x00000000 , sdout_base + S5P_SDO_Y10); + writel(0x0000029a , sdout_base + S5P_SDO_Y11); + writel(0x00000000 , sdout_base + S5P_SDO_CB0); + writel(0x00000000 , sdout_base + S5P_SDO_CB1); + writel(0x00000000 , sdout_base + S5P_SDO_CB2); + writel(0x00000000 , sdout_base + S5P_SDO_CB3); + writel(0x00000000 , sdout_base + S5P_SDO_CB4); + writel(0x00000001 , sdout_base + S5P_SDO_CB5); + writel(0x00000007 , sdout_base + S5P_SDO_CB6); + writel(0x00000015 , sdout_base + S5P_SDO_CB7); + writel(0x0000002b , sdout_base + S5P_SDO_CB8); + writel(0x00000045 , sdout_base + S5P_SDO_CB9); + writel(0x00000059 , sdout_base + S5P_SDO_CB10); + writel(0x00000061 , sdout_base + S5P_SDO_CB11); + writel(0x00000000 , sdout_base + S5P_SDO_CR1); + writel(0x00000000 , sdout_base + S5P_SDO_CR2); + writel(0x00000000 , sdout_base + S5P_SDO_CR3); + writel(0x00000000 , sdout_base + S5P_SDO_CR4); + writel(0x00000002 , sdout_base + S5P_SDO_CR5); + writel(0x0000000a , sdout_base + S5P_SDO_CR6); + writel(0x0000001e , sdout_base + S5P_SDO_CR7); + writel(0x0000003d , sdout_base + S5P_SDO_CR8); + writel(0x00000061 , sdout_base + S5P_SDO_CR9); + writel(0x0000007a , sdout_base + S5P_SDO_CR10); + writel(0x0000008f , sdout_base + S5P_SDO_CR11); + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x0000029a, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000007, sdout_base + S5P_SDO_CB6); + writel(0x00000015, sdout_base + S5P_SDO_CB7); + writel(0x0000002b, sdout_base + S5P_SDO_CB8); + writel(0x00000045, sdout_base + S5P_SDO_CB9); + writel(0x00000059, sdout_base + S5P_SDO_CB10); + writel(0x00000061, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000002, sdout_base + S5P_SDO_CR5); + writel(0x0000000a, sdout_base + S5P_SDO_CR6); + writel(0x0000001e, sdout_base + S5P_SDO_CR7); + writel(0x0000003d, sdout_base + S5P_SDO_CR8); + writel(0x00000061, sdout_base + S5P_SDO_CR9); + writel(0x0000007a, sdout_base + S5P_SDO_CR10); + writel(0x0000008f, sdout_base + S5P_SDO_CR11); + break; + + default: + SDPRINTK("invalid out_mode parameter(%d)\n\r", + out_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case SDOUT_VTOS_RATIO_7_3: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x00000281, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000007, sdout_base + S5P_SDO_CB6); + writel(0x00000015, sdout_base + S5P_SDO_CB7); + writel(0x0000002a, sdout_base + S5P_SDO_CB8); + writel(0x00000044, sdout_base + S5P_SDO_CB9); + writel(0x00000057, sdout_base + S5P_SDO_CB10); + writel(0x0000005f, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000002, sdout_base + S5P_SDO_CR5); + writel(0x0000000a, sdout_base + S5P_SDO_CR6); + writel(0x0000001d, sdout_base + S5P_SDO_CR7); + writel(0x0000003c, sdout_base + S5P_SDO_CR8); + writel(0x0000005f, sdout_base + S5P_SDO_CR9); + writel(0x0000007b, sdout_base + S5P_SDO_CR10); + writel(0x00000086, sdout_base + S5P_SDO_CR11); + break; + + default: + SDPRINTK("invalid composite_ratio parameter(%d)\n\r", + composite_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case S5P_TV_SD_LEVEL_75IRE: + + switch (composite_ratio) { + + case SDOUT_VTOS_RATIO_10_4: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x0000025d, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000007, sdout_base + S5P_SDO_CB6); + writel(0x00000014, sdout_base + S5P_SDO_CB7); + writel(0x00000028, sdout_base + S5P_SDO_CB8); + writel(0x0000003f, sdout_base + S5P_SDO_CB9); + writel(0x00000052, sdout_base + S5P_SDO_CB10); + writel(0x0000005a, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000001, sdout_base + S5P_SDO_CR5); + writel(0x00000009, sdout_base + S5P_SDO_CR6); + writel(0x0000001c, sdout_base + S5P_SDO_CR7); + writel(0x00000039, sdout_base + S5P_SDO_CR8); + writel(0x0000005a, sdout_base + S5P_SDO_CR9); + writel(0x00000074, sdout_base + S5P_SDO_CR10); + writel(0x0000007e, sdout_base + S5P_SDO_CR11); + break; + + case SDOUT_VTOS_RATIO_7_3: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x00000251, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000006, sdout_base + S5P_SDO_CB6); + writel(0x00000013, sdout_base + S5P_SDO_CB7); + writel(0x00000028, sdout_base + S5P_SDO_CB8); + writel(0x0000003f, sdout_base + S5P_SDO_CB9); + writel(0x00000051, sdout_base + S5P_SDO_CB10); + writel(0x00000056, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000002, sdout_base + S5P_SDO_CR5); + writel(0x00000005, sdout_base + S5P_SDO_CR6); + writel(0x00000018, sdout_base + S5P_SDO_CR7); + writel(0x00000037, sdout_base + S5P_SDO_CR8); + writel(0x0000005A, sdout_base + S5P_SDO_CR9); + writel(0x00000076, sdout_base + S5P_SDO_CR10); + writel(0x0000007e, sdout_base + S5P_SDO_CR11); + break; + + default: + SDPRINTK(" invalid composite_ratio parameter(%d)\n\r", + composite_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + default: + SDPRINTK(" invalid composite_level parameter(%d)\n\r", + composite_level); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + SDPRINTK("()\n\r"); + + return SDOUT_NO_ERROR; + +} + + +static enum s5p_tv_sd_err __s5p_sdout_init_oversampling_filter_coeff_default( + enum s5p_tv_o_mode out_mode) +{ + u32 temp_reg = 0; + u8 i; + + SDPRINTK("%d\n\r", out_mode); + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + temp_reg = (u32)(sdout_base + S5P_SDO_OSFC00_0); + + for (i = 0; i < 3; i++) { + temp_reg = (u32)((i == 0) ? + sdout_base + S5P_SDO_OSFC00_0 : + (i == 1) ? + sdout_base + S5P_SDO_OSFC00_1 : + sdout_base + S5P_SDO_OSFC00_2); + + writel(((-2&0xfff) << 0) | ((-3&0xfff) << 0), + temp_reg + 0); + writel(0, + temp_reg + 1); + writel((4 << 0) | (5 << 16), + temp_reg + 2); + writel(((-1&0xfff) << 0) | (0 << 16), + temp_reg + 3); + writel(((-6&0xfff) << 0) | ((-9&0xfff) << 16), + temp_reg + 4); + writel((1 << 0) | (0 << 16), + temp_reg + 5); + writel((10 << 0) | (14 << 16), + temp_reg + 6); + writel(((-1&0xfff) << 0) | (0 << 16), + temp_reg + 7); + writel(((-14&0xfff) << 0) | ((-20&0xfff) << 16), + temp_reg + 8); + writel((1 << 0) | (0 << 16), + temp_reg + 9); + writel((20 << 0) | (29 << 16), + temp_reg + 10); + writel(((-2&0xfff) << 0) | (0 << 16), + temp_reg + 11); + writel(((-28&0xfff) << 0) | ((-40&0xfff) << 16), + temp_reg + 12); + writel((2 << 0) | (0 << 16), + temp_reg + 13); + writel((40 << 0) | (56 << 16), + temp_reg + 14); + writel(((-3&0xfff) << 0) | (0 << 16), + temp_reg + 15); + writel(((-57&0xfff) << 0) | ((-80&0xfff) << 16), + temp_reg + 16); + writel((5 << 0) | (0 << 16), + temp_reg + 17); + writel((86 << 0) | (121 << 16), + temp_reg + 18); + writel(((-10&0xfff) << 0) | (0 << 16), + temp_reg + 19); + writel(((-154&0xfff) << 0) | ((-212&0xfff) << 16), + temp_reg + 20); + writel((27 << 0) | (0 << 16), + temp_reg + 21); + writel((613 << 0) | (651 << 16), + temp_reg + 22); + writel(((-308&0xfff) << 0) | (1024 << 16), + temp_reg + 23); + } + + break; + + default: + SDPRINTK("invalid out_mode parameter(%d)\n\r", out_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + return SDOUT_NO_ERROR; +} + +/* +* initialization +* - iniization functions are only called under stopping sdout +*/ +enum s5p_tv_sd_err __s5p_sdout_init_display_mode( + enum s5p_tv_disp_mode disp_mode, + enum s5p_tv_o_mode out_mode, + enum s5p_sd_order order) +{ + u32 temp_reg = 0; + + SDPRINTK(" %d, %d, %d\n\r", disp_mode, out_mode, order); + + switch (disp_mode) { + + case TVOUT_NTSC_M: + temp_reg |= SDO_NTSC_M; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, + S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4, + out_mode); + break; + + case TVOUT_PAL_BDGHI: + temp_reg |= SDO_PAL_BGHID; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, + out_mode); + break; + + case TVOUT_PAL_M: + temp_reg |= SDO_PAL_M; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, + out_mode); + break; + + case TVOUT_PAL_N: + temp_reg |= SDO_PAL_N; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4, + out_mode); + break; + + case TVOUT_PAL_NC: + temp_reg |= SDO_PAL_NC; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + DOUT_VTOS_RATIO_7_3, + ut_mode); + break; + + case TVOUT_PAL_60: + temp_reg |= SDO_PAL_60; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, + out_mode); + break; + + case TVOUT_NTSC_443: + temp_reg |= SDO_NTSC_443; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4); + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4, + out_mode); + break; + + default: + SDPRINTK("invalid disp_mode parameter(%d)\n\r", disp_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + temp_reg |= SDO_COMPOSITE | SDO_INTERLACED; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_Y_C: + temp_reg |= SDO_DAC2_CVBS | SDO_DAC1_Y | SDO_DAC0_C; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_C_Y: + temp_reg |= SDO_DAC2_CVBS | SDO_DAC1_C | SDO_DAC0_Y; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_Y_C_CVBS: + temp_reg |= SDO_DAC2_Y | SDO_DAC1_C | SDO_DAC0_CVBS; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_Y_CVBS_C: + temp_reg |= SDO_DAC2_Y | SDO_DAC1_CVBS | SDO_DAC0_C; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_C_CVBS_Y: + temp_reg |= SDO_DAC2_C | SDO_DAC1_CVBS | SDO_DAC0_Y; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_C_Y_CVBS: + temp_reg |= SDO_DAC2_C | SDO_DAC1_Y | SDO_DAC0_CVBS; + break; + + default: + SDPRINTK(" invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + temp_reg |= SDO_COMPONENT | SDO_YPBPR | SDO_INTERLACED; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_Y_G | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_PB_B | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_Y_G | + SDO_DAC0_PR_R; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_PR_R | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PR_R | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PB_B | + SDO_DAC0_PR_R; + break; + + default: + SDPRINTK(" invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + temp_reg |= SDO_COMPONENT | SDO_YPBPR | SDO_PROGRESSIVE; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_Y_G | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_PB_B | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_Y_G | + SDO_DAC0_PR_R; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_PR_R | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PR_R | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PB_B | + SDO_DAC0_PR_R; + break; + + default: + SDPRINTK(" invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + temp_reg |= SDO_COMPONENT | SDO_RGB | SDO_PROGRESSIVE; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_Y_G | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_PB_B | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_Y_G | + SDO_DAC0_PR_R; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_PR_R | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PR_R | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PB_B | + SDO_DAC0_PR_R; + break; + + default: + SDPRINTK("invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + default: + SDPRINTK(" invalid out_mode parameter(%d)\n\r", out_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + __s5p_sdout_init_oversampling_filter_coeff_default(out_mode); + + writel(temp_reg, sdout_base + S5P_SDO_CONFIG); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_CONFIG)); + + return SDOUT_NO_ERROR; +} + +/* +* start - start functions are only called under stopping SDOUT +*/ +void __s5p_sdout_start(void) +{ + SDPRINTK("()\n\r"); + + writel(SDO_TVOUT_CLOCK_ON, sdout_base + S5P_SDO_CLKCON); + + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_CLKCON)); +} + +/* +/ stop - stop functions are only called under running SDOUT +*/ +void __s5p_sdout_stop(void) +{ + SDPRINTK("()\n\r"); + + writel(SDO_TVOUT_CLOCK_OFF, sdout_base + S5P_SDO_CLKCON); + + SDPRINTK(" 0x%x)\n\r", readl(sdout_base + S5P_SDO_CLKCON)); +} + +/* +* reset +* - reset function +*/ +void __s5p_sdout_sw_reset(bool active) +{ + SDPRINTK("%d\n\r", active); + + if (active) + writel(readl(sdout_base + S5P_SDO_CLKCON) | SDO_TVOUT_SW_RESET, + sdout_base + S5P_SDO_CLKCON); + else + writel(readl(sdout_base + S5P_SDO_CLKCON) & ~SDO_TVOUT_SW_RESET, + sdout_base + S5P_SDO_CLKCON); + + SDPRINTK(" 0x%x\n\r", readl(sdout_base + S5P_SDO_CLKCON)); +} + + +void __s5p_sdout_set_interrupt_enable(bool vsync_intr_en) +{ + SDPRINTK("%d)\n\r", vsync_intr_en); + + if (vsync_intr_en) + writel(readl(sdout_base + S5P_SDO_IRQMASK) & + ~SDO_VSYNC_IRQ_DISABLE, + sdout_base + S5P_SDO_IRQMASK); + else + writel(readl(sdout_base + S5P_SDO_IRQMASK) | + SDO_VSYNC_IRQ_DISABLE, + sdout_base + S5P_SDO_IRQMASK); + + SDPRINTK("0x%x)\n\r", readl(sdout_base + S5P_SDO_IRQMASK)); +} + +void __s5p_sdout_clear_interrupt_pending(void) +{ + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_IRQ)); + + writel(readl(sdout_base + S5P_SDO_IRQ) | SDO_VSYNC_IRQ_PEND, + sdout_base + S5P_SDO_IRQ); + + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_IRQ)); +} + +bool __s5p_sdout_get_interrupt_pending(void) +{ + SDPRINTK(" 0x%x\n\r", readl(sdout_base + S5P_SDO_IRQ)); + + return (readl(sdout_base + S5P_SDO_IRQ) | + SDO_VSYNC_IRQ_PEND) ? 1 : 0; +} + +int __init __s5p_sdout_probe(struct platform_device *pdev, u32 res_num) +{ + + struct resource *res; + size_t size; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + ret = -ENOENT; + } + + size = (res->end - res->start) + 1; + + sdout_mem = request_mem_region(res->start, size, pdev->name); + + if (sdout_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + ret = -ENOENT; + } + + sdout_base = ioremap(res->start, size); + + if (sdout_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + ret = -ENOENT; + + } + + return ret; + +} + +int __init __s5p_sdout_release(struct platform_device *pdev) +{ + iounmap(sdout_base); + + /* remove memory region */ + + if (sdout_mem != NULL) { + if (release_resource(sdout_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(sdout_mem); + + sdout_mem = NULL; + } + + return 0; +} diff --git a/drivers/media/video/samsung/tv20/s5pc100/tv_clock_s5pc100.c b/drivers/media/video/samsung/tv20/s5pc100/tv_clock_s5pc100.c new file mode 100644 index 0000000..63f565a --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/tv_clock_s5pc100.c @@ -0,0 +1,406 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/tv_clock_s5pc100.c + * + * clock raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/clk.h> + +#include <linux/uaccess.h> +#include <linux/io.h> + +#include <plat/map.h> +#include <plat/regs-clock.h> + +#include "tv_out_s5pc100.h" +#include "regs/regs-clock_extra.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_TVOUT_CLK_DEBUG 1 +#endif + +#ifdef S5P_TVOUT_CLK_DEBUG +#define TVCLKPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[TVCLK] %s: " fmt, __func__ , ## args) +#else +#define TVCLKPRINTK(fmt, args...) +#endif + +static struct resource *tvclk_mem; +void __iomem *tvclk_base; + +/* +* initialization +* - iniization functions are only called under stopping tvout clock +*/ + +void __s5p_tv_clk_init_hpll(unsigned int lock_time, + unsigned int mdiv, + unsigned int pdiv, + unsigned int sdiv) +{ + TVCLKPRINTK("%d,%d,%d,%d\n\r", lock_time, mdiv, pdiv, sdiv); + + writel(HPLL_LOCKTIME(lock_time), S5P_HPLL_LOCK); + writel(MDIV(mdiv) | PDIV(pdiv) | SDIV(sdiv), S5P_HPLL_CON); + + TVCLKPRINTK("0x%08x,0x%08x\n\r", readl(S5P_HPLL_LOCK), + readl(S5P_HPLL_CON)); +} + +void __s5p_tv_clk_hpll_onoff(bool en) +{ + TVCLKPRINTK("%d\n\r", en); + + if (en) { + writel(readl(S5P_HPLL_CON) | HPLL_ENABLE, S5P_HPLL_CON) ; + + while (!HPLL_LOCKED(readl(S5P_HPLL_CON))) + msleep(1); + + } else + writel(readl(S5P_HPLL_CON) & ~HPLL_ENABLE, S5P_HPLL_CON); + + + TVCLKPRINTK("0x%08x,0x%08x\n\r", readl(S5P_HPLL_LOCK), + readl(S5P_HPLL_CON)); +} + +enum s5p_tv_clk_err __s5p_tv_clk_init_href(enum s5p_tv_clk_hpll_ref hpll_ref) +{ + TVCLKPRINTK("(%d)\n\r", hpll_ref); + + switch (hpll_ref) { + + case S5P_TV_CLK_HPLL_REF_27M: + writel(readl(S5P_CLK_SRC0) & HREF_SEL_MASK, S5P_CLK_SRC0); + break; + + case S5P_TV_CLK_HPLL_REF_SRCLK: + writel(readl(S5P_CLK_SRC0) | HREF_SEL_SRCLK, S5P_CLK_SRC0); + break; + + default: + TVCLKPRINTK("invalid hpll_ref parameter = %d\n\r", hpll_ref); + return S5P_TV_CLK_ERR_INVALID_PARAM; + break; + } + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLK_SRC0)); + + return S5P_TV_CLK_ERR_NO_ERROR; +} + +enum s5p_tv_clk_err __s5p_tv_clk_init_mout_hpll( + enum s5p_tv_clk_mout_hpll mout_hpll) +{ + TVCLKPRINTK("(%d)\n\r", mout_hpll); + + switch (mout_hpll) { + + case S5P_TV_CLK_MOUT_HPLL_27M: + writel(readl(S5P_CLK_SRC0) & HPLL_SEL_MASK, S5P_CLK_SRC0); + break; + + case S5P_TV_CLK_MOUT_HPLL_FOUT_HPLL: + writel(readl(S5P_CLK_SRC0) | HPLL_SEL_FOUT_HPLL, S5P_CLK_SRC0); + break; + + default: + TVCLKPRINTK(" invalid mout_hpll parameter = %d\n\r", + mout_hpll); + return S5P_TV_CLK_ERR_INVALID_PARAM; + break; + } + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLK_SRC0)); + + return S5P_TV_CLK_ERR_NO_ERROR; +} + +enum s5p_tv_clk_err __s5p_tv_clk_init_video_mixer( + enum s5p_tv_clk_vmiexr_srcclk src_clk) +{ + TVCLKPRINTK("(%d)\n\r", src_clk); + + switch (src_clk) { + + case TVOUT_CLK_VMIXER_SRCCLK_CLK27M: + writel(((readl(S5P_CLK_SRC2) & VMIXER_SEL_MASK) | + VMIXER_SEL_CLK27M), S5P_CLK_SRC2); + break; + + case TVOUT_CLK_VMIXER_SRCCLK_VCLK_54: + writel(((readl(S5P_CLK_SRC2) & VMIXER_SEL_MASK) | + VMIXER_SEL_VCLK_54), S5P_CLK_SRC2); + break; + + case TVOUT_CLK_VMIXER_SRCCLK_MOUT_HPLL: + writel(((readl(S5P_CLK_SRC2) & VMIXER_SEL_MASK) | + VMIXER_SEL_MOUT_HPLL), S5P_CLK_SRC2); + break; + + default: + TVCLKPRINTK("invalid src_clk parameter = %d\n\r", src_clk); + return S5P_TV_CLK_ERR_INVALID_PARAM; + break; + } + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLK_SRC2)); + + return S5P_TV_CLK_ERR_NO_ERROR; +} + +void __s5p_tv_clk_init_hdmi_ratio(unsigned int clk_div) +{ + TVCLKPRINTK("(%d)\n\r", clk_div); + + writel((readl(S5P_CLK_DIV3) & HDMI_DIV_RATIO_MASK) | + HDMI_DIV_RATIO(clk_div), S5P_CLK_DIV3); + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLK_DIV3)); +} + +/* +* set +* - set functions are only called under running tvout clock +*/ +void __s5p_tv_clk_set_vp_clk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) + writel(readl(S5P_CLKGATE_D12) | CLK_HCLK_VP_PASS, + S5P_CLKGATE_D12); + else + writel(readl(S5P_CLKGATE_D12) & ~CLK_HCLK_VP_PASS, + S5P_CLKGATE_D12); + + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLKGATE_D12)); +} + +void __s5p_tv_clk_set_vmixer_hclk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) + writel(readl(S5P_CLKGATE_D12) | CLK_HCLK_VMIXER_PASS, + S5P_CLKGATE_D12); + else + writel(readl(S5P_CLKGATE_D12) & ~CLK_HCLK_VMIXER_PASS, + S5P_CLKGATE_D12); + + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLKGATE_D12)); +} + +void __s5p_tv_clk_set_vmixer_sclk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) + writel(readl(S5P_SCLKGATE1) | CLK_SCLK_VMIXER_PASS, + S5P_SCLKGATE1); + else + writel(readl(S5P_SCLKGATE1) & ~CLK_SCLK_VMIXER_PASS, + S5P_SCLKGATE1); + + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_SCLKGATE1)); +} + +void __s5p_tv_clk_set_sdout_hclk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) { + writel((readl(S5P_CLKGATE_D12) | CLK_HCLK_SDOUT_PASS), + S5P_CLKGATE_D12); + writel(readl(tvclk_base + 0x304) | VMIXER_OUT_SEL_SDOUT, + tvclk_base + 0x304); + } else + writel((readl(S5P_CLKGATE_D12) & ~CLK_HCLK_SDOUT_PASS), + S5P_CLKGATE_D12); + + + + TVCLKPRINTK("physical %p (0x%08x)\n\r", tvclk_base, + readl(tvclk_base + 0x304)); + + TVCLKPRINTK("after (0x%08x)\n\r", readl(S5P_CLKGATE_D12)); +} + +void __s5p_tv_clk_set_sdout_sclk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) + writel((readl(S5P_SCLKGATE1) | CLK_SCLK_TV54_PASS | + CLK_SCLK_VDAC54_PASS), + S5P_SCLKGATE1); + else + writel((readl(S5P_SCLKGATE1) & (~CLK_SCLK_TV54_PASS & + ~CLK_SCLK_VDAC54_PASS)), + S5P_SCLKGATE1); + + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_SCLKGATE1)); +} + +void __s5p_tv_clk_set_hdmi_hclk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) { + writel((readl(S5P_CLKGATE_D12) | CLK_HCLK_HDMI_PASS), + S5P_CLKGATE_D12); + writel(readl(tvclk_base + 0x304) | VMIXER_OUT_SEL_HDMI, + tvclk_base + 0x304); + } else + writel((readl(S5P_CLKGATE_D12) & ~CLK_HCLK_HDMI_PASS), + S5P_CLKGATE_D12) ; + + + TVCLKPRINTK("physical %p (0x%08x)\n\r", tvclk_base, + readl(tvclk_base + 0x304)); + + TVCLKPRINTK("after (0x%08x)\n\r", readl(S5P_CLKGATE_D12)); +} + +void __s5p_tv_clk_set_hdmi_sclk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) + writel((readl(S5P_SCLKGATE1) | CLK_SCLK_HDMI_PASS), + S5P_SCLKGATE1); + else + writel((readl(S5P_SCLKGATE1) & ~CLK_SCLK_HDMI_PASS), + S5P_SCLKGATE1); + + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_SCLKGATE1)); +} + +void __s5p_tv_clk_set_hdmi_i2c_clk_onoff(bool clk_on) +{ + TVCLKPRINTK("(%d)\n\r", clk_on); + + if (clk_on) + writel((readl(S5P_CLKGATE_D14) | CLK_PCLK_IIC_HDMI_PASS), + S5P_CLKGATE_D14); + else + writel((readl(S5P_CLKGATE_D14) & ~CLK_PCLK_IIC_HDMI_PASS), + S5P_CLKGATE_D14); + + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLKGATE_D14)); +} + +/* +* start +* - start functions are only called under stopping tvout clock +*/ +void __s5p_tv_clk_start(bool vp_hclk_on, + bool sdout_hclk_on, + bool hdmi_hclk_on) +{ + TVCLKPRINTK("(%d,%d,%d)\n\r", vp_hclk_on, sdout_hclk_on, hdmi_hclk_on); + + __s5p_tv_clk_set_vp_clk_onoff(vp_hclk_on); + __s5p_tv_clk_set_sdout_hclk_onoff(sdout_hclk_on); + __s5p_tv_clk_set_sdout_sclk_onoff(sdout_hclk_on); + __s5p_tv_clk_set_hdmi_hclk_onoff(hdmi_hclk_on); + __s5p_tv_clk_set_vmixer_hclk_onoff(true); + __s5p_tv_clk_set_vmixer_sclk_onoff(true); + + if (hdmi_hclk_on) + __s5p_tv_clk_hpll_onoff(true); + +} + + +/* +* stop +* - stop functions are only called under running tvout clock +*/ +void __s5p_tv_clk_stop(void) +{ + __s5p_tv_clk_set_sdout_sclk_onoff(false); + __s5p_tv_clk_set_sdout_hclk_onoff(false); + __s5p_tv_clk_set_hdmi_sclk_onoff(false); + __s5p_tv_clk_set_hdmi_hclk_onoff(false); + __s5p_tv_clk_set_vp_clk_onoff(false); + __s5p_tv_clk_set_vmixer_sclk_onoff(false); + __s5p_tv_clk_set_vmixer_hclk_onoff(false); + __s5p_tv_clk_hpll_onoff(false); +} + +int __init __s5p_tvclk_probe(struct platform_device *pdev, u32 res_num) +{ + + struct resource *res; + size_t size; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + ret = -ENOENT; + + } + + size = (res->end - res->start) + 1; + + tvclk_mem = request_mem_region(res->start, size, pdev->name); + + if (tvclk_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + ret = -ENOENT; + + } + + tvclk_base = ioremap(res->start, size); + + if (tvclk_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + ret = -ENOENT; + + } + + return ret; +} + +int __init __s5p_tvclk_release(struct platform_device *pdev) +{ + iounmap(tvclk_base); + + /* remove memory region */ + + if (tvclk_mem != NULL) { + if (release_resource(tvclk_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(tvclk_mem); + + tvclk_mem = NULL; + } + + return 0; +} diff --git a/drivers/media/video/samsung/tv20/s5pc100/tv_out_s5pc100.h b/drivers/media/video/samsung/tv20/s5pc100/tv_out_s5pc100.h new file mode 100644 index 0000000..19349be --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/tv_out_s5pc100.h @@ -0,0 +1,486 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/tv_out_s5pc100.h + * + * tv out header file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +/*#define COFIG_TVOUT_RAW_DBG */ + + +#define HDMI_START_NUM 0x1000 + +enum s5p_tv_audio_codec_type { + PCM = 1, AC3, MP3, WMA +}; + +enum s5p_endian_type { + TVOUT_LITTLE_ENDIAN_MODE = 0, + TVOUT_BIG_ENDIAN_MODE = 1 +}; + +enum s5p_tv_disp_mode { + TVOUT_NTSC_M = 0, + TVOUT_PAL_BDGHI, + TVOUT_PAL_M, + TVOUT_PAL_N, + TVOUT_PAL_NC, + TVOUT_PAL_60, + TVOUT_NTSC_443, + TVOUT_480P_60_16_9 = HDMI_START_NUM, + TVOUT_480P_60_4_3, + TVOUT_576P_50_16_9, + TVOUT_576P_50_4_3, + TVOUT_720P_60, + TVOUT_720P_50 +}; + +enum s5p_tv_o_mode { + TVOUT_OUTPUT_COMPOSITE, + TVOUT_OUTPUT_SVIDEO, + TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED, + TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE, + TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE, + TVOUT_OUTPUT_HDMI, + TVOUT_OUTPUT_HDMI_RGB, + TVOUT_OUTPUT_DVI +}; + +enum s5p_tv_pwr_err { + S5P_TV_PWR_ERR_NO_ERROR = 0, + S5P_TV_PWR_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x5000, + S5P_TV_PWR_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_PWR_ERR_INVALID_PARAM +}; + +enum s5p_tv_clk_err { + S5P_TV_CLK_ERR_NO_ERROR = 0, + S5P_TV_CLK_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x4000, + S5P_TV_CLK_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_CLK_ERR_INVALID_PARAM +}; + +enum s5p_tv_vp_err { + VPROC_NO_ERROR = 0, + S5P_TV_VP_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x2000, + S5P_TV_VP_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN, + S5P_TV_VP_ERR_NOT_UPDATE_FOR_ANOTHER_UPDATE, + S5P_TV_VP_ERR_INVALID_PARAM +}; + +enum s5p_tv_vmx_err { + VMIXER_NO_ERROR = 0, + S5P_TV_VMX_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x1000, + S5P_TV_VMX_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_VMX_ERR_BASE_ADDRESS_MUST_WORD_ALIGN, + S5P_TV_VMX_ERR_INVALID_PARAM +}; + +enum s5p_tv_vmx_color_fmt { + VM_DIRECT_RGB565 = 4, + VM_DIRECT_RGB1555 = 5, + VM_DIRECT_RGB4444 = 6, + VM_DIRECT_RGB8888 = 7 +}; + +enum s5p_tv_sd_err { + SDOUT_NO_ERROR = 0, + S5P_TV_SD_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x3000, + S5P_TV_SD_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_SD_ERR_INVALID_PARAM +}; + +enum s5p_sd_order { + S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB, + S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY, + S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR, + S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY, + S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB, + S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR, + S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_Y_C, + S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_C_Y, + S5P_TV_SD_O_ORDER_COMPOSITE_Y_C_CVBS, + S5P_TV_SD_O_ORDER_COMPOSITE_Y_CVBS_C, + S5P_TV_SD_O_ORDER_COMPOSITE_C_CVBS_Y, + S5P_TV_SD_O_ORDER_COMPOSITE_C_Y_CVBS +}; + +enum s5p_tv_hdmi_err { + HDMI_NO_ERROR = 0, + S5P_TV_HDMI_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x6000, + S5P_TV_HDMI_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_HDMI_ERR_INVALID_PARAM +}; + +enum s5p_hdmi_transmit { + HDMI_DO_NOT_TANS = 0, + HDMI_TRANS_ONCE, + HDMI_TRANS_EVERY_SYNC +}; + +enum s5p_hdmi_audio_type { + HDMI_AUDIO_NO, + HDMI_AUDIO_PCM +}; + + +enum s5p_tv_stda_err { + STDA_NO_ERROR = 0, + S5P_TV_STDA_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x7000, + S5P_TV_STDA_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_STDA_ERR_INVALID_PARAM +}; + + +/* +* enum +*/ + +enum s5p_tv_active_polarity { + TVOUT_POL_ACTIVE_LOW, + TVOUT_POL_ACTIVE_HIGH +}; + +enum s5p_yuv_fmt_component { + TVOUT_YUV_Y, + TVOUT_YUV_CB, + TVOUT_YUV_CR +}; + +enum s5p_tv_clk_hpll_ref { + S5P_TV_CLK_HPLL_REF_27M, + S5P_TV_CLK_HPLL_REF_SRCLK +}; + +enum s5p_tv_clk_mout_hpll { + S5P_TV_CLK_MOUT_HPLL_27M, + S5P_TV_CLK_MOUT_HPLL_FOUT_HPLL +}; + +enum s5p_tv_clk_vmiexr_srcclk { + TVOUT_CLK_VMIXER_SRCCLK_CLK27M, + TVOUT_CLK_VMIXER_SRCCLK_VCLK_54, + TVOUT_CLK_VMIXER_SRCCLK_MOUT_HPLL +}; + +enum s5p_vp_src_color { + VPROC_SRC_COLOR_NV12 = 0, + VPROC_SRC_COLOR_NV12IW = 1, + VPROC_SRC_COLOR_TILE_NV12 = 2, + VPROC_SRC_COLOR_TILE_NV12IW = 3 +}; + +enum s5p_vp_pxl_rate { + VPROC_PIXEL_PER_RATE_1_1 = 0, + VPROC_PIXEL_PER_RATE_1_2 = 1, + VPROC_PIXEL_PER_RATE_1_3 = 2, + VPROC_PIXEL_PER_RATE_1_4 = 3 +}; + +enum s5p_vp_sharpness_control { + VPROC_SHARPNESS_NO = 0, + VPROC_SHARPNESS_MIN = 1, + VPROC_SHARPNESS_MOD = 2, + VPROC_SHARPNESS_MAX = 3 +}; + +enum s5p_vp_line_eq { + VProc_LINE_EQ_0 = 0, + VProc_LINE_EQ_1 = 1, + VProc_LINE_EQ_2 = 2, + VProc_LINE_EQ_3 = 3, + VProc_LINE_EQ_4 = 4, + VProc_LINE_EQ_5 = 5, + VProc_LINE_EQ_6 = 6, + VProc_LINE_EQ_7 = 7 +}; + +enum s5p_vp_mem_mode { + VPROC_LINEAR_MODE, + VPROC_2D_TILE_MODE +}; + +enum s5p_vp_chroma_expansion { + VPROC_USING_C_TOP, + VPROC_USING_C_TOP_BOTTOM +}; + +enum s5p_vp_filed_id_toggle { + S5P_TV_VP_FILED_ID_TOGGLE_USER, + S5P_TV_VP_FILED_ID_TOGGLE_VSYNC +}; + +enum s5p_vp_field { + VPROC_TOP_FIELD, + VPROC_BOTTOM_FIELD +}; + +enum s5p_vp_poly_coeff { + VPROC_POLY8_Y0_LL = 0, + VPROC_POLY8_Y0_LH, + VPROC_POLY8_Y0_HL, + VPROC_POLY8_Y0_HH, + VPROC_POLY8_Y1_LL, + VPROC_POLY8_Y1_LH, + VPROC_POLY8_Y1_HL, + VPROC_POLY8_Y1_HH, + VPROC_POLY8_Y2_LL, + VPROC_POLY8_Y2_LH, + VPROC_POLY8_Y2_HL, + VPROC_POLY8_Y2_HH, + VPROC_POLY8_Y3_LL, + VPROC_POLY8_Y3_LH, + VPROC_POLY8_Y3_HL, + VPROC_POLY8_Y3_HH, + VPROC_POLY4_Y0_LL = 32, + VPROC_POLY4_Y0_LH, + VPROC_POLY4_Y0_HL, + VPROC_POLY4_Y0_HH, + VPROC_POLY4_Y1_LL, + VPROC_POLY4_Y1_LH, + VPROC_POLY4_Y1_HL, + VPROC_POLY4_Y1_HH, + VPROC_POLY4_Y2_LL, + VPROC_POLY4_Y2_LH, + VPROC_POLY4_Y2_HL, + VPROC_POLY4_Y2_HH, + VPROC_POLY4_Y3_LL, + VPROC_POLY4_Y3_LH, + VPROC_POLY4_Y3_HL, + VPROC_POLY4_Y3_HH, + VPROC_POLY4_C0_LL, + VPROC_POLY4_C0_LH, + VPROC_POLY4_C0_HL, + VPROC_POLY4_C0_HH, + VPROC_POLY4_C1_LL, + VPROC_POLY4_C1_LH, + VPROC_POLY4_C1_HL, + VPROC_POLY4_C1_HH +}; + +enum s5p_vp_csc_coeff { + VPROC_CSC_Y2Y_COEF = 0, + VPROC_CSC_CB2Y_COEF, + VPROC_CSC_CR2Y_COEF, + VPROC_CSC_Y2CB_COEF, + VPROC_CSC_CB2CB_COEF, + VPROC_CSC_CR2CB_COEF, + VPROC_CSC_Y2CR_COEF, + VPROC_CSC_CB2CR_COEF, + VPROC_CSC_CR2CR_COEF +}; + +enum s5p_vp_csc_type { + VPROC_CSC_SD_HD, + VPROC_CSC_HD_SD +}; + +enum s5p_tv_vp_filter_h_pp { + /* Don't change the order and the value */ + VPROC_PP_H_NORMAL = 0, + VPROC_PP_H_8_9, /* 720 to 640 */ + VPROC_PP_H_1_2, + VPROC_PP_H_1_3, + VPROC_PP_H_1_4 +}; + +enum s5p_tv_vp_filter_v_pp { + /* Don't change the order and the value */ + VPROC_PP_V_NORMAL = 0, + VPROC_PP_V_5_6, /* PAL to NTSC */ + VPROC_PP_V_3_4, + VPROC_PP_V_1_2, + VPROC_PP_V_1_3, + VPROC_PP_V_1_4 +}; + +enum s5p_vmx_burst_mode { + VM_BURST_8 = 0, + VM_BURST_16 = 1 +}; + +enum s5p_tv_vmx_scan_mode { + VMIXER_INTERLACED_MODE = 0, + VMIXER_PROGRESSIVE_MODE = 1 +}; + +enum s5p_tv_vmx_layer { + VM_VIDEO_LAYER = 2, + VM_GPR0_LAYER = 0, + VM_GPR1_LAYER = 1 +}; + +enum s5p_tv_vmx_bg_color_num { + VMIXER_BG_COLOR_0 = 0, + VMIXER_BG_COLOR_1 = 1, + VMIXER_BG_COLOR_2 = 2 +}; + +enum s5p_tv_coef_y_mode { + VMIXER_COEF_Y_NARROW = 0, + VMIXER_COEF_Y_WIDE = 1 +}; + +enum s5p_tv_vmx_csc_type { + VMIXER_CSC_RGB_TO_YUV601_LR, + VMIXER_CSC_RGB_TO_YUV601_FR, + VMIXER_CSC_RGB_TO_YUV709_LR, + VMIXER_CSC_RGB_TO_YUV709_FR +}; + +enum s5p_sd_level { + S5P_TV_SD_LEVEL_0IRE, + S5P_TV_SD_LEVEL_75IRE +}; + +enum s5p_sd_vsync_ratio { + SDOUT_VTOS_RATIO_10_4, + SDOUT_VTOS_RATIO_7_3 +}; + +enum s5p_sd_sync_sig_pin { + SDOUT_SYNC_SIG_NO, + SDOUT_SYNC_SIG_YG, + SDOUT_SYNC_SIG_ALL +}; + +enum s5p_sd_closed_caption_type { + SDOUT_NO_INS, + SDOUT_INS_1, + SDOUT_INS_2, + SDOUT_INS_OTHERS +}; + +enum s5p_sd_channel_sel { + SDOUT_CHANNEL_0 = 0, + SDOUT_CHANNEL_1 = 1, + SDOUT_CHANNEL_2 = 2 +}; + +enum s5p_sd_vesa_rgb_sync_type { + SDOUT_VESA_RGB_SYNC_COMPOSITE, + SDOUT_VESA_RGB_SYNC_SEPARATE +}; + +enum s5p_sd_525_copy_permit { + SDO_525_COPY_PERMIT, + SDO_525_ONECOPY_PERMIT, + SDO_525_NOCOPY_PERMIT +}; + +enum s5p_sd_525_mv_psp { + SDO_525_MV_PSP_OFF, + SDO_525_MV_PSP_ON_2LINE_BURST, + SDO_525_MV_PSP_ON_BURST_OFF, + SDO_525_MV_PSP_ON_4LINE_BURST, +}; + +enum s5p_sd_525_copy_info { + SDO_525_COPY_INFO, + SDO_525_DEFAULT, +}; + +enum s5p_sd_525_aspect_ratio { + SDO_525_4_3_NORMAL, + SDO_525_16_9_ANAMORPIC, + SDO_525_4_3_LETTERBOX +}; + +enum s5p_sd_625_subtitles { + SDO_625_NO_OPEN_SUBTITLES, + SDO_625_INACT_OPEN_SUBTITLES, + SDO_625_OUTACT_OPEN_SUBTITLES +}; + +enum s5p_sd_625_camera_film { + SDO_625_CAMERA, + SDO_625_FILM +}; + +enum s5p_sd_625_color_encoding { + SDO_625_NORMAL_PAL, + SDO_625_MOTION_ADAPTIVE_COLORPLUS +}; + +enum s5p_sd_625_aspect_ratio { + SDO_625_4_3_FULL_576, + SDO_625_14_9_LETTERBOX_CENTER_504, + SDO_625_14_9_LETTERBOX_TOP_504, + SDO_625_16_9_LETTERBOX_CENTER_430, + SDO_625_16_9_LETTERBOX_TOP_430, + SDO_625_16_9_LETTERBOX_CENTER, + SDO_625_14_9_FULL_CENTER_576, + SDO_625_16_9_ANAMORPIC_576 +}; + +enum s5p_tv_hdmi_csc_type { + HDMI_CSC_YUV601_TO_RGB_LR, + HDMI_CSC_YUV601_TO_RGB_FR, + HDMI_CSC_YUV709_TO_RGB_LR, + HDMI_CSC_YUV709_TO_RGB_FR, + HDMI_CSC_YUV601_TO_YUV709, + HDMI_CSC_RGB_FR_TO_RGB_LR, + HDMI_CSC_RGB_FR_TO_YUV601, + HDMI_CSC_RGB_FR_TO_YUV709, + HDMI_BYPASS +}; + +enum s5p_tv_hdmi_tg_param { + H_BLANK = 0, + V2_BLANK, + V1_BLANK, + V_LINE, + H_LINE, + VSYNC_POL, + V_BOT_ST, + V_BOT_END, + HSYNC_START, + HSYNC_END, + HSYNC_POL, + VSYNC_T_END, + VSYNC_T_START, + VSYNC_B_END, + VSYNC_B_START, + VSYNC_h_POS_END, + VSYNC_h_POS_START, + TG_H_FSZ, + TG_HACT_START, + TG_HACT_SZ, + TG_V_FSZ, + TG_VSYNC, + TG_VSYNC2, + TG_VACT_START, + TG_VACT_SZ, + TG_FIELD_CHG, + TG_VACT_START2, + TG_VSYNC_TOP_HDMI, + TG_VSYNC_BOTTOM_HDMI, + TG_FIELD_TOP_HDMI, + TG_FIELD_BOTTOM_HDMI +}; + +enum s5p_tv_hdmi_disp_mode { + S5P_TV_HDMI_DISP_MODE_480P_60 = 0, + S5P_TV_HDMI_DISP_MODE_576P_50 = 1, + S5P_TV_HDMI_DISP_MODE_720P_60 = 2, + S5P_TV_HDMI_DISP_MODE_720P_50 = 3, + S5P_TV_HDMI_DISP_MODE_1080I_60 = 4, + S5P_TV_HDMI_DISP_MODE_1080I_50 = 5, + S5P_TV_HDMI_DISP_MODE_VGA_60 = 6, + S5P_TV_HDMI_DISP_MODE_NUM = 7 +}; + +extern void __iomem *hdmi_base; + +/* 0 - hdcp stopped, 1 - hdcp started, 2 - hdcp reset */ +extern u8 hdcp_protocol_status; + +extern bool __s5p_start_hdcp(void); +extern void __s5p_stop_hdcp(void); +extern void __s5p_init_hdcp(bool hpd_status, struct i2c_client *ddc_port); + diff --git a/drivers/media/video/samsung/tv20/s5pc100/tv_power_s5pc100.c b/drivers/media/video/samsung/tv20/s5pc100/tv_power_s5pc100.c new file mode 100644 index 0000000..cf7f0bd --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/tv_power_s5pc100.c @@ -0,0 +1,140 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/tv_power_s5pc100.c + * + * power raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/platform_device.h> + +#include <linux/uaccess.h> +#include <linux/io.h> + +#include <mach/map.h> +#include <plat/regs-clock.h> +#include <plat/regs-power.h> + +#include "tv_out_s5pc100.h" + +#if defined USE_POWERCON_FUNCTION +#undef USE_POWERCON_FUNCTION +#endif + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_TVOUT_PM_DEBUG 1 +#endif + +#ifdef S5P_TVOUT_PM_DEBUG +#define TVPMPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[TVPM] %s: " fmt, __func__ , ## args) +#else +#define TVPMPRINTK(fmt, args...) +#endif + +#define TVPWR_SUBSYSTEM_ACTIVE (1<<4) +#define TVPWR_SUBSYSTEM_LP (0<<4) + +#define TVPWR_MTC_COUNTER_CLEAR(a) (((~0xf)<<16)&a) +#define TVPWR_MTC_COUNTER_SET(a) ((0xf&a)<<16) + +#define TVPWR_TV_BLOCK_STATUS(a) ((0x1<<4)&a) + +#define TVPWR_DAC_STATUS(a) ((0x1<<26)&a) +#define TVPWR_DAC_ON (1<<26) + +static unsigned short g_dacPwrOn; + + +void __s5p_tv_power_init_mtc_stable_counter(unsigned int value) +{ + TVPMPRINTK("(%d)\n\r", value); + + writel(TVPWR_MTC_COUNTER_CLEAR((readl(S5P_MTC_STABLE) | + TVPWR_MTC_COUNTER_SET(value))), + S5P_MTC_STABLE); + + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_MTC_STABLE)); +} + +void __s5p_tv_powerinitialize_dac_onoff(unsigned short on) +{ + TVPMPRINTK("(%d)\n\r", on); + + g_dacPwrOn = on; + + TVPMPRINTK("(0x%08x)\n\r", g_dacPwrOn); +} + +void __s5p_tv_powerset_dac_onoff(unsigned short on) +{ + TVPMPRINTK("(%d)\n\r", on); + + if (on) + writel(readl(S5P_OTHERS) | TVPWR_DAC_ON, S5P_OTHERS); + else + writel(readl(S5P_OTHERS) & ~TVPWR_DAC_ON, S5P_OTHERS); + + + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_OTHERS)); +} + + +unsigned short __s5p_tv_power_get_power_status(void) +{ + + TVPMPRINTK("()\n\r"); + + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_BLK_PWR_STAT)); + + + return TVPWR_TV_BLOCK_STATUS(readl(S5P_BLK_PWR_STAT)) ? 1 : 0; +} + +unsigned short __s5p_tv_power_get_dac_power_status(void) +{ + TVPMPRINTK("()\n\r"); + + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_OTHERS)); + + return TVPWR_DAC_STATUS(readl(S5P_OTHERS)) ? 1 : 0; +} + +void __s5p_tv_poweron(void) +{ + TVPMPRINTK("()\n\r"); + + writel(readl(S5P_NORMAL_CFG) | TVPWR_SUBSYSTEM_ACTIVE, + S5P_NORMAL_CFG); + + while (!TVPWR_TV_BLOCK_STATUS(readl(S5P_BLK_PWR_STAT))) + msleep(1); + + + TVPMPRINTK("0x%08x,0x%08x)\n\r", readl(S5P_NORMAL_CFG), + readl(S5P_BLK_PWR_STAT)); +} + + +void __s5p_tv_poweroff(void) +{ + TVPMPRINTK("()\n\r"); + + __s5p_tv_powerset_dac_onoff(0); + + writel(readl(S5P_NORMAL_CFG) & ~TVPWR_SUBSYSTEM_ACTIVE, + S5P_NORMAL_CFG); + + while (TVPWR_TV_BLOCK_STATUS(readl(S5P_BLK_PWR_STAT))) + msleep(1); + + + TVPMPRINTK("0x%08x,0x%08x)\n\r", readl(S5P_NORMAL_CFG), + readl(S5P_BLK_PWR_STAT)); +} diff --git a/drivers/media/video/samsung/tv20/s5pc100/vmixer_s5pc100.c b/drivers/media/video/samsung/tv20/s5pc100/vmixer_s5pc100.c new file mode 100644 index 0000000..046f44b --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/vmixer_s5pc100.c @@ -0,0 +1,1047 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/vmixer_s5pc100.c + * + * Mixer raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#include <linux/io.h> + +#include "tv_out_s5pc100.h" + +#include "regs/regs-vmx.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_MXR_DEBUG 1 +#endif + +#ifdef S5P_MXR_DEBUG +#define VMPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[VM] %s: " fmt, __func__ , ## args) +#else +#define VMPRINTK(fmt, args...) +#endif + +static struct resource *mixer_mem; +void __iomem *mixer_base; + +/* +*set - set functions are only called under running vmixer +*/ + +enum s5p_tv_vmx_err __s5p_vm_set_layer_show(enum s5p_tv_vmx_layer layer, + bool show) +{ + u32 mxr_config; + + VMPRINTK("%d, %d\n\r", layer, show); + + switch (layer) { + + case VM_VIDEO_LAYER: + mxr_config = (show) ? + (readl(mixer_base + S5P_MXR_CFG) | + S5P_MXR_VIDEO_LAYER_SHOW) : + (readl(mixer_base + S5P_MXR_CFG) & + ~S5P_MXR_VIDEO_LAYER_SHOW); + break; + + case VM_GPR0_LAYER: + mxr_config = (show) ? + (readl(mixer_base + S5P_MXR_CFG) | + S5P_MXR_GRAPHIC0_LAYER_SHOW) : + (readl(mixer_base + S5P_MXR_CFG) & + ~S5P_MXR_GRAPHIC0_LAYER_SHOW); + break; + + case VM_GPR1_LAYER: + mxr_config = (show) ? + (readl(mixer_base + S5P_MXR_CFG) | + S5P_MXR_GRAPHIC1_LAYER_SHOW) : + (readl(mixer_base + S5P_MXR_CFG) & + ~S5P_MXR_GRAPHIC1_LAYER_SHOW); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(mxr_config, mixer_base + S5P_MXR_CFG); + + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_CFG)); + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_layer_priority(enum s5p_tv_vmx_layer layer, + u32 priority) +{ + u32 layer_cfg; + + VMPRINTK("%d, %d\n\r", layer, priority); + + switch (layer) { + + case VM_VIDEO_LAYER: + layer_cfg = S5P_MXR_VP_LAYER_PRIORITY_CLEAR( + readl(mixer_base + S5P_MXR_LAYER_CFG)) | + S5P_MXR_VP_LAYER_PRIORITY(priority); + break; + + case VM_GPR0_LAYER: + layer_cfg = S5P_MXR_GRP0_LAYER_PRIORITY_CLEAR( + readl(mixer_base + S5P_MXR_LAYER_CFG)) | + S5P_MXR_GRP0_LAYER_PRIORITY(priority); + break; + + case VM_GPR1_LAYER: + layer_cfg = S5P_MXR_GRP1_LAYER_PRIORITY_CLEAR( + readl(mixer_base + S5P_MXR_LAYER_CFG)) | + S5P_MXR_GRP1_LAYER_PRIORITY(priority); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(layer_cfg, mixer_base + S5P_MXR_LAYER_CFG); + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_win_blend( + enum s5p_tv_vmx_layer layer, bool enable) +{ + u32 temp_reg; + VMPRINTK("%d, %d\n\r", layer, enable); + + switch (layer) { + + case VM_VIDEO_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_VIDEO_CFG) + & (~S5P_MXR_VP_BLEND_ENABLE) ; + + if (enable) + temp_reg |= S5P_MXR_VP_BLEND_ENABLE; + else + temp_reg |= S5P_MXR_VP_BLEND_DISABLE; + + writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG); + + break; + + case VM_GPR0_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG) + & (~S5P_MXR_WIN_BLEND_ENABLE) ; + + if (enable) + temp_reg |= S5P_MXR_WIN_BLEND_ENABLE; + else + temp_reg |= S5P_MXR_WIN_BLEND_DISABLE; + + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG); + + break; + + case VM_GPR1_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG) + & (~S5P_MXR_WIN_BLEND_ENABLE) ; + + if (enable) + temp_reg |= S5P_MXR_WIN_BLEND_ENABLE; + else + temp_reg |= S5P_MXR_WIN_BLEND_DISABLE; + + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG); + + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + + return S5P_TV_VMX_ERR_INVALID_PARAM; + + break; + } + + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_VIDEO_CFG)); + + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)); + + return VMIXER_NO_ERROR; +} + + +enum s5p_tv_vmx_err __s5p_vm_set_layer_alpha(enum s5p_tv_vmx_layer layer, + u32 alpha) +{ + u32 temp_reg; + VMPRINTK("%d, %d\n\r", layer, alpha); + + switch (layer) { + + case VM_VIDEO_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_VIDEO_CFG) + & (~S5P_MXR_ALPHA) ; + temp_reg |= S5P_MXR_VP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG); + break; + + case VM_GPR0_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG) + & (~S5P_MXR_ALPHA) ; + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG); + break; + + case VM_GPR1_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG) + & (~S5P_MXR_ALPHA) ; + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_VIDEO_CFG)); + + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)); + + return VMIXER_NO_ERROR; +} + + +enum s5p_tv_vmx_err __s5p_vm_set_grp_base_address(enum s5p_tv_vmx_layer layer, + u32 base_addr) +{ + VMPRINTK("%d, 0x%x\n\r", layer, base_addr); + + if (S5P_MXR_GRP_ADDR_ILLEGAL(base_addr)) { + VMPRINTK(" address is not word align = %d\n\r", base_addr); + return S5P_TV_VMX_ERR_BASE_ADDRESS_MUST_WORD_ALIGN; + } + + switch (layer) { + + case VM_GPR0_LAYER: + writel(S5P_MXR_GPR_BASE(base_addr), + mixer_base + S5P_MXR_GRAPHIC0_BASE); + VMPRINTK("0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_BASE)); + break; + + case VM_GPR1_LAYER: + writel(S5P_MXR_GPR_BASE(base_addr), + mixer_base + S5P_MXR_GRAPHIC1_BASE); + VMPRINTK("0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_BASE)); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_grp_layer_position(enum s5p_tv_vmx_layer + layer, u32 dst_offs_x, u32 dst_offs_y) +{ + VMPRINTK("%d, %d, %d)\n\r", layer, dst_offs_x, dst_offs_y); + + switch (layer) { + + case VM_GPR0_LAYER: + writel(S5P_MXR_GRP_DESTX(dst_offs_x) | + S5P_MXR_GRP_DESTY(dst_offs_y), + mixer_base + S5P_MXR_GRAPHIC0_DXY); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC0_DXY)); + break; + + case VM_GPR1_LAYER: + writel(S5P_MXR_GRP_DESTX(dst_offs_x) | + S5P_MXR_GRP_DESTY(dst_offs_y), + mixer_base + S5P_MXR_GRAPHIC1_DXY); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC1_DXY)); + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_grp_layer_size(enum s5p_tv_vmx_layer layer, + u32 span, + u32 width, + u32 height, + u32 src_offs_x, + u32 src_offs_y) +{ + VMPRINTK("%d, %d, %d, %d, %d, %d)\n\r", layer, span, width, height, + src_offs_x, src_offs_y); + + switch (layer) { + + case VM_GPR0_LAYER: + writel(S5P_MXR_GRP_SPAN(span), + mixer_base + S5P_MXR_GRAPHIC0_SPAN); + writel(S5P_MXR_GRP_WIDTH(width) | + S5P_MXR_GRP_HEIGHT(height), + mixer_base + S5P_MXR_GRAPHIC0_WH); + writel(S5P_MXR_GRP_STARTX(src_offs_x) | + S5P_MXR_GRP_STARTY(src_offs_y), + mixer_base + S5P_MXR_GRAPHIC0_SXY); + VMPRINTK("0x%x, 0x%x, 0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_SPAN), + readl(mixer_base + S5P_MXR_GRAPHIC0_WH), + readl(mixer_base + S5P_MXR_GRAPHIC0_SXY)); + break; + + case VM_GPR1_LAYER: + writel(S5P_MXR_GRP_SPAN(span), + mixer_base + S5P_MXR_GRAPHIC1_SPAN); + writel(S5P_MXR_GRP_WIDTH(width) | S5P_MXR_GRP_HEIGHT(height), + mixer_base + S5P_MXR_GRAPHIC1_WH); + writel(S5P_MXR_GRP_STARTX(src_offs_x) | + S5P_MXR_GRP_STARTY(src_offs_y), + mixer_base + S5P_MXR_GRAPHIC1_SXY); + VMPRINTK("0x%x, 0x%x, 0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_SPAN), + readl(mixer_base + S5P_MXR_GRAPHIC1_WH), + readl(mixer_base + S5P_MXR_GRAPHIC1_SXY)); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_bg_color( + enum s5p_tv_vmx_bg_color_num colornum, + u32 color_y, + u32 color_cb, + u32 color_cr) +{ + u32 reg_value; + VMPRINTK("%d, %d, %d, %d)\n\r", colornum, color_y, color_cb, color_cr); + + reg_value = S5P_MXR_BG_COLOR_Y(color_y) | + S5P_MXR_BG_COLOR_CB(color_cb) | + S5P_MXR_BG_COLOR_CR(color_cr); + + switch (colornum) { + + case VMIXER_BG_COLOR_0: + writel(reg_value, mixer_base + S5P_MXR_BG_COLOR0); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_BG_COLOR0)); + break; + + case VMIXER_BG_COLOR_1: + writel(reg_value, mixer_base + S5P_MXR_BG_COLOR1); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_BG_COLOR1)); + break; + + case VMIXER_BG_COLOR_2: + writel(reg_value, mixer_base + S5P_MXR_BG_COLOR2); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_BG_COLOR2)); + break; + + default: + VMPRINTK(" invalid uiColorNum parameter = %d\n\r", colornum); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + + + +/* +* initialization - iniization functions are only called under stopping vmixer +*/ +enum s5p_tv_vmx_err __s5p_vm_init_status_reg(enum s5p_vmx_burst_mode burst, + enum s5p_endian_type endian) +{ + u32 temp_reg = 0; + + VMPRINTK("++(%d, %d)\n\r", burst, endian); + + temp_reg = S5P_MXR_MIXER_RESERVED | + S5P_MXR_CMU_CANNOT_STOP_CLOCK; + + switch (burst) { + + case VM_BURST_8: + temp_reg |= S5P_MXR_BURST8_MODE; + break; + + case VM_BURST_16: + temp_reg |= S5P_MXR_BURST16_MODE; + break; + + default: + VMPRINTK("[ERR] : invalid burst parameter = %d\n\r", burst); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + switch (endian) { + + case TVOUT_BIG_ENDIAN_MODE: + temp_reg |= S5P_MXR_BIG_ENDIAN_SOURCE_FORMAT; + break; + + case TVOUT_LITTLE_ENDIAN_MODE: + temp_reg |= S5P_MXR_LITTLE_ENDIAN_SOURCE_FORMAT; + break; + + default: + VMPRINTK("[ERR] : invalid endian parameter = %d\n\r", endian); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, mixer_base + S5P_MXR_STATUS); + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_STATUS)); + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_init_display_mode(enum s5p_tv_disp_mode mode, + enum s5p_tv_o_mode output_mode) +{ + u32 temp_reg = 0; + + VMPRINTK("%d, %d)\n\r", mode, output_mode); + + switch (mode) { + + case TVOUT_NTSC_M: + + case TVOUT_NTSC_443: + temp_reg = S5P_MXR_SD | S5P_MXR_NTSC; + break; + + case TVOUT_PAL_BDGHI: + + case TVOUT_PAL_M: + + case TVOUT_PAL_N: + + case TVOUT_PAL_NC: + + case TVOUT_PAL_60: + temp_reg = S5P_MXR_SD | S5P_MXR_PAL; + break; + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + temp_reg = S5P_MXR_SD | S5P_MXR_NTSC; + break; + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + temp_reg = S5P_MXR_SD | S5P_MXR_PAL; + break; + + case TVOUT_720P_50: + + case TVOUT_720P_60: + temp_reg = S5P_MXR_HD | S5P_MXR_HD_720P_MODE; + break; + + default: + VMPRINTK(" invalid mode parameter = %d\n\r", mode); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + switch (output_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + temp_reg |= S5P_MXR_INTERLACE_MODE; + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + temp_reg |= S5P_MXR_PROGRESSVE_MODE; + break; + + case TVOUT_OUTPUT_HDMI: + temp_reg |= S5P_MXR_PROGRESSVE_MODE; + break; + + default: + VMPRINTK(" invalid mode parameter = %d\n\r", mode); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, mixer_base + S5P_MXR_CFG); + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CFG)); + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_init_layer(enum s5p_tv_vmx_layer layer, + bool show, + bool win_blending, + u32 alpha, + u32 priority, + enum s5p_tv_vmx_color_fmt color, + bool blank_change, + bool pixel_blending, + bool premul, + u32 blank_color, + u32 base_addr, + u32 span, + u32 width, + u32 height, + u32 src_offs_x, + u32 src_offs_y, + u32 dst_offs_x, + u32 dst_offs_y) +{ + u32 temp_reg = 0; + + VMPRINTK("%d, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x,\ + 0x%x, %d, %d, %d, %d, %d, %d, %d)\n\r", + layer, show, win_blending, alpha, priority, + color, blank_change, pixel_blending, premul, + blank_color, base_addr, span, width, height, + src_offs_x, src_offs_y, dst_offs_x, dst_offs_y); + + switch (layer) { + + case VM_VIDEO_LAYER: + temp_reg = (win_blending) ? S5P_MXR_VP_BLEND_ENABLE : + S5P_MXR_VP_BLEND_DISABLE; + temp_reg |= S5P_MXR_VP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG); + break; + + case VM_GPR0_LAYER: + temp_reg = (blank_change) ? + S5P_MXR_BLANK_NOT_CHANGE_NEW_PIXEL : + S5P_MXR_BLANK_CHANGE_NEW_PIXEL; + temp_reg |= (premul) ? S5P_MXR_PRE_MUL_MODE : + S5P_MXR_NORMAL_MODE; + temp_reg |= (win_blending) ? S5P_MXR_WIN_BLEND_ENABLE : + S5P_MXR_WIN_BLEND_DISABLE; + temp_reg |= (pixel_blending) ? S5P_MXR_PIXEL_BLEND_ENABLE : + S5P_MXR_PIXEL_BLEND_DISABLE; + temp_reg |= S5P_MXR_EG_COLOR_FORMAT(color); + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG); + writel(S5P_MXR_GPR_BLANK_COLOR(blank_color), + mixer_base + S5P_MXR_GRAPHIC0_BLANK); + + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_BLANK)); + + __s5p_vm_set_grp_layer_size(layer, span, width, height, + src_offs_x, src_offs_y); + + __s5p_vm_set_grp_base_address(layer, base_addr); + __s5p_vm_set_grp_layer_position(layer, dst_offs_x, dst_offs_y); + + break; + + case VM_GPR1_LAYER: + temp_reg = (blank_change) ? + S5P_MXR_BLANK_NOT_CHANGE_NEW_PIXEL : + S5P_MXR_BLANK_CHANGE_NEW_PIXEL; + temp_reg |= (premul) ? S5P_MXR_PRE_MUL_MODE : + S5P_MXR_NORMAL_MODE; + temp_reg |= (win_blending) ? S5P_MXR_WIN_BLEND_ENABLE : + S5P_MXR_WIN_BLEND_DISABLE; + temp_reg |= (pixel_blending) ? S5P_MXR_PIXEL_BLEND_ENABLE : + S5P_MXR_PIXEL_BLEND_DISABLE; + temp_reg |= S5P_MXR_EG_COLOR_FORMAT(color); + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG); + writel(S5P_MXR_GPR_BLANK_COLOR(blank_color), + mixer_base + S5P_MXR_GRAPHIC1_BLANK); + + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_BLANK)); + + __s5p_vm_set_grp_layer_size(layer, span, width, height, + src_offs_x, src_offs_y); + + __s5p_vm_set_grp_base_address(layer, base_addr); + __s5p_vm_set_grp_layer_position(layer, dst_offs_x, dst_offs_y); + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + __s5p_vm_set_layer_priority(layer, priority); + + __s5p_vm_set_layer_show(layer, show); + + return VMIXER_NO_ERROR; +} + +void __s5p_vm_init_bg_dither_enable(bool cr_dither_enable, + bool cb_dither_enable, + bool y_dither_enable) +{ + u32 temp_reg = 0; + + VMPRINTK("%d, %d, %d\n\r", cr_dither_enable, + cb_dither_enable, y_dither_enable); + + temp_reg = (cr_dither_enable) ? + (temp_reg | S5P_MXR_BG_CR_DIHER_EN) : + (temp_reg & ~S5P_MXR_BG_CR_DIHER_EN); + temp_reg = (cb_dither_enable) ? + (temp_reg | S5P_MXR_BG_CB_DIHER_EN) : + (temp_reg & ~S5P_MXR_BG_CB_DIHER_EN); + temp_reg = (y_dither_enable) ? + (temp_reg | S5P_MXR_BG_Y_DIHER_EN) : + (temp_reg & ~S5P_MXR_BG_Y_DIHER_EN); + + writel(temp_reg, mixer_base + S5P_MXR_BG_CFG); + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_BG_CFG)); + +} + + +enum s5p_tv_vmx_err __s5p_vm_init_bg_color( + enum s5p_tv_vmx_bg_color_num color_num, + u32 color_y, + u32 color_cb, + u32 color_cr) +{ + return __s5p_vm_set_bg_color(color_num, color_y, color_cb, color_cr); +} + +enum s5p_tv_vmx_err __s5p_vm_init_csc_coef(enum s5p_yuv_fmt_component component, + enum s5p_tv_coef_y_mode mode, + u32 coeff0, + u32 coeff1, + u32 coeff2) +{ + u32 mxr_cm; + + VMPRINTK("%d, %d, %d, %d, %d\n\r", component, mode, coeff0, + coeff1, coeff2); + + switch (component) { + + case TVOUT_YUV_Y: + mxr_cm = (mode == VMIXER_COEF_Y_WIDE) ? + S5P_MXR_BG_COLOR_WIDE : S5P_MXR_BG_COLOR_NARROW; + mxr_cm |= S5P_MXR_BG_COEFF_0(coeff0) | + S5P_MXR_BG_COEFF_1(coeff1) | + S5P_MXR_BG_COEFF_2(coeff2); + writel(mxr_cm, mixer_base + S5P_MXR_CM_COEFF_Y); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + break; + + case TVOUT_YUV_CB: + mxr_cm = S5P_MXR_BG_COEFF_0(coeff0) | + S5P_MXR_BG_COEFF_1(coeff1) | + S5P_MXR_BG_COEFF_2(coeff2); + writel(mxr_cm, mixer_base + S5P_MXR_CM_COEFF_CB); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + break; + + case TVOUT_YUV_CR: + mxr_cm = S5P_MXR_BG_COEFF_0(coeff0) | + S5P_MXR_BG_COEFF_1(coeff1) | + S5P_MXR_BG_COEFF_2(coeff2); + writel(mxr_cm, S5P_MXR_CM_COEFF_CR); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_CM_COEFF_CR)); + break; + + default: + VMPRINTK("invalid component parameter = %d\n\r", component); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +void __s5p_vm_init_csc_coef_default(enum s5p_tv_vmx_csc_type csc_type) +{ + VMPRINTK("%d\n\r", csc_type); + + switch (csc_type) { + + case VMIXER_CSC_RGB_TO_YUV601_LR: + writel((0 << 30) | (153 << 20) | (300 << 10) | (58 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((936 << 20) | (851 << 10) | (262 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((262 << 20) | (805 << 10) | (982 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + case VMIXER_CSC_RGB_TO_YUV601_FR: + writel((1 << 30) | (132 << 20) | (258 << 10) | (50 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((948 << 20) | (875 << 10) | (225 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((225 << 20) | (836 << 10) | (988 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + case VMIXER_CSC_RGB_TO_YUV709_LR: + writel((0 << 30) | (109 << 20) | (366 << 10) | (36 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((964 << 20) | (822 << 10) | (216 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((262 << 20) | (787 << 10) | (1000 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + case VMIXER_CSC_RGB_TO_YUV709_FR: + writel((1 << 30) | (94 << 20) | (314 << 10) | (32 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((972 << 20) | (851 << 10) | (225 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((225 << 20) | (820 << 10) | (1004 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + default: + VMPRINTK(" invalid csc_type parameter = %d\n\r", csc_type); + break; + } + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CM_COEFF_CR)); +} + +/* +* etc +*/ +enum s5p_tv_vmx_err __s5p_vm_get_layer_info(enum s5p_tv_vmx_layer layer, + bool *show, + u32 *priority) +{ + VMPRINTK("%d\n\r", layer); + + switch (layer) { + + case VM_VIDEO_LAYER: + *show = (readl(mixer_base + S5P_MXR_LAYER_CFG) & + S5P_MXR_VIDEO_LAYER_SHOW) ? 1 : 0; + *priority = S5P_MXR_VP_LAYER_PRIORITY_INFO( + readl(mixer_base + S5P_MXR_LAYER_CFG)); + break; + + case VM_GPR0_LAYER: + *show = (readl(mixer_base + S5P_MXR_LAYER_CFG) & + S5P_MXR_GRAPHIC0_LAYER_SHOW) ? 1 : 0; + *priority = S5P_MXR_GRP0_LAYER_PRIORITY_INFO( + readl(mixer_base + S5P_MXR_LAYER_CFG)); + break; + + case VM_GPR1_LAYER: + *show = (readl(mixer_base + S5P_MXR_LAYER_CFG) & + S5P_MXR_GRAPHIC1_LAYER_SHOW) ? 1 : 0; + *priority = S5P_MXR_GRP1_LAYER_PRIORITY_INFO( + readl(mixer_base + S5P_MXR_LAYER_CFG)); + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + VMPRINTK("%d, %d\n\r", *show, *priority); + + return VMIXER_NO_ERROR; +} + +/* +* start - start functions are only called under stopping vmixer +*/ + +void __s5p_vm_start(void) +{ + VMPRINTK("()\n\r"); + writel((readl(mixer_base + S5P_MXR_STATUS) | S5P_MXR_MIXER_START), + mixer_base + S5P_MXR_STATUS); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_STATUS)); + + + VMPRINTK("S5P_MXR_STATUS \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_STATUS)); + VMPRINTK("S5P_MXR_INT_EN \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_INT_EN)); + VMPRINTK("S5P_MXR_BG_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_CFG)); + VMPRINTK("S5P_MXR_BG_COLOR0 \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_COLOR0)); + VMPRINTK("S5P_MXR_BG_COLOR1 \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_COLOR1)); + VMPRINTK("S5P_MXR_BG_COLOR2 \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_COLOR2)); + VMPRINTK("S5P_MXR_CM_COEFF_Y \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + VMPRINTK("S5P_MXR_CM_COEFF_CB \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + VMPRINTK("S5P_MXR_CM_COEFF_CR \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CR)); + VMPRINTK("S5P_MXR_CM_COEFF_Y \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + VMPRINTK("S5P_MXR_CM_COEFF_CB \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + VMPRINTK("S5P_MXR_CM_COEFF_CR \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CR)); + VMPRINTK("S5P_MXR_GRAPHIC0_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("S5P_MXR_GRAPHIC0_BASE \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_BASE)); + VMPRINTK("S5P_MXR_GRAPHIC0_SPAN \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_SPAN)); + VMPRINTK("S5P_MXR_GRAPHIC0_WH \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_WH)); + VMPRINTK("S5P_MXR_GRAPHIC0_SXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_SXY)); + VMPRINTK("S5P_MXR_GRAPHIC0_DXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_DXY)); + VMPRINTK("S5P_MXR_GRAPHIC0_BLANK \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_BLANK)); + VMPRINTK("S5P_MXR_GRAPHIC1_BASE \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_BASE)); + VMPRINTK("S5P_MXR_GRAPHIC1_SPAN \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_SPAN)); + VMPRINTK("S5P_MXR_GRAPHIC1_WH \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_WH)); + VMPRINTK("S5P_MXR_GRAPHIC1_SXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_SXY)); + VMPRINTK("S5P_MXR_GRAPHIC1_DXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_DXY)); + VMPRINTK("S5P_MXR_GRAPHIC1_BLANK \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_BLANK)); + VMPRINTK("S5P_MXR_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CFG)); + VMPRINTK("S5P_MXR_LAYER_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_LAYER_CFG)); + +} + +/* +* stop - stop functions are only called under running vmixer +*/ + +void __s5p_vm_stop(void) +{ + VMPRINTK("()\n\r"); + writel((readl(mixer_base + S5P_MXR_STATUS) & ~S5P_MXR_MIXER_START), + mixer_base + S5P_MXR_STATUS); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_STATUS)); +} + +/* +* interrupt - for debug +*/ + +enum s5p_tv_vmx_err __s5p_vm_set_underflow_interrupt_enable( + enum s5p_tv_vmx_layer layer, bool en) +{ + u32 enablemaks; + + VMPRINTK("%d, %d\n\r", layer, en); + + switch (layer) { + + case VM_VIDEO_LAYER: + enablemaks = S5P_MXR_VP_INT_ENABLE; + break; + + case VM_GPR0_LAYER: + enablemaks = S5P_MXR_GRP0_INT_ENABLE; + break; + + case VM_GPR1_LAYER: + enablemaks = S5P_MXR_GRP1_INT_ENABLE; + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + if (en) { + writel((readl(mixer_base + S5P_MXR_INT_EN) | enablemaks), + mixer_base + S5P_MXR_INT_EN); + } else { + writel((readl(mixer_base + S5P_MXR_INT_EN) & ~enablemaks), + mixer_base + S5P_MXR_INT_EN); + } + + VMPRINTK("0x%x)\n\r", readl(mixer_base + S5P_MXR_INT_EN)); + + return VMIXER_NO_ERROR; +} + +void __s5p_vm_clear_pend_all(void) +{ + writel(S5P_MXR_INT_FIRED | S5P_MXR_VP_INT_FIRED | + S5P_MXR_GRP0_INT_FIRED | S5P_MXR_GRP1_INT_FIRED, + mixer_base + S5P_MXR_INT_EN); +} + +irqreturn_t __s5p_mixer_irq(int irq, void *dev_id) +{ + bool v_i_f; + bool g0_i_f; + bool g1_i_f; + bool mxr_i_f; + u32 temp_reg = 0; + + v_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_VP_INT_FIRED) ? true : false; + g0_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_GRP0_INT_FIRED) ? true : false; + g1_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_GRP1_INT_FIRED) ? true : false; + mxr_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_INT_FIRED) ? true : false; + + if (mxr_i_f) { + temp_reg |= S5P_MXR_INT_FIRED; + + if (v_i_f) { + temp_reg |= S5P_MXR_VP_INT_FIRED; + printk("VP fifo under run!!\n\r"); + } + + if (g0_i_f) { + temp_reg |= S5P_MXR_GRP0_INT_FIRED; + printk("GRP0 fifo under run!!\n\r"); + } + + if (g1_i_f) { + temp_reg |= S5P_MXR_GRP1_INT_FIRED; + printk("GRP1 fifo under run!!\n\r"); + } + + writel(temp_reg, mixer_base + S5P_MXR_INT_STATUS); + } + + return IRQ_HANDLED; +} + +int __init __s5p_mixer_probe(struct platform_device *pdev, u32 res_num) +{ + + struct resource *res; + size_t size; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + ret = -ENOENT; + + } + + size = (res->end - res->start) + 1; + + mixer_mem = request_mem_region(res->start, size, pdev->name); + + if (mixer_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + ret = -ENOENT; + + } + + mixer_base = ioremap(res->start, size); + + if (mixer_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + ret = -ENOENT; + + + } + + return ret; + +} + +int __init __s5p_mixer_release(struct platform_device *pdev) +{ + iounmap(mixer_base); + + /* remove memory region */ + + if (mixer_mem != NULL) { + if (release_resource(mixer_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(mixer_mem); + + mixer_mem = NULL; + } + + return 0; +} diff --git a/drivers/media/video/samsung/tv20/s5pc100/vp_coeff_s5pc100.h b/drivers/media/video/samsung/tv20/s5pc100/vp_coeff_s5pc100.h new file mode 100644 index 0000000..3ec0343 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/vp_coeff_s5pc100.h @@ -0,0 +1,310 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/vp_coeff_s5pc100.h + * + * Video Processor coefficient header file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +/* Horizontal Y 8tap */ +const signed char g_s_vp8tap_coef_y_h[] = { + /* VP_PP_H_NORMAL */ + 0, 0, 0, 0, 127, 0, 0, 0, + 0, 1, -2, 8, 126, -6, 2, -1, + 0, 1, -5, 16, 125, -12, 4, -1, + 0, 2, -8, 25, 121, -16, 5, -1, + -1, 3, -10, 35, 114, -18, 6, -1, + -1, 4, -13, 46, 107, -20, 6, -1, + -1, 5, -16, 57, 99, -21, 6, -1, + -1, 5, -18, 68, 89, -20, 6, -1, + -1, 6, -20, 79, 79, -20, 6, -1, + -1, 6, -20, 89, 68, -18, 5, -1, + -1, 6, -21, 99, 57, -16, 5, -1, + -1, 6, -20, 107, 46, -13, 4, -1, + -1, 6, -18, 114, 35, -10, 3, -1, + -1, 5, -16, 121, 25, -8, 2, 0, + -1, 4, -12, 125, 16, -5, 1, 0, + -1, 2, -6, 126, 8, -2, 1, 0, + + /* VP_PP_H_8_9 */ + 0, 3, -7, 12, 112, 12, -7, 3, + -1, 3, -9, 19, 113, 6, -5, 2, + -1, 3, -11, 27, 111, 0, -3, 2, + -1, 4, -13, 35, 108, -5, -1, 1, + -1, 4, -14, 43, 104, -9, 0, 1, + -1, 5, -16, 52, 99, -12, 1, 0, + -1, 5, -17, 61, 92, -14, 2, 0, + 0, 4, -17, 69, 85, -16, 3, 0, + 0, 4, -17, 77, 77, -17, 4, 0, + 0, 3, -16, 85, 69, -17, 4, 0, + 0, 2, -14, 92, 61, -17, 5, -1, + 0, 1, -12, 99, 52, -16, 5, -1, + 1, 0, -9, 104, 43, -14, 4, -1, + 1, -1, -5, 108, 35, -13, 4, -1, + 2, -3, 0, 111, 27, -11, 3, -1, + 2, -5, 6, 113, 19, -9, 3, -1, + + /* VP_PP_H_1_2 */ + 0, -3, 0, 35, 64, 35, 0, -3, + 0, -3, 1, 38, 64, 32, -1, -3, + 0, -3, 2, 41, 63, 29, -2, -2, + 0, -4, 4, 43, 63, 27, -3, -2, + 0, -4, 5, 46, 62, 24, -3, -2, + 0, -4, 7, 49, 60, 21, -3, -2, + -1, -4, 9, 51, 59, 19, -4, -1, + -1, -4, 12, 53, 57, 16, -4, -1, + -1, -4, 14, 55, 55, 14, -4, -1, + -1, -4, 16, 57, 53, 12, -4, -1, + -1, -4, 19, 59, 51, 9, -4, -1, + -2, -3, 21, 60, 49, 7, -4, 0, + -2, -3, 24, 62, 46, 5, -4, 0, + -2, -3, 27, 63, 43, 4, -4, 0, + -2, -2, 29, 63, 41, 2, -3, 0, + -3, -1, 32, 64, 38, 1, -3, 0, + + /* VP_PP_H_1_3 */ + 0, 0, 10, 32, 44, 32, 10, 0, + -1, 0, 11, 33, 45, 31, 9, 0, + -1, 0, 12, 35, 45, 29, 8, 0, + -1, 1, 13, 36, 44, 28, 7, 0, + -1, 1, 15, 37, 44, 26, 6, 0, + -1, 2, 16, 38, 43, 25, 5, 0, + -1, 2, 18, 39, 43, 23, 5, -1, + -1, 3, 19, 40, 42, 22, 4, -1, + -1, 3, 21, 41, 41, 21, 3, -1, + -1, 4, 22, 42, 40, 19, 3, -1, + -1, 5, 23, 43, 39, 18, 2, -1, + 0, 5, 25, 43, 38, 16, 2, -1, + 0, 6, 26, 44, 37, 15, 1, -1, + 0, 7, 28, 44, 36, 13, 1, -1, + 0, 8, 29, 45, 35, 12, 0, -1, + 0, 9, 31, 45, 33, 11, 0, -1, + + /* VP_PP_H_1_4 */ + 0, 2, 13, 30, 38, 30, 13, 2, + 0, 3, 14, 30, 38, 29, 12, 2, + 0, 3, 15, 31, 38, 28, 11, 2, + 0, 4, 16, 32, 38, 27, 10, 1, + 0, 4, 17, 33, 37, 26, 10, 1, + 0, 5, 18, 34, 37, 24, 9, 1, + 0, 5, 19, 34, 37, 24, 8, 1, + 1, 6, 20, 35, 36, 22, 7, 1, + 1, 6, 21, 36, 36, 21, 6, 1, + 1, 7, 22, 36, 35, 20, 6, 1, + 1, 8, 24, 37, 34, 19, 5, 0, + 1, 9, 24, 37, 34, 18, 5, 0, + 1, 10, 26, 37, 33, 17, 4, 0, + 1, 10, 27, 38, 32, 16, 4, 0, + 2, 11, 28, 38, 31, 15, 3, 0, + 2, 12, 29, 38, 30, 14, 3, 0 +}; + +/* Horizontal C 4tap */ +const signed char g_s_vp4tap_coef_c_h[] = { + /* VP_PP_H_NORMAL */ + 0, 0, 128, 0, + 0, 5, 126, -3, + -1, 11, 124, -6, + -1, 19, 118, -8, + -2, 27, 111, -8, + -3, 37, 102, -8, + -4, 48, 92, -8, + -5, 59, 81, -7, + -6, 70, 70, -6, + -7, 81, 59, -5, + -8, 92, 48, -4, + -8, 102, 37, -3, + -8, 111, 27, -2, + -8, 118, 19, -1, + -6, 124, 11, -1, + -3, 126, 5, 0, + + /* VP_PP_H_8_9 */ + 0, 8, 112, 8, + -1, 13, 113, 3, + -2, 19, 111, 0, + -2, 26, 107, -3, + -3, 34, 101, -4, + -3, 42, 94, -5, + -4, 51, 86, -5, + -5, 60, 78, -5, + -5, 69, 69, -5, + -5, 78, 60, -5, + -5, 86, 51, -4, + -5, 94, 42, -3, + -4, 101, 34, -3, + -3, 107, 26, -2, + 0, 111, 19, -2, + 3, 113, 13, -1, + + /* VP_PP_H_1_2 */ + 0, 26, 76, 26, + 0, 30, 76, 22, + 0, 34, 75, 19, + 1, 38, 73, 16, + 1, 43, 71, 13, + 2, 47, 69, 10, + 3, 51, 66, 8, + 4, 55, 63, 6, + 5, 59, 59, 5, + 6, 63, 55, 4, + 8, 66, 51, 3, + 10, 69, 47, 2, + 13, 71, 43, 1, + 16, 73, 38, 1, + 19, 75, 34, 0, + 22, 76, 30, 0, + + /* VP_PP_H_1_3 */ + 0, 30, 68, 30, + 2, 33, 66, 27, + 3, 36, 66, 23, + 3, 39, 65, 21, + 4, 43, 63, 18, + 5, 46, 62, 15, + 6, 49, 60, 13, + 8, 52, 57, 11, + 9, 55, 55, 9, + 11, 57, 52, 8, + 13, 60, 49, 6, + 15, 62, 46, 5, + 18, 63, 43, 4, + 21, 65, 39, 3, + 23, 66, 36, 3, + 27, 66, 33, 2, + + /* VP_PP_H_1_4 */ + 0, 31, 66, 31, + 3, 34, 63, 28, + 4, 37, 62, 25, + 4, 40, 62, 22, + 5, 43, 61, 19, + 6, 46, 59, 17, + 7, 48, 58, 15, + 9, 51, 55, 13, + 11, 53, 53, 11, + 13, 55, 51, 9, + 15, 58, 48, 7, + 17, 59, 46, 6, + 19, 61, 43, 5, + 22, 62, 40, 4, + 25, 62, 37, 4, + 28, 63, 34, 3, +}; + + +/* Vertical Y 8tap */ +const signed char g_s_vp4tap_coef_y_v[] = { + /* VP_PP_V_NORMAL */ + 0, 0, 127, 0, + 0, 5, 126, -3, + -1, 11, 124, -6, + -1, 19, 118, -8, + -2, 27, 111, -8, + -3, 37, 102, -8, + -4, 48, 92, -8, + -5, 59, 81, -7, + -6, 70, 70, -6, + -7, 81, 59, -5, + -8, 92, 48, -4, + -8, 102, 37, -3, + -8, 111, 27, -2, + -8, 118, 19, -1, + -6, 124, 11, -1, + -3, 126, 5, 0, + + /* VP_PP_V_5_6 */ + 0, 11, 106, 11, + -2, 16, 107, 7, + -2, 22, 105, 3, + -2, 29, 101, 0, + -3, 36, 96, -1, + -3, 44, 90, -3, + -4, 52, 84, -4, + -4, 60, 76, -4, + -4, 68, 68, -4, + -4, 76, 60, -4, + -4, 84, 52, -4, + -3, 90, 44, -3, + -1, 96, 36, -3, + 0, 101, 29, -2, + 3, 105, 22, -2, + 7, 107, 16, -2, + + /* VP_PP_V_3_4 */ + 0, 15, 98, 15, + -2, 21, 97, 12, + -2, 26, 96, 8, + -2, 32, 93, 5, + -2, 39, 89, 2, + -2, 46, 84, 0, + -3, 53, 79, -1, + -2, 59, 73, -2, + -2, 66, 66, -2, + -2, 73, 59, -2, + -1, 79, 53, -3, + 0, 84, 46, -2, + 2, 89, 39, -2, + 5, 93, 32, -2, + 8, 96, 26, -2, + 12, 97, 21, -2, + + /* VP_PP_V_1_2 */ + 0, 26, 76, 26, + 0, 30, 76, 22, + 0, 34, 75, 19, + 1, 38, 73, 16, + 1, 43, 71, 13, + 2, 47, 69, 10, + 3, 51, 66, 8, + 4, 55, 63, 6, + 5, 59, 59, 5, + 6, 63, 55, 4, + 8, 66, 51, 3, + 10, 69, 47, 2, + 13, 71, 43, 1, + 16, 73, 38, 1, + 19, 75, 34, 0, + 22, 76, 30, 0, + + /* VP_PP_V_1_3 */ + 0, 30, 68, 30, + 2, 33, 66, 27, + 3, 36, 66, 23, + 3, 39, 65, 21, + 4, 43, 63, 18, + 5, 46, 62, 15, + 6, 49, 60, 13, + 8, 52, 57, 11, + 9, 55, 55, 9, + 11, 57, 52, 8, + 13, 60, 49, 6, + 15, 62, 46, 5, + 18, 63, 43, 4, + 21, 65, 39, 3, + 23, 66, 36, 3, + 27, 66, 33, 2, + + /* VP_PP_V_1_4 */ + 0, 31, 66, 31, + 3, 34, 63, 28, + 4, 37, 62, 25, + 4, 40, 62, 22, + 5, 43, 61, 19, + 6, 46, 59, 17, + 7, 48, 58, 15, + 9, 51, 55, 13, + 11, 53, 53, 11, + 13, 55, 51, 9, + 15, 58, 48, 7, + 17, 59, 46, 6, + 19, 61, 43, 5, + 22, 62, 40, 4, + 25, 62, 37, 4, + 28, 63, 34, 3 +}; + diff --git a/drivers/media/video/samsung/tv20/s5pc100/vprocessor_s5pc100.c b/drivers/media/video/samsung/tv20/s5pc100/vprocessor_s5pc100.c new file mode 100644 index 0000000..6a2a7ef --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pc100/vprocessor_s5pc100.c @@ -0,0 +1,809 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/vprocessor_s5pc100.c + * + * Video Processor raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/platform_device.h> + +#include <linux/io.h> + +#include "tv_out_s5pc100.h" + +#include "regs/regs-vprocessor.h" +#include "vp_coeff_s5pc100.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_VP_DEBUG 1 +#endif + +#ifdef S5P_VP_DEBUG +#define VPPRINTK(fmt, args...)\ + printk(KERN_INFO "\t\t[VP] %s: " fmt, __func__ , ## args) +#else +#define VPPRINTK(fmt, args...) +#endif + +static struct resource *vp_mem; +void __iomem *vp_base; + +/* +* set +* - set functions are only called under running video processor +* - after running set functions, it is need to run __s5p_vp_update() function +* for update shadow registers +*/ +void __s5p_vp_set_field_id(enum s5p_vp_field mode) +{ + VPPRINTK("%d\n\r", mode); + + writel((mode == VPROC_TOP_FIELD) ? + vp_base + S5P_VP_FIELD_ID_TOP : + vp_base + S5P_VP_FIELD_ID_BOTTOM, + vp_base + S5P_VP_FIELD_ID); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_FIELD_ID)); +} + +enum s5p_tv_vp_err __s5p_vp_set_top_field_address(u32 top_y_addr, + u32 top_c_addr) +{ + VPPRINTK("0x%x, 0x%x\n\r", top_y_addr, top_c_addr); + + if (VP_PTR_ILLEGAL(top_y_addr) || VP_PTR_ILLEGAL(top_c_addr)) { + VPPRINTK(" address is not double word align = 0x%x, 0x%x\n\r", + top_y_addr, top_c_addr); + return S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN; + } + + writel(top_y_addr, vp_base + S5P_VP_TOP_Y_PTR); + + writel(top_c_addr, vp_base + S5P_VP_TOP_C_PTR); + + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_TOP_Y_PTR), + readl(vp_base + S5P_VP_TOP_C_PTR)); + + return VPROC_NO_ERROR; +} + +enum s5p_tv_vp_err __s5p_vp_set_bottom_field_address(u32 bottom_y_addr, + u32 bottom_c_addr) +{ + VPPRINTK("0x%x, 0x%x\n\r", bottom_y_addr, bottom_c_addr); + + if (VP_PTR_ILLEGAL(bottom_y_addr) || VP_PTR_ILLEGAL(bottom_c_addr)) { + VPPRINTK(" address is not double word align = 0x%x, 0x%x\n\r", + bottom_y_addr, bottom_c_addr); + return S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN; + } + + writel(bottom_y_addr, vp_base + S5P_VP_BOT_Y_PTR); + + writel(bottom_c_addr, vp_base + S5P_VP_BOT_C_PTR); + + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_BOT_Y_PTR), + readl(vp_base + S5P_VP_BOT_C_PTR)); + + return VPROC_NO_ERROR; +} + + +enum s5p_tv_vp_err __s5p_vp_set_img_size(u32 img_width, u32 img_height) +{ + VPPRINTK("%d, %d\n\r", img_width, img_height); + + if (VP_IMG_SIZE_ILLEGAL(img_width) || + VP_IMG_SIZE_ILLEGAL(img_height / 2)) { + VPPRINTK(" image full size is not double word align\ + = %d, %d\n\r", + img_width, img_height); + return S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN; + } + + writel(VP_IMG_HSIZE(img_width) | VP_IMG_VSIZE(img_height), + + vp_base + S5P_VP_IMG_SIZE_Y); + + writel(VP_IMG_HSIZE(img_width) | VP_IMG_VSIZE(img_height / 2), + vp_base + S5P_VP_IMG_SIZE_C); + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_IMG_SIZE_Y), + readl(vp_base + S5P_VP_IMG_SIZE_C)); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_set_src_position(u32 src_off_x, + u32 src_x_fract_step, + u32 src_off_y) +{ + VPPRINTK("%d, %d, %d)\n\r", src_off_x, src_x_fract_step, src_off_y); + + writel(VP_SRC_H_POSITION(src_off_x) | + VP_SRC_X_FRACT_STEP(src_x_fract_step), + vp_base + S5P_VP_SRC_H_POSITION); + writel(VP_SRC_V_POSITION(src_off_y), vp_base + S5P_VP_SRC_V_POSITION); + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_SRC_H_POSITION), + readl(vp_base + S5P_VP_SRC_V_POSITION)); +} + +void __s5p_vp_set_dest_position(u32 dst_off_x, + u32 dst_off_y) +{ + VPPRINTK("%d, %d)\n\r", dst_off_x, dst_off_y); + + + writel(VP_DST_H_POSITION(dst_off_x), vp_base + S5P_VP_DST_H_POSITION); + writel(VP_DST_V_POSITION(dst_off_y), vp_base + S5P_VP_DST_V_POSITION); + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_DST_H_POSITION), + readl(vp_base + S5P_VP_DST_V_POSITION)); +} + +void __s5p_vp_set_src_dest_size(u32 src_width, + u32 src_height, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + u32 h_ratio = (src_width << 16) / dst_width; + u32 v_ratio = (ipc_2d) ? + ((src_height << 17) / dst_height) : + ((src_height << 16) / dst_height); + + VPPRINTK("(%d, %d, %d, %d)++\n\r", src_width, src_height, + dst_width, dst_height); + + writel(VP_SRC_WIDTH(src_width), vp_base + S5P_VP_SRC_WIDTH); + writel(VP_SRC_HEIGHT(src_height), vp_base + S5P_VP_SRC_HEIGHT); + writel(VP_DST_WIDTH(dst_width), vp_base + S5P_VP_DST_WIDTH); + writel(VP_DST_HEIGHT(dst_height), vp_base + S5P_VP_DST_HEIGHT) ; + writel(VP_H_RATIO(h_ratio), vp_base + S5P_VP_H_RATIO); + writel(VP_V_RATIO(v_ratio), vp_base + S5P_VP_V_RATIO); + + writel((ipc_2d) ? (readl(vp_base + S5P_VP_MODE) | VP_2D_IPC_ON) : + (readl(vp_base + S5P_VP_MODE) & ~VP_2D_IPC_ON), + vp_base + S5P_VP_MODE); + + VPPRINTK("%d, %d, %d, %d, 0x%x, 0x%x\n\r", + readl(vp_base + S5P_VP_SRC_WIDTH), + readl(vp_base + S5P_VP_SRC_HEIGHT), + readl(vp_base + S5P_VP_DST_WIDTH), + readl(vp_base + S5P_VP_DST_HEIGHT), + readl(vp_base + S5P_VP_H_RATIO), + readl(vp_base + S5P_VP_V_RATIO)); +} + +enum s5p_tv_vp_err __s5p_vp_set_poly_filter_coef( + enum s5p_vp_poly_coeff poly_coeff, + signed char ch0, + signed char ch1, + signed char ch2, + signed char ch3) +{ + VPPRINTK("%d, %d, %d, %d, %d)\n\r", poly_coeff, ch0, ch1, ch2, ch3); + + if (poly_coeff > VPROC_POLY4_C1_HH || + poly_coeff < VPROC_POLY8_Y0_LL || + (poly_coeff > VPROC_POLY8_Y3_HH && + poly_coeff < VPROC_POLY4_Y0_LL)) { + + VPPRINTK("invaild poly_coeff parameter \n\r"); + return S5P_TV_VP_ERR_INVALID_PARAM; + } + + writel((((0xff&ch0) << 24) | ((0xff&ch1) << 16) | + ((0xff&ch2) << 8) | (0xff&ch3)), + vp_base + S5P_VP_POLY8_Y0_LL + poly_coeff*4); + + VPPRINTK("0x%08x, 0x%08x\n\r", + readl(vp_base + S5P_VP_POLY8_Y0_LL + poly_coeff*4), + vp_base + S5P_VP_POLY8_Y0_LL + poly_coeff*4); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_set_poly_filter_coef_default(u32 h_ratio, u32 v_ratio) +{ + enum s5p_tv_vp_filter_h_pp e_h_filter; + enum s5p_tv_vp_filter_v_pp e_v_filter; + u8 *poly_flt_coeff; + int i, j; + + VPPRINTK("%d, %d\n\r", h_ratio, v_ratio); + + /* + * For the real interlace mode, the vertical ratio should be + * used after divided by 2. Because in the interlace mode, + * all the VP output is used for SDOUT display and it should + * be the same as one field of the progressive mode. + * Therefore the same filter coefficients should be used for + * the same the final output video. + * When half of the interlace V_RATIO is same as the progressive + * V_RATIO, the final output video scale is same. (20051104, ishan) + */ + + /*Horizontal Y 8tap */ + /*Horizontal C 4tap */ + + if (h_ratio <= (0x1 << 16)) { /* 720->720 or zoom in */ + e_h_filter = VPROC_PP_H_NORMAL; + } + + else if (h_ratio <= (0x9 << 13)) /* 720->640 */ + e_h_filter = VPROC_PP_H_8_9 ; + + else if (h_ratio <= (0x1 << 17)) /* 2->1 */ + e_h_filter = VPROC_PP_H_1_2; + + else if (h_ratio <= (0x3 << 16)) /* 2->1 */ + e_h_filter = VPROC_PP_H_1_3; + else + e_h_filter = VPROC_PP_H_1_4; /* 4->1 */ + + /* Vertical Y 4tap */ + if (v_ratio <= (0x1 << 16)) /* 720->720 or zoom in*/ + e_v_filter = VPROC_PP_V_NORMAL; + else if (v_ratio <= (0x3 << 15)) /* 6->5*/ + e_v_filter = VPROC_PP_V_5_6; + else if (v_ratio <= (0x5 << 14)) /* 4->3*/ + e_v_filter = VPROC_PP_V_3_4; + else if (v_ratio <= (0x1 << 17)) /* 2->1*/ + e_v_filter = VPROC_PP_V_1_2; + else if (v_ratio <= (0x3 << 16)) /* 3->1*/ + e_v_filter = VPROC_PP_V_1_3; + else /* 4->1*/ + e_v_filter = VPROC_PP_V_1_4; + + poly_flt_coeff = (u8 *)(g_s_vp8tap_coef_y_h + e_h_filter * 16 * 8); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + __s5p_vp_set_poly_filter_coef( + VPROC_POLY8_Y0_LL + (i*4) + j, + *(poly_flt_coeff + 4*j*8 + (7 - i)), + *(poly_flt_coeff + (4*j + 1)*8 + (7 - i)), + *(poly_flt_coeff + (4*j + 2)*8 + (7 - i)), + *(poly_flt_coeff + (4*j + 3)*8 + (7 - i))); + } + } + + poly_flt_coeff = (u8 *)(g_s_vp4tap_coef_c_h + e_h_filter * 16 * 4); + + for (i = 0; i < 2; i++) { + for (j = 0; j < 4; j++) { + __s5p_vp_set_poly_filter_coef( + VPROC_POLY4_C0_LL + (i*4) + j, + *(poly_flt_coeff + 4*j*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 1)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 2)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 3)*4 + (3 - i))); + } + } + + poly_flt_coeff = (u8 *)(g_s_vp4tap_coef_y_v + e_v_filter * 16 * 4); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + __s5p_vp_set_poly_filter_coef( + VPROC_POLY4_Y0_LL + (i*4) + j, + *(poly_flt_coeff + 4*j*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 1)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 2)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 3)*4 + (3 - i))); + } + } + + VPPRINTK("%d, %d\n\r", e_h_filter, e_v_filter); +} + +void __s5p_vp_set_src_dest_size_with_default_poly_filter_coef(u32 src_width, + u32 src_height, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + u32 h_ratio = (src_width << 16) / dst_width; + u32 v_ratio = (ipc_2d) ? ((src_height << 17) / dst_height) : + ((src_height << 16) / dst_height); + + __s5p_vp_set_src_dest_size(src_width, src_height, dst_width, + dst_height, ipc_2d); + __s5p_vp_set_poly_filter_coef_default(h_ratio, v_ratio); +} + +enum s5p_tv_vp_err __s5p_vp_set_brightness_contrast_control( + enum s5p_vp_line_eq eq_num, u32 intc, u32 slope) +{ + VPPRINTK("%d, %d, %d\n\r", eq_num, intc, slope); + + if (eq_num > VProc_LINE_EQ_7 || eq_num < VProc_LINE_EQ_0) { + VPPRINTK("invaild eq_num parameter \n\r"); + return S5P_TV_VP_ERR_INVALID_PARAM; + } + + writel(VP_LINE_INTC(intc) | VP_LINE_SLOPE(slope), + + vp_base + S5P_PP_LINE_EQ0 + eq_num*4); + + VPPRINTK("0x%08x, 0x%08x\n\r", + readl(vp_base + S5P_PP_LINE_EQ0 + eq_num*4), + vp_base + S5P_PP_LINE_EQ0 + eq_num*4); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_set_brightness(bool brightness) +{ + unsigned short i; + + VPPRINTK("%d\n\r", brightness); + + g_vp_contrast_brightness = + VP_LINE_INTC_CLEAR(g_vp_contrast_brightness) | + VP_LINE_INTC(brightness); + + for (i = 0; i < 8; i++) + writel(g_vp_contrast_brightness, + vp_base + S5P_PP_LINE_EQ0 + i*4); + + + VPPRINTK("%d\n\r", g_vp_contrast_brightness); +} + +void __s5p_vp_set_contrast(u8 contrast) +{ + unsigned short i; + + VPPRINTK("%d\n\r", contrast); + + g_vp_contrast_brightness = + VP_LINE_SLOPE_CLEAR(g_vp_contrast_brightness) | + VP_LINE_SLOPE(contrast); + + for (i = 0; i < 8; i++) + writel(g_vp_contrast_brightness, + vp_base + S5P_PP_LINE_EQ0 + i*4); + + + VPPRINTK("%d\n\r", g_vp_contrast_brightness); +} + +enum s5p_tv_vp_err __s5p_vp_update(void) +{ + VPPRINTK("()\n\r"); + + writel(readl(vp_base + S5P_VP_SHADOW_UPDATE) | + S5P_VP_SHADOW_UPDATE_ENABLE, + vp_base + S5P_VP_SHADOW_UPDATE); + + VPPRINTK("()\n\r"); + + return VPROC_NO_ERROR; +} + +/* +* get - get info +*/ +enum s5p_vp_field __s5p_vp_get_field_id(void) +{ + VPPRINTK("()\n\r"); + return (readl(vp_base + S5P_VP_FIELD_ID) == S5P_VP_FIELD_ID_BOTTOM) ? + VPROC_BOTTOM_FIELD : VPROC_TOP_FIELD; +} + +/* +* etc +*/ +unsigned short __s5p_vp_get_update_status(void) +{ + VPPRINTK("()\n\r"); + return readl(vp_base + S5P_VP_SHADOW_UPDATE) & + S5P_VP_SHADOW_UPDATE_ENABLE; +} + + +void __s5p_vp_init_field_id(enum s5p_vp_field mode) +{ + __s5p_vp_set_field_id(mode); +} + +void __s5p_vp_init_op_mode(bool line_skip, + enum s5p_vp_mem_mode mem_mode, + enum s5p_vp_chroma_expansion chroma_exp, + enum s5p_vp_filed_id_toggle toggle_id) +{ + u32 temp_reg; + VPPRINTK("%d, %d, %d, %d\n\r", line_skip, mem_mode, + chroma_exp, toggle_id); + + temp_reg = (line_skip) ? VP_LINE_SKIP_ON : VP_LINE_SKIP_OFF; + temp_reg |= (mem_mode == VPROC_2D_TILE_MODE) ? + VP_MEM_2D_MODE : VP_MEM_LINEAR_MODE; + temp_reg |= (chroma_exp == VPROC_USING_C_TOP_BOTTOM) ? + VP_CHROMA_USE_TOP_BOTTOM : VP_CHROMA_USE_TOP; + temp_reg |= (toggle_id == S5P_TV_VP_FILED_ID_TOGGLE_VSYNC) ? + VP_FIELD_ID_TOGGLE_VSYNC : VP_FIELD_ID_TOGGLE_USER; + + writel(temp_reg, vp_base + S5P_VP_MODE); + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_MODE)); +} + +void __s5p_vp_init_pixel_rate_control(enum s5p_vp_pxl_rate rate) +{ + VPPRINTK("%d\n\r", rate); + + writel(VP_PEL_RATE_CTRL(rate), vp_base + S5P_VP_PER_RATE_CTRL); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_PER_RATE_CTRL)); +} + +enum s5p_tv_vp_err __s5p_vp_init_layer(u32 top_y_addr, + u32 top_c_addr, + u32 bottom_y_addr, + u32 bottom_c_addr, + enum s5p_endian_type src_img_endian, + u32 img_width, + u32 img_height, + u32 src_off_x, + u32 src_x_fract_step, + u32 src_off_y, + u32 src_width, + u32 src_height, + u32 dst_off_x, + u32 dst_off_y, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + VPPRINTK("%d\n\r", src_img_endian); + + writel(1, vp_base + S5P_VP_ENDIAN_MODE); + + error = __s5p_vp_set_top_field_address(top_y_addr, top_c_addr); + + if (error != VPROC_NO_ERROR) + return error; + + error = __s5p_vp_set_bottom_field_address(bottom_y_addr, + bottom_c_addr); + + if (error != VPROC_NO_ERROR) + return error; + + error = __s5p_vp_set_img_size(img_width, img_height); + + if (error != VPROC_NO_ERROR) + return error; + + __s5p_vp_set_src_position(src_off_x, src_x_fract_step, src_off_y); + + __s5p_vp_set_dest_position(dst_off_x, dst_off_y); + + __s5p_vp_set_src_dest_size(src_width, src_height, dst_width, + dst_height, ipc_2d); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_ENDIAN_MODE)); + + return error; + +} + +enum s5p_tv_vp_err __s5p_vp_init_layer_def_poly_filter_coef(u32 top_y_addr, + u32 top_c_addr, + u32 bottom_y_addr, + u32 bottom_c_addr, + enum s5p_endian_type src_img_endian, + u32 img_width, + u32 img_height, + u32 src_off_x, + u32 src_x_fract_step, + u32 src_off_y, + u32 src_width, + u32 src_height, + u32 dst_off_x, + u32 dst_off_y, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + u32 h_ratio = (src_width << 16) / dst_width; + u32 v_ratio = (ipc_2d) ? ((src_height << 17) / dst_height) : + ((src_height << 16) / dst_height); + + __s5p_vp_set_poly_filter_coef_default(h_ratio, v_ratio); + error = __s5p_vp_init_layer(top_y_addr, top_c_addr, + bottom_y_addr, bottom_c_addr, + src_img_endian, + img_width, img_height, + src_off_x, src_x_fract_step, src_off_y, + src_width, src_height, + dst_off_x, dst_off_y, + dst_width, dst_height, + ipc_2d); + return error; +} + +enum s5p_tv_vp_err __s5p_vp_init_poly_filter_coef( + enum s5p_vp_poly_coeff poly_coeff, + signed char ch0, + signed char ch1, + signed char ch2, + signed char ch3) +{ + return __s5p_vp_set_poly_filter_coef(poly_coeff, ch0, ch1, ch2, ch3); +} + +void __s5p_vp_init_bypass_post_process(bool bypass) +{ + VPPRINTK("%d\n\r", bypass); + + writel((bypass) ? VP_BY_PASS_ENABLE : VP_BY_PASS_DISABLE, + vp_base + S5P_PP_BYPASS); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_BYPASS)); +} + +enum s5p_tv_vp_err __s5p_vp_init_csc_coef(enum s5p_vp_csc_coeff csc_coeff, + u32 coeff) +{ + VPPRINTK("%d, %d\n\r", csc_coeff, coeff); + + if (csc_coeff > VPROC_CSC_CR2CR_COEF || + csc_coeff < VPROC_CSC_Y2Y_COEF) { + VPPRINTK("invaild csc_coeff parameter \n\r"); + return S5P_TV_VP_ERR_INVALID_PARAM; + } + + writel(VP_CSC_COEF(coeff), + vp_base + S5P_PP_CSC_Y2Y_COEF + csc_coeff*4); + + VPPRINTK("0x%08x\n\r", + readl(vp_base + S5P_PP_CSC_Y2Y_COEF + csc_coeff*4)); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_init_saturation(u32 sat) +{ + VPPRINTK("%d\n\r", sat); + + writel(VP_SATURATION(sat), vp_base + S5P_PP_SATURATION); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_SATURATION)); +} + +void __s5p_vp_init_sharpness(u32 th_h_noise, + enum s5p_vp_sharpness_control sharpness) +{ + VPPRINTK("%d, %d\n\r", th_h_noise, sharpness); + + writel(VP_TH_HNOISE(th_h_noise) | VP_SHARPNESS(sharpness), + vp_base + S5P_PP_SHARPNESS); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_SHARPNESS)); +} + +enum s5p_tv_vp_err __s5p_vp_init_brightness_contrast_control( + enum s5p_vp_line_eq eq_num, u32 intc, u32 slope) +{ + return __s5p_vp_set_brightness_contrast_control(eq_num, intc, slope); +} + +void __s5p_vp_init_brightness(bool brightness) +{ + __s5p_vp_set_brightness(brightness); +} + + +void __s5p_vp_init_contrast(u8 contrast) +{ + __s5p_vp_set_contrast(contrast); +} + +void __s5p_vp_init_brightness_offset(u32 offset) +{ + VPPRINTK("%d\n\r", offset); + + writel(VP_BRIGHT_OFFSET(offset), vp_base + S5P_PP_BRIGHT_OFFSET); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_BRIGHT_OFFSET)); +} + +void __s5p_vp_init_csc_control(bool sub_y_offset_en, bool csc_en) +{ + u32 temp_reg; + VPPRINTK("%d, %d\n\r", sub_y_offset_en, csc_en); + + temp_reg = (sub_y_offset_en) ? VP_SUB_Y_OFFSET_ENABLE : + VP_SUB_Y_OFFSET_DISABLE; + temp_reg |= (csc_en) ? VP_CSC_ENABLE : VP_CSC_DISABLE; + writel(temp_reg, vp_base + S5P_PP_CSC_EN); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_CSC_EN)); +} + +enum s5p_tv_vp_err __s5p_vp_init_csc_coef_default(enum s5p_vp_csc_type csc_type) +{ + VPPRINTK("%d\n\r", csc_type); + + switch (csc_type) { + + case VPROC_CSC_SD_HD: + writel(Y2Y_COEF_601_TO_709, vp_base + S5P_PP_CSC_Y2Y_COEF); + writel(CB2Y_COEF_601_TO_709, vp_base + S5P_PP_CSC_CB2Y_COEF); + writel(CR2Y_COEF_601_TO_709, vp_base + S5P_PP_CSC_CR2Y_COEF); + writel(Y2CB_COEF_601_TO_709, vp_base + S5P_PP_CSC_Y2CB_COEF); + writel(CB2CB_COEF_601_TO_709, vp_base + S5P_PP_CSC_CB2CB_COEF); + writel(CR2CB_COEF_601_TO_709, vp_base + S5P_PP_CSC_CR2CB_COEF); + writel(Y2CR_COEF_601_TO_709, vp_base + S5P_PP_CSC_Y2CR_COEF); + writel(CB2CR_COEF_601_TO_709, vp_base + S5P_PP_CSC_CB2CR_COEF); + writel(CR2CR_COEF_601_TO_709, vp_base + S5P_PP_CSC_CR2CR_COEF); + break; + + case VPROC_CSC_HD_SD: + writel(Y2Y_COEF_709_TO_601, vp_base + S5P_PP_CSC_Y2Y_COEF); + writel(CB2Y_COEF_709_TO_601, vp_base + S5P_PP_CSC_CB2Y_COEF); + writel(CR2Y_COEF_709_TO_601, vp_base + S5P_PP_CSC_CR2Y_COEF); + writel(Y2CB_COEF_709_TO_601, vp_base + S5P_PP_CSC_Y2CB_COEF); + writel(CB2CB_COEF_709_TO_601, vp_base + S5P_PP_CSC_CB2CB_COEF); + writel(CR2CB_COEF_709_TO_601, vp_base + S5P_PP_CSC_CR2CB_COEF); + writel(Y2CR_COEF_709_TO_601, vp_base + S5P_PP_CSC_Y2CR_COEF); + writel(CB2CR_COEF_709_TO_601, vp_base + S5P_PP_CSC_CB2CR_COEF); + writel(CR2CR_COEF_709_TO_601, vp_base + S5P_PP_CSC_CR2CR_COEF); + break; + + default: + VPPRINTK("invalid csc_type parameter = %d\n\r", csc_type); + return S5P_TV_VP_ERR_INVALID_PARAM; + break; + } + + VPPRINTK("0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,\ + 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n\r", + + readl(vp_base + S5P_PP_CSC_Y2Y_COEF), + readl(vp_base + S5P_PP_CSC_CB2Y_COEF), + readl(vp_base + S5P_PP_CSC_CR2Y_COEF), + readl(vp_base + S5P_PP_CSC_Y2CB_COEF), + readl(vp_base + S5P_PP_CSC_CB2CB_COEF), + readl(vp_base + S5P_PP_CSC_CR2CB_COEF), + readl(vp_base + S5P_PP_CSC_Y2CR_COEF), + readl(vp_base + S5P_PP_CSC_CB2CR_COEF), + readl(vp_base + S5P_PP_CSC_CR2CR_COEF)); + + return VPROC_NO_ERROR; +} + +/* +* start - start functions are only called under stopping video processor +*/ +enum s5p_tv_vp_err __s5p_vp_start(void) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + VPPRINTK("()\n\r"); + + writel(VP_ON_ENABLE, vp_base + S5P_VP_ENABLE); + + error = __s5p_vp_update(); + + VPPRINTK("()\n\r"); + return error; +} + +/* +* stop - stop functions are only called under running video processor +*/ +enum s5p_tv_vp_err __s5p_vp_stop(void) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + VPPRINTK("()\n\r"); + + writel((readl(vp_base + S5P_VP_ENABLE) & ~VP_ON_ENABLE), + vp_base + S5P_VP_ENABLE); + + error = __s5p_vp_update(); + + while (!(readl(vp_base + S5P_VP_ENABLE) & VP_POWER_DOWN_RDY)) + msleep(1); + + + return error; +} + +/* +* reset - reset function +*/ +void __s5p_vp_sw_reset(void) +{ + VPPRINTK("()\n\r"); + + writel((readl(vp_base + S5P_VP_SRESET) | VP_SOFT_RESET), + vp_base + S5P_VP_SRESET); + + while (readl(vp_base + S5P_VP_SRESET) & VP_SOFT_RESET) + msleep(10); + + + VPPRINTK("()\n\r"); +} + +int __init __s5p_vp_probe(struct platform_device *pdev, u32 res_num) +{ + + struct resource *res; + size_t size; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + ret = -ENOENT; + + } + + size = (res->end - res->start) + 1; + + vp_mem = request_mem_region(res->start, size, pdev->name); + + if (vp_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + ret = -ENOENT; + + } + + vp_base = ioremap(res->start, size); + + if (vp_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + ret = -ENOENT; + + + } + + return ret; + +} + +int __init __s5p_vp_release(struct platform_device *pdev) +{ + iounmap(vp_base); + + /* remove memory region */ + + if (vp_mem != NULL) { + if (release_resource(vp_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(vp_mem); + + vp_mem = NULL; + } + + return 0; +} + diff --git a/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.c new file mode 100644 index 0000000..91568d8 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.c @@ -0,0 +1,294 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.c + * + * cec ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/io.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> +#include "regs/regs-cec.h" +#include <linux/slab.h> +#include <linux/mm.h> + +#include "../cec.h" + +#ifdef CECDEBUG +#define CECPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[CEC] %s: " fmt, __func__ , ## args) +#else +#define CECPRINTK(fmt, args...) +#endif + +static struct resource *cec_mem; +void __iomem *cec_base; + +#define S5P_HDMI_FIN 24000000 +#define CEC_DIV_RATIO 187500 + +/** + * Set CEC divider value. + */ +void __s5p_cec_set_divider(void) +{ + u32 div_ratio, reg, div_val; + + div_ratio = S5P_HDMI_FIN/CEC_DIV_RATIO - 1; + + reg = readl(S5P_HDMI_PHY_CONTROL); + reg = (reg & ~(0x3FF<<16)) | (div_ratio << 16); + + writel(reg, S5P_HDMI_PHY_CONTROL); + + div_val = CEC_DIV_RATIO * 0.00005 - 1; + + writeb(0x0, cec_base + CEC_DIVISOR_3); + writeb(0x0, cec_base + CEC_DIVISOR_2); + writeb(0x0, cec_base + CEC_DIVISOR_1); + writeb(div_val, cec_base + CEC_DIVISOR_0); + + CECPRINTK("CEC_DIVISOR_3 = 0x%08x\n", readb(cec_base + CEC_DIVISOR_3)); + CECPRINTK("CEC_DIVISOR_2 = 0x%08x\n", readb(cec_base + CEC_DIVISOR_2)); + CECPRINTK("CEC_DIVISOR_1 = 0x%08x\n", readb(cec_base + CEC_DIVISOR_1)); + CECPRINTK("CEC_DIVISOR_0 = 0x%08x\n", readb(cec_base + CEC_DIVISOR_0)); +} + +/** + * Enable CEC Rx engine + */ +void __s5p_cec_enable_rx(void) +{ + u8 reg; + reg = readb(cec_base + CEC_RX_CTRL); + reg |= CEC_RX_CTRL_ENABLE; + writeb(reg, cec_base + CEC_RX_CTRL); + + CECPRINTK("CEC_RX_CTRL = 0x%08x \n", readb(cec_base + CEC_RX_CTRL)); +} + +/** + * Mask CEC Rx interrupts + */ +void __s5p_cec_mask_rx_interrupts(void) +{ + u8 reg; + reg = readb(cec_base + CEC_IRQ_MASK); + reg |= CEC_IRQ_RX_DONE; + reg |= CEC_IRQ_RX_ERROR; + writeb(reg, cec_base + CEC_IRQ_MASK); + + CECPRINTK("CEC_IRQ_MASK = 0x%08x \n", readb(cec_base + CEC_IRQ_MASK)); +} + +/** + * Unmask CEC Rx interrupts + */ +void __s5p_cec_unmask_rx_interrupts(void) +{ + u8 reg; + reg = readb(cec_base + CEC_IRQ_MASK); + reg &= ~CEC_IRQ_RX_DONE; + reg &= ~CEC_IRQ_RX_ERROR; + writeb(reg, cec_base + CEC_IRQ_MASK); + + CECPRINTK("CEC_IRQ_MASK = 0x%08x \n", readb(cec_base + CEC_IRQ_MASK)); +} + +/** + * Mask CEC Tx interrupts + */ +void __s5p_cec_mask_tx_interrupts(void) +{ + u8 reg; + reg = readb(cec_base + CEC_IRQ_MASK); + reg |= CEC_IRQ_TX_DONE; + reg |= CEC_IRQ_TX_ERROR; + writeb(reg, cec_base + CEC_IRQ_MASK); + + CECPRINTK("CEC_IRQ_MASK = 0x%08x \n", readb(cec_base + CEC_IRQ_MASK)); + +} + +/** + * Unmask CEC Tx interrupts + */ +void __s5p_cec_unmask_tx_interrupts(void) +{ + u8 reg; + reg = readb(cec_base + CEC_IRQ_MASK); + reg &= ~CEC_IRQ_TX_DONE; + reg &= ~CEC_IRQ_TX_ERROR; + writeb(reg, cec_base + CEC_IRQ_MASK); + + CECPRINTK("CEC_IRQ_MASK = 0x%08x \n", readb(cec_base + CEC_IRQ_MASK)); +} + +void __s5p_cec_reset(void) +{ + writeb(CEC_RX_CTRL_RESET, cec_base + CEC_RX_CTRL); + writeb(CEC_TX_CTRL_RESET, cec_base + CEC_TX_CTRL); + + CECPRINTK("CEC_RX_CTRL = 0x%08x \n", readb(cec_base + CEC_RX_CTRL)); + CECPRINTK("CEC_TX_CTRL = 0x%08x \n", readb(cec_base + CEC_TX_CTRL)); +} + +void __s5p_cec_tx_reset(void) +{ + writeb(CEC_TX_CTRL_RESET, cec_base + CEC_TX_CTRL); + + CECPRINTK("CEC_TX_CTRL = 0x%08x \n", readb(cec_base + CEC_TX_CTRL)); +} + +void __s5p_cec_rx_reset(void) +{ + writeb(CEC_RX_CTRL_RESET, cec_base + CEC_RX_CTRL); + CECPRINTK("CEC_RX_CTRL = 0x%08x \n", readb(cec_base + CEC_RX_CTRL)); +} + +void __s5p_cec_threshold(void) +{ + writeb(CEC_FILTER_THRESHOLD, cec_base + CEC_RX_FILTER_TH); + writeb(0, cec_base + CEC_RX_FILTER_CTRL); + CECPRINTK("CEC_RX_FILTER_TH = 0x%08x \n", + readb(cec_base + CEC_RX_FILTER_TH)); +} + +void __s5p_cec_copy_packet(char *data, size_t count) +{ + int i = 0; + u8 reg; + /* copy packet to hardware buffer */ + while (i < count) { + writeb(data[i], cec_base + (CEC_TX_BUFF0 + (i*4))); + i++; + } + + /* set number of bytes to transfer */ + writeb(count, cec_base + CEC_TX_BYTES); + + __s5p_cec_set_tx_state(STATE_TX); + + /* start transfer */ + reg = readb(cec_base + CEC_TX_CTRL); + + reg |= CEC_TX_CTRL_START; + + /* if message is broadcast message - set corresponding bit */ + if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST) + reg |= CEC_TX_CTRL_BCAST; + else + reg &= ~CEC_TX_CTRL_BCAST; + + /* set number of retransmissions */ + reg |= 0x50; + + writeb(reg, cec_base + CEC_TX_CTRL); +} + +void __s5p_cec_set_addr(u32 addr) +{ + writeb(addr & 0x0F, cec_base + CEC_LOGIC_ADDR); + +} + +u32 __s5p_cec_get_status(void) +{ + u32 status = 0; + + status = readb(cec_base + CEC_STATUS_0); + status |= readb(cec_base + CEC_STATUS_1) << 8; + status |= readb(cec_base + CEC_STATUS_2) << 16; + status |= readb(cec_base + CEC_STATUS_3) << 24; + + CECPRINTK("status = 0x%x!\n", status); + + return status; +} + +void __s5p_clr_pending_tx(void) +{ + /* clear interrupt pending bit */ + writeb(CEC_IRQ_TX_DONE | CEC_IRQ_TX_ERROR, cec_base + CEC_IRQ_CLEAR); +} + +void __s5p_clr_pending_rx(void) +{ + /* clear interrupt pending bit */ + writeb(CEC_IRQ_RX_DONE | CEC_IRQ_RX_ERROR, cec_base + CEC_IRQ_CLEAR); +} + +void __s5p_cec_get_rx_buf(u32 size, u8 *buffer) +{ + u32 i = 0; + + while (i < size) { + buffer[i] = readb(cec_base + CEC_RX_BUFF0 + (i * 4)); + i++; + } +} + +void __init __s5p_cec_probe(struct platform_device *pdev) +{ + struct resource *res; + size_t size; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource for cec\n"); + ret = -ENOENT; + + } + + size = (res->end - res->start) + 1; + + cec_mem = request_mem_region(res->start, size, pdev->name); + + if (cec_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region for cec\n"); + ret = -ENOENT; + + } + + cec_base = ioremap(res->start, size); + + if (cec_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region for cec\n"); + ret = -ENOENT; + + + } + +} + +int __init __s5p_cec_release(struct platform_device *pdev) +{ + iounmap(cec_base); + + /* remove memory region */ + if (cec_mem != NULL) { + if (release_resource(cec_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(cec_mem); + + cec_mem = NULL; + } + + return 0; +} + diff --git a/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.h b/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.h new file mode 100644 index 0000000..a5e6abf --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.h @@ -0,0 +1,23 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/cec_s5pv210.h + * + * cec ftn header for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef _LINUX_CEC_H_ +#define _LINUX_CEC_H_ + +#define CEC_IOC_MAGIC 'c' + +/** + * CEC device request code to set logical address. + */ +#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int) + +#endif /* _LINUX_CEC_H_ */ diff --git a/drivers/media/video/samsung/tv20/s5pv210/hdcp_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/hdcp_s5pv210.c new file mode 100644 index 0000000..25ab4c5 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/hdcp_s5pv210.c @@ -0,0 +1,1790 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/hdcp_s5pv210.c + * + * hdcp raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/wait.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include <plat/gpio-cfg.h> + +#include <mach/regs-gpio.h> +#include <mach/gpio.h> + +#include "../ddc.h" +#include "tv_out_s5pv210.h" +#include "regs/regs-hdmi.h" + +/* for Operation check */ +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_HDCP_DEBUG 1 +#define S5P_HDCP_I2C_DEBUG 1 +#define S5P_HDCP_AUTH_DEBUG 1 +#endif + +#ifdef S5P_HDCP_DEBUG +#define HDCPPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[HDCP] %s: " fmt, __func__ , ## args) +#else +#define HDCPPRINTK(fmt, args...) +#endif + +/* for authentication key check */ +#ifdef S5P_HDCP_AUTH_DEBUG +#define AUTHPRINTK(fmt, args...) \ + printk("\t\t\t[AUTHKEY] %s: " fmt, __func__ , ## args) +#else +#define AUTHPRINTK(fmt, args...) +#endif + +enum hdmi_run_mode { + DVI_MODE, + HDMI_MODE +}; + +enum hdmi_resolution { + SD480P, + SD480I, + WWSD480P, + HD720P, + SD576P, + WWSD576P, + HD1080I +}; + +enum hdmi_color_bar_type { + HORIZONTAL, + VERTICAL +}; + +enum hdcp_event { + /* Stop HDCP */ + HDCP_EVENT_STOP, + /* Start HDCP*/ + HDCP_EVENT_START, + /* Start to read Bksv, Bcaps */ + HDCP_EVENT_READ_BKSV_START, + /* Start to write Aksv, An */ + HDCP_EVENT_WRITE_AKSV_START, + /* Start to check if Ri is equal to Rj */ + HDCP_EVENT_CHECK_RI_START, + /* Start 2nd authentication process */ + HDCP_EVENT_SECOND_AUTH_START +}; + +enum hdcp_state { + NOT_AUTHENTICATED, + RECEIVER_READ_READY, + BCAPS_READ_DONE, + BKSV_READ_DONE, + AN_WRITE_DONE, + AKSV_WRITE_DONE, + FIRST_AUTHENTICATION_DONE, + SECOND_AUTHENTICATION_RDY, + RECEIVER_FIFOLSIT_READY, + SECOND_AUTHENTICATION_DONE, +}; + +/* + * Below CSC_TYPE is temporary. CSC_TYPE enum. + * may be included in SetSD480pVars_60Hz etc. + * + * LR : Limited Range (16~235) + * FR : Full Range (0~255) + */ +enum hdmi_intr_src { + WAIT_FOR_ACTIVE_RX, + WDT_FOR_REPEATER, + EXCHANGE_KSV, + UPDATE_P_VAL, + UPDATE_R_VAL, + AUDIO_OVERFLOW, + AUTHEN_ACK, + UNKNOWN_INT +}; + +struct s5p_hdcp_info { + bool is_repeater; + bool hpd_status; + u32 time_out; + u32 hdcp_enable; + + spinlock_t lock; + spinlock_t reset_lock; + + struct i2c_client *client; + + wait_queue_head_t waitq; + enum hdcp_event event; + enum hdcp_state auth_status; + + struct work_struct work; +}; + +static struct s5p_hdcp_info hdcp_info = { + .is_repeater = false, + .time_out = 0, + .hdcp_enable = false, + .client = NULL, + .event = HDCP_EVENT_STOP, + .auth_status = NOT_AUTHENTICATED, + +}; + +#define HDCP_RI_OFFSET 0x08 +#define INFINITE 0xffffffff + +#define HDMI_SYS_ENABLE (1 << 0) +#define HDMI_ASP_ENABLE (1 << 2) +#define HDMI_ASP_DISABLE (~HDMI_ASP_ENABLE) + +#define MAX_DEVS_EXCEEDED (0x1 << 7) +#define MAX_CASCADE_EXCEEDED (0x1 << 3) + +#define MAX_CASCADE_EXCEEDED_ERROR (-1) +#define MAX_DEVS_EXCEEDED_ERROR (-2) +#define REPEATER_ILLEGAL_DEVICE_ERROR (-3) +#define REPEATER_TIMEOUT_ERROR (-4) + +#define AINFO_SIZE 1 +#define BCAPS_SIZE 1 +#define BSTATUS_SIZE 2 +#define SHA_1_HASH_SIZE 20 + +#define KSV_FIFO_READY (0x1 << 5) + +/* spmoon for test : it's not in manual */ +#define SET_HDCP_KSV_WRITE_DONE (0x1 << 3) +#define CLEAR_HDCP_KSV_WRITE_DONE (~SET_HDCP_KSV_WRITE_DONE) + +#define SET_HDCP_KSV_LIST_EMPTY (0x1 << 2) +#define CLEAR_HDCP_KSV_LIST_EMPTY (~SET_HDCP_KSV_LIST_EMPTY) +#define SET_HDCP_KSV_END (0x1 << 1) +#define CLEAR_HDCP_KSV_END (~SET_HDCP_KSV_END) +#define SET_HDCP_KSV_READ (0x1 << 0) +#define CLEAR_HDCP_KSV_READ (~SET_HDCP_KSV_READ) + +#define SET_HDCP_SHA_VALID_READY (0x1 << 1) +#define CLEAR_HDCP_SHA_VALID_READY (~SET_HDCP_SHA_VALID_READY) +#define SET_HDCP_SHA_VALID (0x1 << 0) +#define CLEAR_HDCP_SHA_VALID (~SET_HDCP_SHA_VALID) + +#define TRANSMIT_EVERY_VSYNC (0x1 << 1) + +/* must be checked */ +static bool sw_reset; +static bool is_dvi; +static bool av_mute; +static bool audio_en; + +void s5p_hdmi_set_audio(bool en) +{ + if (en) + audio_en = true; + else + audio_en = false; +} + +int s5p_hdcp_is_reset(void) +{ + int ret = 0; + + if (spin_is_locked(&hdcp_info.reset_lock)) + return 1; + + return ret; +} + +int s5p_hdmi_set_dvi(bool en) +{ + if (en) + is_dvi = true; + else + is_dvi = false; + + return 0; +} + +int s5p_hdmi_set_mute(bool en) +{ + if (en) + av_mute = true; + else + av_mute = false; + + return 0; +} + +int s5p_hdmi_get_mute(void) +{ + return av_mute ? true : false; +} + +int s5p_hdmi_audio_enable(bool en) +{ + u8 reg; + + if (!is_dvi) { + reg = readl(hdmi_base + S5P_HDMI_CON_0); + + if (en) { + reg |= ASP_EN; + writel(HDMI_TRANS_EVERY_SYNC , hdmi_base + S5P_AUI_CON); + } else { + reg &= ~ASP_EN; + writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_AUI_CON); + } + + writel(reg, hdmi_base + S5P_HDMI_CON_0); + } + + return 0; +} + +void s5p_hdmi_mute_en(bool en) +{ + if (!av_mute) { + if (en) { + __s5p_hdmi_video_set_bluescreen(true, 0, 0, 0); + s5p_hdmi_audio_enable(false); + } else { + __s5p_hdmi_video_set_bluescreen(false, 0, 0, 0); + if (audio_en) + s5p_hdmi_audio_enable(true); + } + } +} + +/* + * 1st Authentication step func. + * Write the Ainfo data to Rx + */ +static bool write_ainfo(void) +{ + int ret = 0; + u8 ainfo[2]; + + ainfo[0] = HDCP_Ainfo; + ainfo[1] = 0; + + ret = ddc_write(ainfo, 2); + if (ret < 0) + HDCPPRINTK("Can't write ainfo data through i2c bus\n"); + + return (ret < 0) ? false : true; +} + +/* + * Write the An data to Rx + */ +static bool write_an(void) +{ + int ret = 0; + u8 an[AN_SIZE+1]; + + an[0] = HDCP_An; + + an[1] = readb(hdmi_base + S5P_HDCP_An_0_0); + an[2] = readb(hdmi_base + S5P_HDCP_An_0_1); + an[3] = readb(hdmi_base + S5P_HDCP_An_0_2); + an[4] = readb(hdmi_base + S5P_HDCP_An_0_3); + an[5] = readb(hdmi_base + S5P_HDCP_An_1_0); + an[6] = readb(hdmi_base + S5P_HDCP_An_1_1); + an[7] = readb(hdmi_base + S5P_HDCP_An_1_2); + an[8] = readb(hdmi_base + S5P_HDCP_An_1_3); + + ret = ddc_write(an, AN_SIZE + 1); + if (ret < 0) + HDCPPRINTK("Can't write an data through i2c bus\n"); + +#ifdef S5P_HDCP_AUTH_DEBUG + { + u16 i = 0; + for (i = 1; i < AN_SIZE + 1; i++) + AUTHPRINTK("HDCPAn[%d]: 0x%x \n", i, an[i]); + + } +#endif + + return (ret < 0) ? false : true; +} + +/* + * Write the Aksv data to Rx + */ +static bool write_aksv(void) +{ + int ret = 0; + u8 aksv[AKSV_SIZE+1]; + + aksv[0] = HDCP_Aksv; + + aksv[1] = readb(hdmi_base + S5P_HDCP_AKSV_0_0); + aksv[2] = readb(hdmi_base + S5P_HDCP_AKSV_0_1); + aksv[3] = readb(hdmi_base + S5P_HDCP_AKSV_0_2); + aksv[4] = readb(hdmi_base + S5P_HDCP_AKSV_0_3); + aksv[5] = readb(hdmi_base + S5P_HDCP_AKSV_1); + + if (aksv[1] == 0 && + aksv[2] == 0 && + aksv[3] == 0 && + aksv[4] == 0 && + aksv[5] == 0) + return false; + + ret = ddc_write(aksv, AKSV_SIZE + 1); + if (ret < 0) + HDCPPRINTK("Can't write aksv data through i2c bus\n"); + +#ifdef S5P_HDCP_AUTH_DEBUG + { + u16 i = 0; + for (i = 1; i < AKSV_SIZE + 1; i++) + AUTHPRINTK("HDCPAksv[%d]: 0x%x\n", i, aksv[i]); + + } +#endif + + return (ret < 0) ? false : true; +} + +static bool read_bcaps(void) +{ + int ret = 0; + u8 bcaps[BCAPS_SIZE] = {0}; + + ret = ddc_read(HDCP_Bcaps, bcaps, BCAPS_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bcaps data from i2c bus\n"); + return false; + } + + writel(bcaps[0], hdmi_base + S5P_HDCP_BCAPS); + + HDCPPRINTK("BCAPS(from i2c) : 0x%08x\n", bcaps[0]); + + if (bcaps[0] & REPEATER_SET) + hdcp_info.is_repeater = true; + else + hdcp_info.is_repeater = false; + + HDCPPRINTK("attached device type : %s !! \n\r", + hdcp_info.is_repeater ? "REPEATER" : "SINK"); + HDCPPRINTK("BCAPS(from sfr) = 0x%08x\n", + readl(hdmi_base + S5P_HDCP_BCAPS)); + + return true; +} + +static bool read_again_bksv(void) +{ + u8 bk_sv[BKSV_SIZE] = {0, 0, 0, 0, 0}; + u8 i = 0; + u8 j = 0; + u32 no_one = 0; + u32 no_zero = 0; + u32 result = 0; + int ret = 0; + + ret = ddc_read(HDCP_Bksv, bk_sv, BKSV_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bk_sv data from i2c bus\n"); + return false; + } + +#ifdef S5P_HDCP_AUTH_DEBUG + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("i2c read : Bksv[%d]: 0x%x\n", i, bk_sv[i]); +#endif + + for (i = 0; i < BKSV_SIZE; i++) { + + for (j = 0; j < 8; j++) { + + result = bk_sv[i] & (0x1 << j); + + if (result == 0) + no_zero += 1; + else + no_one += 1; + } + } + + if ((no_zero == 20) && (no_one == 20)) { + HDCPPRINTK("Suucess: no_zero, and no_one is 20\n"); + + writel(bk_sv[0], hdmi_base + S5P_HDCP_BKSV_0_0); + writel(bk_sv[1], hdmi_base + S5P_HDCP_BKSV_0_1); + writel(bk_sv[2], hdmi_base + S5P_HDCP_BKSV_0_2); + writel(bk_sv[3], hdmi_base + S5P_HDCP_BKSV_0_3); + writel(bk_sv[4], hdmi_base + S5P_HDCP_BKSV_1); + +#ifdef S5P_HDCP_AUTH_DEBUG + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("set reg : Bksv[%d]: 0x%x\n", i, bk_sv[i]); + + /* + writel(HDCP_ENC_ENABLE, hdmi_base + S5P_ENC_EN); + */ +#endif + return true; + } else { + HDCPPRINTK("Failed: no_zero or no_one is NOT 20\n"); + return false; + } +} + +static bool read_bksv(void) +{ + u8 bk_sv[BKSV_SIZE] = {0, 0, 0, 0, 0}; + + int i = 0; + int j = 0; + + u32 no_one = 0; + u32 no_zero = 0; + u32 result = 0; + u32 count = 0; + int ret = 0; + + ret = ddc_read(HDCP_Bksv, bk_sv, BKSV_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bk_sv data from i2c bus\n"); + return false; + } + +#ifdef S5P_HDCP_AUTH_DEBUG + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("i2c read : Bksv[%d]: 0x%x\n", i, bk_sv[i]); +#endif + + for (i = 0; i < BKSV_SIZE; i++) { + + for (j = 0; j < 8; j++) { + + result = bk_sv[i] & (0x1 << j); + + if (result == 0) + no_zero++; + else + no_one++; + } + } + + if ((no_zero == 20) && (no_one == 20)) { + + writel(bk_sv[0], hdmi_base + S5P_HDCP_BKSV_0_0); + writel(bk_sv[1], hdmi_base + S5P_HDCP_BKSV_0_1); + writel(bk_sv[2], hdmi_base + S5P_HDCP_BKSV_0_2); + writel(bk_sv[3], hdmi_base + S5P_HDCP_BKSV_0_3); + writel(bk_sv[4], hdmi_base + S5P_HDCP_BKSV_1); + +#ifdef S5P_HDCP_AUTH_DEBUG + for (i = 0; i < BKSV_SIZE; i++) + AUTHPRINTK("set reg : Bksv[%d]: 0x%x\n", i, bk_sv[i]); +#endif + + HDCPPRINTK("Success: no_zero, and no_one is 20\n"); + + } else { + + HDCPPRINTK("Failed: no_zero or no_one is NOT 20\n"); + + while (!read_again_bksv()) { + + count++; + + mdelay(200); + + if (count == 14) + return false; + } + } + + return true; +} + +/* + * Compare the R value of Tx with that of Rx + */ +static bool compare_r_val(void) +{ + int ret = 0; + u8 ri[2] = {0, 0}; + u8 rj[2] = {0, 0}; + u16 i; + + for (i = 0; i < R_VAL_RETRY_CNT; i++) { + + if (hdcp_info.auth_status < AKSV_WRITE_DONE) { + ret = false; + break; + } + + /* Read R value from Tx */ + ri[0] = readl(hdmi_base + S5P_HDCP_Ri_0); + ri[1] = readl(hdmi_base + S5P_HDCP_Ri_1); + + /* Read R value from Rx */ + ret = ddc_read(HDCP_Ri, rj, 2); + if (ret < 0) { + HDCPPRINTK("Can't read r data from i2c bus\n"); + return false; + } + +#ifdef S5P_HDCP_AUTH_DEBUG + AUTHPRINTK("retries :: %d\n", i); + printk(KERN_INFO "\t\t\t Rx(ddc) ->"); + printk(KERN_INFO "rj[0]: 0x%02x, rj[1]: 0x%02x\n", + rj[0], rj[1]); + printk(KERN_INFO "\t\t\t Tx(register) ->"); + printk(KERN_INFO "ri[0]: 0x%02x, ri[1]: 0x%02x\n", + ri[0], ri[1]); +#endif + + /* Compare R value */ + if ((ri[0] == rj[0]) && (ri[1] == rj[1]) && (ri[0] | ri[1])) { + writel(Ri_MATCH_RESULT__YES, + hdmi_base + S5P_HDCP_CHECK_RESULT); + HDCPPRINTK("R0, R0' is matched!!\n"); + ret = true; + break; + } else { + writel(Ri_MATCH_RESULT__NO, + hdmi_base + S5P_HDCP_CHECK_RESULT); + HDCPPRINTK("R0, R0' is not matched!!\n"); + ret = false; + } + + ri[0] = 0; + ri[1] = 0; + rj[0] = 0; + rj[1] = 0; + + } + + if (!ret) { + hdcp_info.event = HDCP_EVENT_STOP; + hdcp_info.auth_status = NOT_AUTHENTICATED; + } + + return ret ? true : false; +} + + +/* + * Enable/Disable Software HPD control + */ +void sw_hpd_enable(bool enable) +{ + u8 reg; + + reg = readb(hdmi_base + S5P_HPD); + reg &= ~HPD_SW_ENABLE; + + if (enable) + writeb(reg | HPD_SW_ENABLE, hdmi_base + S5P_HPD); + else + writeb(reg, hdmi_base + S5P_HPD); +} + +/* + * Set Software HPD level + * + * @param level [in] if 0 - low;othewise, high + */ +void set_sw_hpd(bool level) +{ + u8 reg; + + reg = readb(hdmi_base + S5P_HPD); + reg &= ~HPD_ON; + + if (level) + writeb(reg | HPD_ON, hdmi_base + S5P_HPD); + else + writeb(reg, hdmi_base + S5P_HPD); +} + + +/* + * Reset Authentication + */ +void reset_authentication(void) +{ + u8 reg; + + spin_lock_irq(&hdcp_info.reset_lock); + + hdcp_info.time_out = INFINITE; + hdcp_info.event = HDCP_EVENT_STOP; + hdcp_info.auth_status = NOT_AUTHENTICATED; + + + /* Disable hdcp */ + writeb(0x0, hdmi_base + S5P_HDCP_CTRL1); + writeb(0x0, hdmi_base + S5P_HDCP_CTRL2); + + s5p_hdmi_mute_en(true); + + /* Disable encryption */ + HDCPPRINTK("Stop Encryption by reset!!\n"); + writeb(HDCP_ENC_DIS, hdmi_base + S5P_ENC_EN); + + HDCPPRINTK("Now reset authentication\n"); + + /* disable hdmi status enable reg. */ + reg = readb(hdmi_base + S5P_STATUS_EN); + reg &= HDCP_STATUS_DIS_ALL; + writeb(reg, hdmi_base + S5P_STATUS_EN); + + /* clear all result */ + + writeb(CLEAR_ALL_RESULTS, hdmi_base + S5P_HDCP_CHECK_RESULT); + + /* + * 1. Mask HPD plug and unplug interrupt + * disable HPD INT + */ + sw_reset = true; + reg = s5p_hdmi_get_enabled_interrupt(); + + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG); + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG); + + /* 2. Enable software HPD */ + sw_hpd_enable(true); + + /* 3. Make software HPD logical 0 */ + set_sw_hpd(false); + + /* 4. Make software HPD logical 1 */ + set_sw_hpd(true); + + /* 5. Disable software HPD */ + sw_hpd_enable(false); + + /* 6. Unmask HPD plug and unplug interrupt */ + if (reg & 1<<HDMI_IRQ_HPD_PLUG) + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG); + if (reg & 1<<HDMI_IRQ_HPD_UNPLUG) + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG); + + + sw_reset = false; + + /* clear result */ +#if 0 + writel(Ri_MATCH_RESULT__NO, hdmi_base + S5P_HDCP_CHECK_RESULT); + writel(readl(hdmi_base + S5P_HDMI_CON_0) & HDMI_DIS, + hdmi_base + S5P_HDMI_CON_0); + writel(readl(hdmi_base + S5P_HDMI_CON_0) | HDMI_EN, + hdmi_base + S5P_HDMI_CON_0); +#endif + writel(CLEAR_ALL_RESULTS, hdmi_base + S5P_HDCP_CHECK_RESULT); + + /* set hdcp_int enable */ + reg = readb(hdmi_base + S5P_STATUS_EN); + reg |= WTFORACTIVERX_INT_OCCURRED | + WATCHDOG_INT_OCCURRED | + EXCHANGEKSV_INT_OCCURRED | + UPDATE_RI_INT_OCCURRED; + writeb(reg, hdmi_base + S5P_STATUS_EN); + + /* HDCP Enable */ + writeb(CP_DESIRED_EN, hdmi_base + S5P_HDCP_CTRL1); + + spin_unlock_irq(&hdcp_info.reset_lock); +} + +/* + * Set the timing parameter for load e-fuse key. + */ + +/* TODO: must use clk_get for pclk rate */ +#define PCLK_D_RATE_FOR_HDCP 166000000 + +u32 efuse_ceil(u32 val, u32 time) +{ + u32 res; + + res = val / time; + + if (val % time) + res += 1; + + return res; +} + +#if 0 +static void hdcp_efuse_timing(void) +{ + u32 time, val; + + /* TODO: must use clk_get for pclk rate */ + time = 1000000000/PCLK_D_RATE_FOR_HDCP; + + val = efuse_ceil(EFUSE_ADDR_WIDTH, time); + writeb(val, hdmi_base + S5P_EFUSE_ADDR_WIDTH); + + val = efuse_ceil(EFUSE_SIGDEV_ASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_SIGDEV_ASSERT); + + val = efuse_ceil(EFUSE_SIGDEV_DEASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_SIGDEV_DEASSERT); + + val = efuse_ceil(EFUSE_PRCHG_ASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_PRCHG_ASSERT); + + val = efuse_ceil(EFUSE_PRCHG_DEASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_PRCHG_DEASSERT); + + val = efuse_ceil(EFUSE_FSET_ASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_FSET_ASSERT); + + val = efuse_ceil(EFUSE_FSET_DEASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_FSET_DEASSERT); + + val = efuse_ceil(EFUSE_SENSING, time); + writeb(val, hdmi_base + S5P_EFUSE_SENSING); + + val = efuse_ceil(EFUSE_SCK_ASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_SCK_ASSERT); + + val = efuse_ceil(EFUSE_SCK_DEASSERT, time); + writeb(val, hdmi_base + S5P_EFUSE_SCK_DEASSERT); + + val = efuse_ceil(EFUSE_SDOUT_OFFSET, time); + writeb(val, hdmi_base + S5P_EFUSE_SDOUT_OFFSET); + + val = efuse_ceil(EFUSE_READ_OFFSET, time); + writeb(val, hdmi_base + S5P_EFUSE_READ_OFFSET); + +} +#endif + +/* + * load hdcp key from e-fuse mem. + */ +static int hdcp_loadkey(void) +{ + u8 status; + +#if 0 + hdcp_efuse_timing(); +#endif + /* read HDCP key from E-Fuse */ + writeb(EFUSE_CTRL_ACTIVATE, hdmi_base + S5P_EFUSE_CTRL); + + do { + status = readb(hdmi_base + S5P_EFUSE_STATUS); + } while (!(status & EFUSE_ECC_DONE)); + + if (readb(hdmi_base + S5P_EFUSE_STATUS) & EFUSE_ECC_FAIL) { + HDCPPRINTK("Can't load key from fuse ctrl.\n"); + return -EINVAL; + } + + return 0; + +} + +/* + * Start encryption + */ +static void start_encryption(void) +{ + u32 time_out = 100; + + if (readl(hdmi_base + S5P_HDCP_CHECK_RESULT) == + Ri_MATCH_RESULT__YES) { + + while (time_out) { + + if (readl(hdmi_base + S5P_STATUS) & AUTHENTICATED) { + writel(HDCP_ENC_ENABLE, + hdmi_base + S5P_ENC_EN); + HDCPPRINTK("Encryption start!!\n"); + s5p_hdmi_mute_en(false); + break; + } else { + time_out--; + mdelay(1); + } + } + } else { + writel(HDCP_ENC_DISABLE, hdmi_base + S5P_ENC_EN); + s5p_hdmi_mute_en(true); + HDCPPRINTK("Encryption stop!!\n"); + } +} + +/* + * Check whether Rx is repeater or not + */ +static int check_repeater(void) +{ + int ret = 0; + + u8 i = 0; + u16 j = 0; + + u8 bcaps[BCAPS_SIZE] = {0}; + u8 status[BSTATUS_SIZE] = {0, 0}; + u8 rx_v[SHA_1_HASH_SIZE] = {0}; + u8 ksv_list[HDCP_MAX_DEVS*HDCP_KSV_SIZE] = {0}; + + u32 dev_cnt; + u32 stat; + + bool ksv_fifo_ready = false; + + memset(rx_v, 0x0, SHA_1_HASH_SIZE); + memset(ksv_list, 0x0, HDCP_MAX_DEVS*HDCP_KSV_SIZE); + + while (j <= 50) { + ret = ddc_read(HDCP_Bcaps, + bcaps, BCAPS_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read bcaps data from i2c bus\n"); + return false; + } + + if (bcaps[0] & KSV_FIFO_READY) { + HDCPPRINTK("ksv fifo is ready\n"); + ksv_fifo_ready = true; + writel(bcaps[0], hdmi_base + S5P_HDCP_BCAPS); + break; + } else { + HDCPPRINTK("ksv fifo is not ready\n"); + ksv_fifo_ready = false; + mdelay(100); + j++; + } + + bcaps[0] = 0; + } + + if (!ksv_fifo_ready) + return REPEATER_TIMEOUT_ERROR; + + /* + * Check MAX_CASCADE_EXCEEDED + * or MAX_DEVS_EXCEEDED indicator + */ + ret = ddc_read(HDCP_BStatus, + status, BSTATUS_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read status data from i2c bus\n"); + return false; + } + + /* MAX_CASCADE_EXCEEDED || MAX_DEVS_EXCEEDED */ + if (status[1] & MAX_CASCADE_EXCEEDED) { + HDCPPRINTK("MAX_CASCADE_EXCEEDED\n"); + return MAX_CASCADE_EXCEEDED_ERROR; + } else if (status[0] & MAX_DEVS_EXCEEDED) { + HDCPPRINTK("MAX_CASCADE_EXCEEDED\n"); + return MAX_DEVS_EXCEEDED_ERROR; + } + + writel(status[0], hdmi_base + S5P_HDCP_BSTATUS_0); + writel(status[1], hdmi_base + S5P_HDCP_BSTATUS_1); + + /* Read KSV list */ + dev_cnt = status[0] & 0x7f; + + HDCPPRINTK("status[0] :0x%08x, status[1] :0x%08x!!\n", + status[0], status[1]); + + if (dev_cnt) { + + u32 val = 0; + + /* read ksv */ + ret = ddc_read(HDCP_KSVFIFO, ksv_list, + dev_cnt * HDCP_KSV_SIZE); + if (ret < 0) { + HDCPPRINTK("Can't read ksv fifo!!\n"); + return false; + } + + /* write ksv */ + for (i = 0; i < dev_cnt - 1; i++) { + + writel(ksv_list[(i*5) + 0], + hdmi_base + S5P_HDCP_RX_KSV_0_0); + writel(ksv_list[(i*5) + 1], + hdmi_base + S5P_HDCP_RX_KSV_0_1); + writel(ksv_list[(i*5) + 2], + hdmi_base + S5P_HDCP_RX_KSV_0_2); + writel(ksv_list[(i*5) + 3], + hdmi_base + S5P_HDCP_RX_KSV_0_3); + writel(ksv_list[(i*5) + 4], + hdmi_base + S5P_HDCP_RX_KSV_0_4); + + mdelay(1); + writel(SET_HDCP_KSV_WRITE_DONE, + hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL); + mdelay(1); + + stat = readl(hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL); + + if (!(stat & SET_HDCP_KSV_READ)) + return false; + + HDCPPRINTK("HDCP_RX_KSV_1 = 0x%x\n\r", + readl(hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL)); + HDCPPRINTK("i : %d, dev_cnt : %d, val = 0x%08x\n", + i, dev_cnt, val); + } + + writel(ksv_list[(i*5) + 0], hdmi_base + S5P_HDCP_RX_KSV_0_0); + writel(ksv_list[(i*5) + 1], hdmi_base + S5P_HDCP_RX_KSV_0_1); + writel(ksv_list[(i*5) + 2], hdmi_base + S5P_HDCP_RX_KSV_0_2); + writel(ksv_list[(i*5) + 3], hdmi_base + S5P_HDCP_RX_KSV_0_3); + writel(ksv_list[(i*5) + 4], hdmi_base + S5P_HDCP_RX_KSV_0_4); + + mdelay(1); + + /* end of ksv */ + val = SET_HDCP_KSV_END|SET_HDCP_KSV_WRITE_DONE; + writel(val, hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL); + + HDCPPRINTK("HDCP_RX_KSV_1 = 0x%x\n\r", + readl(hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL)); + HDCPPRINTK("i : %d, dev_cnt : %d, val = 0x%08x\n", + i, dev_cnt, val); + + } else { + + /* + mdelay(200); + */ + + writel(SET_HDCP_KSV_LIST_EMPTY, + hdmi_base + S5P_HDCP_RX_KSV_LIST_CTRL); + } + + + /* Read SHA-1 from receiver */ + ret = ddc_read(HDCP_SHA1, + rx_v, SHA_1_HASH_SIZE); + + if (ret < 0) { + HDCPPRINTK("Can't read sha_1_hash data from i2c bus\n"); + return false; + } + +#ifdef S5P_HDCP_DEBUG + for (i = 0; i < SHA_1_HASH_SIZE; i++) + HDCPPRINTK("SHA_1 rx :: %x\n", rx_v[i]); +#endif + + /* write SHA-1 to register */ + writeb(rx_v[0], hdmi_base + S5P_HDCP_RX_SHA1_0_0); + writeb(rx_v[1], hdmi_base + S5P_HDCP_RX_SHA1_0_1); + writeb(rx_v[2], hdmi_base + S5P_HDCP_RX_SHA1_0_2); + writeb(rx_v[3], hdmi_base + S5P_HDCP_RX_SHA1_0_3); + writeb(rx_v[4], hdmi_base + S5P_HDCP_RX_SHA1_1_0); + writeb(rx_v[5], hdmi_base + S5P_HDCP_RX_SHA1_1_1); + writeb(rx_v[6], hdmi_base + S5P_HDCP_RX_SHA1_1_2); + writeb(rx_v[7], hdmi_base + S5P_HDCP_RX_SHA1_1_3); + writeb(rx_v[8], hdmi_base + S5P_HDCP_RX_SHA1_2_0); + writeb(rx_v[9], hdmi_base + S5P_HDCP_RX_SHA1_2_1); + writeb(rx_v[10], hdmi_base + S5P_HDCP_RX_SHA1_2_2); + writeb(rx_v[11], hdmi_base + S5P_HDCP_RX_SHA1_2_3); + writeb(rx_v[12], hdmi_base + S5P_HDCP_RX_SHA1_3_0); + writeb(rx_v[13], hdmi_base + S5P_HDCP_RX_SHA1_3_1); + writeb(rx_v[14], hdmi_base + S5P_HDCP_RX_SHA1_3_2); + writeb(rx_v[15], hdmi_base + S5P_HDCP_RX_SHA1_3_3); + writeb(rx_v[16], hdmi_base + S5P_HDCP_RX_SHA1_4_0); + writeb(rx_v[17], hdmi_base + S5P_HDCP_RX_SHA1_4_1); + writeb(rx_v[18], hdmi_base + S5P_HDCP_RX_SHA1_4_2); + writeb(rx_v[19], hdmi_base + S5P_HDCP_RX_SHA1_4_3); + + /* SHA write done, and wait for SHA computation being done */ + mdelay(1); + + /* check authentication success or not */ + stat = readb(hdmi_base + S5P_HDCP_AUTH_STATUS); + + HDCPPRINTK("auth status %d\n", stat); + + if (stat & SET_HDCP_SHA_VALID_READY) { + + stat = readb(hdmi_base + S5P_HDCP_AUTH_STATUS); + + if (stat & SET_HDCP_SHA_VALID) + ret = true; + else + ret = false; + } else { + HDCPPRINTK("SHA not ready 0x%x \n\r", stat); + ret = false; + } + + /* clear all validate bit */ + writeb(0x0, hdmi_base + S5P_HDCP_AUTH_STATUS); + + return ret; + +} + +static bool try_read_receiver(void) +{ + u16 i = 0; + bool ret = false; + + s5p_hdmi_mute_en(true); + + for (i = 0; i < 400; i++) { + + msleep(250); + + if (hdcp_info.auth_status != RECEIVER_READ_READY) { + + HDCPPRINTK("hdcp stat. changed!!" + "failed attempt no = %d\n\r", i); + + return false; + } + + ret = read_bcaps(); + + if (ret) { + HDCPPRINTK("succeeded at attempt no= %d \n\r", i); + + return true; + } else + HDCPPRINTK("can't read bcaps!!" + "failed attempt no=%d\n\r", i); + } + + return false; +} + +/* + * stop - stop functions are only called under running HDCP + */ +bool __s5p_stop_hdcp(void) +{ + u32 sfr_val = 0; + + HDCPPRINTK("HDCP ftn. Stop!!\n"); +#if 0 + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG); + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG); +#endif + s5p_hdmi_disable_interrupts(HDMI_IRQ_HDCP); + + hdcp_protocol_status = 0; + + hdcp_info.time_out = INFINITE; + hdcp_info.event = HDCP_EVENT_STOP; + hdcp_info.auth_status = NOT_AUTHENTICATED; + hdcp_info.hdcp_enable = false; + + /* + hdcp_info.client = NULL; + */ + + /* 3. disable hdcp control reg. */ + sfr_val = readl(hdmi_base + S5P_HDCP_CTRL1); + sfr_val &= (ENABLE_1_DOT_1_FEATURE_DIS + & CLEAR_REPEATER_TIMEOUT + & EN_PJ_DIS + & CP_DESIRED_DIS); + writel(sfr_val, hdmi_base + S5P_HDCP_CTRL1); + + /* 1-3. disable hdmi hpd reg. */ + sw_hpd_enable(false); + + /* 1-2. disable hdmi status enable reg. */ + sfr_val = readl(hdmi_base + S5P_STATUS_EN); + sfr_val &= HDCP_STATUS_DIS_ALL; + writel(sfr_val, hdmi_base + S5P_STATUS_EN); + + /* 1-1. clear all status pending */ + sfr_val = readl(hdmi_base + S5P_STATUS); + sfr_val |= HDCP_STATUS_EN_ALL; + writel(sfr_val, hdmi_base + S5P_STATUS); + + /* disable encryption */ + HDCPPRINTK("Stop Encryption by Stop!!\n"); + writel(HDCP_ENC_DISABLE, hdmi_base + S5P_ENC_EN); + s5p_hdmi_mute_en(true); + + /* clear result */ + writel(Ri_MATCH_RESULT__NO, hdmi_base + S5P_HDCP_CHECK_RESULT); + writel(CLEAR_ALL_RESULTS, hdmi_base + S5P_HDCP_CHECK_RESULT); + + /* hdmi disable */ +#if 0 + sfr_val = readl(hdmi_base + S5P_HDMI_CON_0); + sfr_val &= ~(PWDN_ENB_NORMAL | HDMI_EN | ASP_EN); + writel(sfr_val, hdmi_base + S5P_HDMI_CON_0); + */ + HDCPPRINTK("\tSTATUS \t0x%08x\n", readl(hdmi_base + S5P_STATUS)); + HDCPPRINTK("\tSTATUS_EN \t0x%08x\n", + readl(hdmi_base + S5P_STATUS_EN)); + HDCPPRINTK("\tHPD \t0x%08x\n", readl(hdmi_base + S5P_HPD)); + HDCPPRINTK("\tHDCP_CTRL \t0x%08x\n", + readl(hdmi_base + S5P_HDCP_CTRL1)); + HDCPPRINTK("\tMODE_SEL \t0x%08x\n", + readl(hdmi_base + S5P_MODE_SEL)); + HDCPPRINTK("\tENC_EN \t0x%08x\n", readl(hdmi_base + S5P_ENC_EN)); + HDCPPRINTK("\tHDMI_CON_0 \t0x%08x\n", + readl(hdmi_base + S5P_HDMI_CON_0)); + + writel(sfr_val, hdmi_base + S5P_HDMI_CON_0); +#endif + return true; +} + + +void __s5p_hdcp_reset(void) +{ + + __s5p_stop_hdcp(); + + hdcp_protocol_status = 2; + + HDCPPRINTK("HDCP ftn. reset!!\n"); +} + +/* + * start - start functions are only called under stopping HDCP + */ +bool __s5p_start_hdcp(void) +{ + u8 reg; + u32 sfr_val; + + hdcp_info.event = HDCP_EVENT_STOP; + hdcp_info.time_out = INFINITE; + hdcp_info.auth_status = NOT_AUTHENTICATED; + + HDCPPRINTK("HDCP ftn. Start!!\n"); + + sw_reset = true; + reg = s5p_hdmi_get_enabled_interrupt(); + + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_PLUG); + s5p_hdmi_disable_interrupts(HDMI_IRQ_HPD_UNPLUG); + + /* 2. Enable software HPD */ + sw_hpd_enable(true); + + /* 3. Make software HPD logical */ + set_sw_hpd(false); + + /* 4. Make software HPD logical */ + set_sw_hpd(true); + + /* 5. Disable software HPD */ + sw_hpd_enable(false); + set_sw_hpd(false); + + /* 6. Unmask HPD plug and unplug interrupt */ + + if (reg & 1<<HDMI_IRQ_HPD_PLUG) + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_PLUG); + if (reg & 1<<HDMI_IRQ_HPD_UNPLUG) + s5p_hdmi_enable_interrupts(HDMI_IRQ_HPD_UNPLUG); + + sw_reset = false; + HDCPPRINTK("Stop Encryption by Start!!\n"); + + writel(HDCP_ENC_DISABLE, hdmi_base + S5P_ENC_EN); + s5p_hdmi_mute_en(true); + + hdcp_protocol_status = 1; + + if (hdcp_loadkey() < 0) + return false; + + /* for av mute */ + writel(DO_NOT_TRANSMIT, hdmi_base + S5P_GCP_CON); + + /* + * 1-1. set hdmi status enable reg. + * Update_Ri_int_en should be enabled after + * s/w gets ExchangeKSV_int. + */ + writel(HDCP_STATUS_EN_ALL, hdmi_base + S5P_STATUS_EN); + + /* + * 3. set hdcp control reg. + * Disable advance cipher option, Enable CP(Content Protection), + * Disable time-out (This bit is only available in a REPEATER) + * Disable XOR shift, Disable Pj port update, Use external key + */ + sfr_val = 0; + sfr_val |= CP_DESIRED_EN; + writel(sfr_val, hdmi_base + S5P_HDCP_CTRL1); + + s5p_hdmi_enable_interrupts(HDMI_IRQ_HDCP); + + if (!read_bcaps()) { + HDCPPRINTK("can't read ddc port!\n"); + reset_authentication(); + } + + hdcp_info.hdcp_enable = true; + + HDCPPRINTK("\tSTATUS \t0x%08x\n", + readl(hdmi_base + S5P_STATUS)); + HDCPPRINTK("\tSTATUS_EN \t0x%08x\n", + readl(hdmi_base + S5P_STATUS_EN)); + HDCPPRINTK("\tHPD \t0x%08x\n", readl(hdmi_base + S5P_HPD)); + HDCPPRINTK("\tHDCP_CTRL \t0x%08x\n", + readl(hdmi_base + S5P_HDCP_CTRL1)); + HDCPPRINTK("\tMODE_SEL \t0x%08x\n", + readl(hdmi_base + S5P_MODE_SEL)); + HDCPPRINTK("\tENC_EN \t0x%08x\n", + readl(hdmi_base + S5P_ENC_EN)); + HDCPPRINTK("\tHDMI_CON_0 \t0x%08x\n", + readl(hdmi_base + S5P_HDMI_CON_0)); + + return true; +} + + +static void bksv_start_bh(void) +{ + bool ret = false; + + HDCPPRINTK("HDCP_EVENT_READ_BKSV_START bh\n"); + + hdcp_info.auth_status = RECEIVER_READ_READY; + + ret = read_bcaps(); + + if (!ret) { + + ret = try_read_receiver(); + + if (!ret) { + HDCPPRINTK("Can't read bcaps!! retry failed!!\n" + "\t\t\t\thdcp ftn. will be stopped\n"); + + reset_authentication(); + return; + } + } + + hdcp_info.auth_status = BCAPS_READ_DONE; + + ret = read_bksv(); + + if (!ret) { + HDCPPRINTK("Can't read bksv!!" + "hdcp ftn. will be reset\n"); + + reset_authentication(); + return; + } + + hdcp_info.auth_status = BKSV_READ_DONE; + + HDCPPRINTK("authentication status : bksv is done (0x%08x)\n", + hdcp_info.auth_status); +} + +static void second_auth_start_bh(void) +{ + u8 count = 0; + int reg; + bool ret = false; + + int ret_err; + + u32 bcaps; + + HDCPPRINTK("HDCP_EVENT_SECOND_AUTH_START bh\n"); + + ret = read_bcaps(); + + if (!ret) { + + ret = try_read_receiver(); + + if (!ret) { + + HDCPPRINTK("Can't read bcaps!! retry failed!!\n" + "\t\t\t\thdcp ftn. will be stopped\n"); + + reset_authentication(); + return; + } + + } + + bcaps = readl(hdmi_base + S5P_HDCP_BCAPS); + bcaps &= (KSV_FIFO_READY); + + if (!bcaps) { + + HDCPPRINTK("ksv fifo is not ready\n"); + + do { + count++; + + ret = read_bcaps(); + + if (!ret) { + + ret = try_read_receiver(); + if (!ret) + reset_authentication(); + return; + + } + + bcaps = readl(hdmi_base + S5P_HDCP_BCAPS); + bcaps &= (KSV_FIFO_READY); + + if (bcaps) { + HDCPPRINTK("bcaps retries : %d\n", count); + break; + } + + mdelay(100); + + if (!hdcp_info.hdcp_enable) { + + reset_authentication(); + return; + + } + + } while (count <= 50); + + /* wait times exceeded 5 seconds */ + if (count > 50) { + + hdcp_info.time_out = INFINITE; + + /* + * time-out (This bit is only available in a REPEATER) + */ + writel(readl(hdmi_base + S5P_HDCP_CTRL1) | 0x1 << 2, + hdmi_base + S5P_HDCP_CTRL1); + + reset_authentication(); + + return; + } + } + + HDCPPRINTK("ksv fifo ready\n"); + + ret_err = check_repeater(); + + if (ret_err == true) { + u32 flag; + + hdcp_info.auth_status = SECOND_AUTHENTICATION_DONE; + HDCPPRINTK("second authentication done!!\n"); + + flag = readb(hdmi_base + S5P_STATUS); + HDCPPRINTK("hdcp state : %s authenticated!!\n", + flag & AUTHENTICATED ? "" : "not not"); + + start_encryption(); + } else if (ret_err == false) { + /* i2c error */ + HDCPPRINTK("repeater check error!!\n"); + reset_authentication(); + } else { + if (ret_err == REPEATER_ILLEGAL_DEVICE_ERROR) { + /* + * No need to start the HDCP + * in case of invalid KSV (revocation case) + */ + HDCPPRINTK("illegal dev. error!!\n"); + reg = readl(hdmi_base + S5P_HDCP_CTRL2); + reg = 0x1; + writel(reg, hdmi_base + S5P_HDCP_CTRL2); + reg = 0x0; + writel(reg, hdmi_base + S5P_HDCP_CTRL2); + + hdcp_info.auth_status = NOT_AUTHENTICATED; + + } else if (ret_err == REPEATER_TIMEOUT_ERROR) { + reg = readl(hdmi_base + S5P_HDCP_CTRL1); + reg |= SET_REPEATER_TIMEOUT; + writel(reg, hdmi_base + S5P_HDCP_CTRL1); + reg &= ~SET_REPEATER_TIMEOUT; + writel(reg, hdmi_base + S5P_HDCP_CTRL1); + + hdcp_info.auth_status = NOT_AUTHENTICATED; + } else { + /* + * MAX_CASCADE_EXCEEDED_ERROR + * MAX_DEVS_EXCEEDED_ERROR + */ + HDCPPRINTK("repeater check error(MAX_EXCEEDED)!!\n"); + reset_authentication(); + } + } +} + +static bool write_aksv_start_bh(void) +{ + bool ret = false; + + HDCPPRINTK("HDCP_EVENT_WRITE_AKSV_START bh\n"); + + if (hdcp_info.auth_status != BKSV_READ_DONE) { + HDCPPRINTK("bksv is not ready!!\n"); + return false; + } + + ret = write_an(); + if (!ret) + return false; + + hdcp_info.auth_status = AN_WRITE_DONE; + + HDCPPRINTK("an write done!!\n"); + + ret = write_aksv(); + if (!ret) + return false; + + /* + * Wait for 100ms. Transmitter must not read + * Ro' value sooner than 100ms after writing + * Aksv + */ + mdelay(100); + + hdcp_info.auth_status = AKSV_WRITE_DONE; + + HDCPPRINTK("aksv write done!!\n"); + + return ret; +} + +static bool check_ri_start_bh(void) +{ + bool ret = false; + + + HDCPPRINTK("HDCP_EVENT_CHECK_RI_START bh\n"); + + if (hdcp_info.auth_status == AKSV_WRITE_DONE || + hdcp_info.auth_status == FIRST_AUTHENTICATION_DONE || + hdcp_info.auth_status == SECOND_AUTHENTICATION_DONE) { + + ret = compare_r_val(); + + if (ret) { + + if (hdcp_info.auth_status == AKSV_WRITE_DONE) { + /* + * Check whether HDMI receiver is + * repeater or not + */ + if (hdcp_info.is_repeater) + hdcp_info.auth_status + = SECOND_AUTHENTICATION_RDY; + else { + hdcp_info.auth_status + = FIRST_AUTHENTICATION_DONE; + start_encryption(); + } + } + + } else { + + HDCPPRINTK("authentication reset\n"); + reset_authentication(); + + } + + HDCPPRINTK("auth_status = 0x%08x\n", + hdcp_info.auth_status); + + + return true; + } else + reset_authentication(); + + HDCPPRINTK("aksv_write or first/second" + " authentication is not done\n"); + + return false; +} + +/* + * bottom half for hdmi interrupt + * + */ +static void hdcp_work(void *arg) +{ + /* + * I2C int. was occurred + * for reading Bksv and Bcaps + */ + if (hdcp_info.event & (1 << HDCP_EVENT_READ_BKSV_START)) { + + bksv_start_bh(); + + /* clear event */ + /* + spin_lock_bh(&hdcp_info.lock); + */ + hdcp_info.event &= ~(1 << HDCP_EVENT_READ_BKSV_START); + /* + spin_unlock_bh(&hdcp_info.lock); + */ + } + /* + * Watchdog timer int. was occurred + * for checking repeater + */ + if (hdcp_info.event & (1 << HDCP_EVENT_SECOND_AUTH_START)) { + + second_auth_start_bh(); + + /* clear event */ + /* + spin_lock_bh(&hdcp_info.lock); + */ + hdcp_info.event &= ~(1 << HDCP_EVENT_SECOND_AUTH_START); + /* + spin_unlock_bh(&hdcp_info.lock); + */ + } + + /* + * An_Write int. was occurred + * for writing Ainfo, An and Aksv + */ + if (hdcp_info.event & (1 << HDCP_EVENT_WRITE_AKSV_START)) { + + write_aksv_start_bh(); + + /* clear event */ + /* + spin_lock_bh(&hdcp_info.lock); + */ + hdcp_info.event &= ~(1 << HDCP_EVENT_WRITE_AKSV_START); + /* + spin_unlock_bh(&hdcp_info.lock); + */ + } + + /* + * Ri int. was occurred + * for comparing Ri and Ri'(from HDMI sink) + */ + if (hdcp_info.event & (1 << HDCP_EVENT_CHECK_RI_START)) { + + + check_ri_start_bh(); + + /* clear event */ + /* + spin_lock_bh(&hdcp_info.lock); + */ + hdcp_info.event &= ~(1 << HDCP_EVENT_CHECK_RI_START); + /* + spin_unlock_bh(&hdcp_info.lock); + */ + } + +} + +void __s5p_init_hdcp(bool hpd_status, struct i2c_client *ddc_port) +{ + + HDCPPRINTK("HDCP ftn. Init!!\n"); + + is_dvi = false; + av_mute = false; + audio_en = true; + + /* for bh */ + INIT_WORK(&hdcp_info.work, (work_func_t)hdcp_work); + + init_waitqueue_head(&hdcp_info.waitq); + + /* for dev_dbg err. */ + spin_lock_init(&hdcp_info.lock); + +} + + +irqreturn_t __s5p_hdcp_irq_handler(int irq) + +{ + u32 event = 0; + u8 flag; + + event = 0; + /* check HDCP Status */ + flag = readb(hdmi_base + S5P_STATUS); + + HDCPPRINTK("irq_status : 0x%08x\n", readb(hdmi_base + S5P_STATUS)); + + HDCPPRINTK("hdcp state : %s authenticated!!\n", + flag & AUTHENTICATED ? "" : "not"); + + spin_lock_irq(&hdcp_info.lock); + + /* + * processing interrupt + * interrupt processing seq. is firstly set event for workqueue, + * and interrupt pending clear. 'flag|' was used for preventing + * to clear AUTHEN_ACK.- it caused many problem. be careful. + */ + /* I2C INT */ + if (flag & WTFORACTIVERX_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_READ_BKSV_START); + writeb(flag | WTFORACTIVERX_INT_OCCURRED, + hdmi_base + S5P_STATUS); + writeb(0x0, hdmi_base + S5P_HDCP_I2C_INT); + } + + /* AN INT */ + if (flag & EXCHANGEKSV_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_WRITE_AKSV_START); + writeb(flag | EXCHANGEKSV_INT_OCCURRED, + hdmi_base + S5P_STATUS); + writeb(0x0, hdmi_base + S5P_HDCP_AN_INT); + } + + /* RI INT */ + if (flag & UPDATE_RI_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_CHECK_RI_START); + writeb(flag | UPDATE_RI_INT_OCCURRED, + hdmi_base + S5P_STATUS); + writeb(0x0, hdmi_base + S5P_HDCP_RI_INT); + } + + /* WATCHDOG INT */ + if (flag & WATCHDOG_INT_OCCURRED) { + event |= (1 << HDCP_EVENT_SECOND_AUTH_START); + writeb(flag | WATCHDOG_INT_OCCURRED, + hdmi_base + S5P_STATUS); + writeb(0x0, hdmi_base + S5P_HDCP_WDT_INT); + } + + if (!event) { + HDCPPRINTK("unknown irq.\n"); + return IRQ_HANDLED; + } + + hdcp_info.event |= event; + + schedule_work(&hdcp_info.work); + + spin_unlock_irq(&hdcp_info.lock); + + return IRQ_HANDLED; +} + +bool __s5p_set_hpd_detection(bool detection, bool hdcp_enabled, + struct i2c_client *client) +{ + u32 hpd_reg_val = 0; + + if (detection) + hpd_reg_val = CABLE_PLUGGED; + else + hpd_reg_val = CABLE_UNPLUGGED; + + + writel(hpd_reg_val, hdmi_base + S5P_HPD); + + HDCPPRINTK("HPD status :: 0x%08x\n\r", + readl(hdmi_base + S5P_HPD)); + + return true; +} + +int __s5p_hdcp_init(void) +{ + /* for bh */ + INIT_WORK(&hdcp_info.work, (work_func_t)hdcp_work); + is_dvi = false; + av_mute = false; + audio_en = true; + + init_waitqueue_head(&hdcp_info.waitq); + + /* for dev_dbg err. */ + spin_lock_init(&hdcp_info.lock); + spin_lock_init(&hdcp_info.reset_lock); + + s5p_hdmi_register_isr((hdmi_isr)__s5p_hdcp_irq_handler, + (u8)HDMI_IRQ_HDCP); + + return 0; +} + +/* called by hpd */ +int s5p_hdcp_encrypt_stop(bool on) +{ + u32 reg; + + if (hdcp_info.hdcp_enable) { + /* clear interrupt pending all */ + writeb(0x0, hdmi_base + S5P_HDCP_I2C_INT); + writeb(0x0, hdmi_base + S5P_HDCP_AN_INT); + writeb(0x0, hdmi_base + S5P_HDCP_RI_INT); + writeb(0x0, hdmi_base + S5P_HDCP_WDT_INT); + + writel(HDCP_ENC_DISABLE, hdmi_base + S5P_ENC_EN); + s5p_hdmi_mute_en(true); + + if (!sw_reset) { + reg = readl(hdmi_base + S5P_HDCP_CTRL1); + + if (on) { + writel(reg | CP_DESIRED_EN, + hdmi_base + S5P_HDCP_CTRL1); + s5p_hdmi_enable_interrupts(HDMI_IRQ_HDCP); + } else { + hdcp_info.event + = HDCP_EVENT_STOP; + hdcp_info.auth_status + = NOT_AUTHENTICATED; + writel(reg & ~CP_DESIRED_EN, + hdmi_base + S5P_HDCP_CTRL1); + s5p_hdmi_disable_interrupts(HDMI_IRQ_HDCP); + } + } + + HDCPPRINTK("Stop Encryption by HPD Event!!\n"); + } + + return 0; +} +EXPORT_SYMBOL(s5p_hdcp_encrypt_stop); + diff --git a/drivers/media/video/samsung/tv20/s5pv210/hdmi_param.h b/drivers/media/video/samsung/tv20/s5pv210/hdmi_param.h new file mode 100644 index 0000000..a8c6338 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/hdmi_param.h @@ -0,0 +1,414 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/hdmi_param.h + * + * hdmi parameter header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#define PHY_I2C_ADDRESS 0x70 +#define PHY_REG_MODE_SET_DONE 0x1F + +struct hdmi_v_params { + u16 h_blank; + u32 v_blank; + u32 hvline; + u32 h_sync_gen; + u32 v_sync_gen; + u8 avi_vic; + u8 avi_vic_16_9; + u8 interlaced; + u8 repetition; + u8 polarity; + u32 v_blank_f; + u32 v_sync_gen2; + u32 v_sync_gen3; + enum phy_freq pixel_clock; +}; + +struct _hdmi_tg_param { + u16 h_fsz; + u16 hact_st; + u16 hact_sz; + u16 v_fsz; + u16 vsync; + u16 vsync2; + u16 vact_st; + u16 vact_sz; + u16 field_chg; + u16 vact_st2; + u16 vsync_top_hdmi; + u16 vsync_bot_hdmi; + u16 field_top_hdmi; + u16 field_bot_hdmi; + u8 mhl_hsync_width; + u8 mhl_vsync_width; +}; + +static const struct hdmi_v_params video_params[] = { + { 0xA0 , 0x16A0D, 0x32020D, 0x11B80E, 0xA00C , 1 , 1 , 0, 0, 1, + 0, 0, 0, ePHY_FREQ_25_200,}, + { 0x8A , 0x16A0D, 0x35A20D, 0x11300E, 0x900F , 2 , 3 , 0, 0, 1, + 0, 0, 0, ePHY_FREQ_27_027,}, + { 0x172, 0xF2EE , 0x6722EE, 0x2506C , 0x500A , 4 , 4 , 0, 0, 0, + 0, 0, 0, ePHY_FREQ_74_250,}, + { 0x118, 0xB232 , 0x898465, 0x20856, 0x2007 , 5 , 5 , 1, 0, 0, + 0x232A49, 0x234239, 0x4A44A4, ePHY_FREQ_74_250,}, + { 0x114, 0xB106 , 0x6B420D, 0x128024, 0x4007 , 6 , 7 , 1, 1, 1, + 0x10691D, 0x10A10D, 0x380380, ePHY_FREQ_27_027,}, + { 0x114, 0xB106 , 0x6B4106, 0x128024, 0x4007 , 8 , 9 , 0, 1, 1, + 0, 0, 0, ePHY_FREQ_27_027,}, + { 0x228, 0xB106 , 0xD6820D, 0x15084A, 0x4007 , 10, 11, 1, 1, 1, + 0x10691D, 0x10A10D, 0x700700, ePHY_FREQ_54_054,}, + { 0x228, 0xB106 , 0x6B4106, 0x15084A, 0x4007 , 12, 13, 0, 1, 1, + 0, 0, 0, ePHY_FREQ_54_054,}, + { 0x114, 0x16A0D, 0x6B420D, 0x12681E, 0x900F , 14, 15, 0, 1, 1, + 0, 0, 0, ePHY_FREQ_54_054,}, + { 0x118, 0x16C65, 0x898465, 0x20856 , 0x4009 , 16, 16, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_148_500}, + + + { 0x90 , 0x18A71, 0x360271, 0x11280A, 0x500A , 17, 18, 0, 0, 1, + 0, 0, 0, ePHY_FREQ_27, }, + { 0x2BC, 0xF2EE , 0x7BC2EE, 0x779B6 , 0x500A , 19, 19, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_74_250,}, + { 0x2D0, 0xB232 , 0xA50465, 0x8EA0E , 0x2007 , 20, 20, 1, 0, 0, + 0x232A49, 0x234239, 0x738738, ePHY_FREQ_74_250,}, + { 0x120, 0xC138 , 0x6C0271, 0x125016, 0x2005 , 21, 22, 1, 1, 1, + 0x138951, 0x13A13D, 0x378378, ePHY_FREQ_27, }, + { 0x120, 0xC138 , 0x6C0138, 0x125016, 0x3006 , 23, 24, 0, 1, 1, + 0, 0, 0, ePHY_FREQ_27, }, + { 0x240, 0xC138 , 0xD80271, 0x14A82E, 0x2005 , 25, 26, 1, 1, 1, + 0x138951, 0x13A13D, 0x6F06F0, ePHY_FREQ_54, }, + { 0x240, 0xC138 , 0xD80138, 0x14A82E, 0x2005 , 27, 28, 0, 1, 1, + 0, 0, 0, ePHY_FREQ_54, }, + { 0x120, 0x18A71, 0x6C0271, 0x125816, 0x500A , 29, 30, 0, 1, 1, + 0, 0, 0, ePHY_FREQ_54, }, + { 0x2D0, 0x16C65, 0xA50465, 0x8EA0E , 0x4009 , 31, 31, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_148_500,}, + { 0x33E, 0x16C65, 0xABE465, 0xAA27C , 0x4009 , 32, 32, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_74_250,}, + + + { 0x2D0, 0x16C65, 0xA50465, 0x8EA0E , 0x4009 , 33, 33, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_74_250, }, + { 0x118, 0x16C65, 0x898465, 0x20856 , 0x4009 , 34, 34, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_74_250, }, + { 0x228, 0x16A0D, 0xD6820D, 0x14D83E, 0x900F , 35, 36, 0, 0, 1, + 0, 0, 0, ePHY_FREQ_108_108, }, + { 0x240, 0x18A71, 0xD80271, 0x14B82E, 0x500A , 37, 38, 0, 1, 1, + 0, 0, 0, ePHY_FREQ_108, }, + { 0x180, 0x2AA71, 0x9004E2, 0x3181E , 0x1701C, 39, 39, 0, 0, 0, + 0x2712C6, 0x28728F, 0x4a44a4, ePHY_FREQ_72, }, + { 0x2D0, 0xB232 , 0xA50465, 0x8EA0E , 0x2007 , 40, 40, 1, 0, 0, + 0x232A49, 0x234239, 0x738738, ePHY_FREQ_148_500, }, + { 0x2BC, 0xF2EE , 0x7BC2EE, 0x779B6 , 0x500A , 41, 41, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_148_500, }, + { 0x90 , 0x18A71, 0x360271, 0x11280A, 0x500A , 42, 43, 0, 0, 1, + 0, 0, 0, ePHY_FREQ_54, }, + { 0x120, 0xC138 , 0x6C0271, 0x125016, 0x2005 , 44, 45, 1, 1, 1, + 0x138951, 0x13A13D, 0x378378, ePHY_FREQ_54, }, + { 0x118, 0xB232 , 0x898465, 0x20856 , 0x2007 , 46, 46, 1, 0, 0, + 0x232A49, 0x234239, 0x4A44A4, ePHY_FREQ_148_500, }, + + + { 0x172, 0xF2EE , 0x6722EE, 0x2506C , 0x500A , 47, 47, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_148_500,}, + { 0x8A , 0x16A0D, 0x35A20D, 0x11300E, 0x900F , 48, 49, 0, 0, 1, + 0, 0, 0, ePHY_FREQ_54_054, }, + { 0x114, 0xB106 , 0x6B420D, 0x128024, 0x4007 , 50, 51, 1, 1, 1, + 0x10691D, 0x10A10D, 0x380380, ePHY_FREQ_54_054, }, + { 0x90 , 0x18A71, 0x360271, 0x11280A, 0x500A , 52, 53, 0, 0, 1, + 0, 0, 0, ePHY_FREQ_108, }, + { 0x120, 0xC138 , 0x6C0271, 0x125016, 0x2005 , 54, 55, 1, 1, 1, + 0x138951, 0x13A13D, 0x378378, ePHY_FREQ_108, }, + { 0x8A , 0x16A0D, 0x35A20D, 0x11300E, 0x900F , 56, 57, 0, 0, 1, + 0, 0, 0, ePHY_FREQ_108_108,}, + { 0x114, 0xB106 , 0x6B420D, 0x128024, 0x4007 , 58, 59, 1, 1, 1, + 0x10691D, 0x10A10D, 0x380380, ePHY_FREQ_108_108,}, + + { 0x8A , 0x16A0D, 0x35A20D, 0x11300E, 0x900F , 2 , 3 , 0, 0, 1, + 0, 0, 0, ePHY_FREQ_27, }, + { 0x172, 0xF2EE , 0x6722EE, 0x2506C , 0x500A , 4 , 4 , 0, 0, 0, + 0, 0, 0, ePHY_FREQ_74_176, }, + { 0x118, 0xB232 , 0x898465, 0x20856, 0x2007 , 5 , 5 , 1, 0, 0, + 0x232A49, 0x234239, 0x4A44A4, ePHY_FREQ_74_176, }, + { 0x118, 0x16C65, 0x898465, 0x20856 , 0x4009 , 16, 16, 0, 0, 0, + 0, 0, 0, ePHY_FREQ_148_352,}, +}; + +static const struct _hdmi_tg_param hdmi_tg_param[] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + + {0x35a , 0x8a , 0x2d0 , 0x20d , 0x1 , 0x233 , 0x2d , 0x1e0 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0x672 , 0x172 , 0x500 , 0x2ee , 0x1 , 0x233 , 0x1e , 0x2d0 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0x898 , 0x118 , 0x780 , 0x465 , 0x1 , 0x233 , 0x16 , 0x21c , + 0x233 , 0x249 , 0x1 , 0x233 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + + {0x898 , 0x118 , 0x780 , 0x465 , 0x1 , 0x233 , 0x2d , 0x438 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0x360 , 0x90 , 0x2d0 , 0x271 , 0x1 , 0x233 , 0x31 , 0x240 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0x7bc , 0x2bc , 0x500 , 0x2ee , 0x1 , 0x233 , 0x1e , 0x2d0 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0xa50 , 0x2d0 , 0x780 , 0x465 , 0x1 , 0x233 , 0x16 , 0x21c , + 0x233 , 0x249 , 0x1 , 0x233 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + + {0xa50 , 0x2d0 , 0x780 , 0x465 , 0x1 , 0x233 , 0x2d , 0x438 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + + {0x898 , 0x118 , 0x780 , 0x465 , 0x1 , 0x233 , 0x2d , 0x438 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + + {0x35a , 0x8a , 0x2d0 , 0x20d , 0x1 , 0x233 , 0x2d , 0x1e0 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0x672 , 0x172 , 0x500 , 0x2ee , 0x1 , 0x233 , 0x1e , 0x2d0 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0x898 , 0x118 , 0x780 , 0x465 , 0x1 , 0x233 , 0x16 , 0x21c , + 0x233 , 0x249 , 0x1 , 0x233 , 0x1 , 0x233 , 0xf , 0x1 }, + + {0x898 , 0x118 , 0x780 , 0x465 , 0x1 , 0x233 , 0x2d , 0x438 , + 0x233 , 0x248 , 0x1 , 0x1 , 0x1 , 0x233 , 0xf , 0x1 }, + +}; + +static const u8 phy_config[][3][32] = { + { /* freq = 25.200 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x10, 0x02, + 0x51, 0x5f, 0xF1, 0x54, 0x7e, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xf3, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x10, 0x02, + 0x51, 0x9f, 0xF6, 0x54, 0x9e, 0x84, 0x00, 0x32, 0x38, 0x00, 0xB8, + 0x10, 0xE0, 0x22, 0x40, 0xc2, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x10, 0x02, + 0x51, 0xFf, 0xF3, 0x54, 0xbd, 0x84, 0x00, 0x30, 0x38, 0x00, 0xA4, + 0x10, 0xE0, 0x22, 0x40, 0xa2, 0x26, 0x00, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 25.175 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x1e, 0x20, 0x6B, 0x50, 0x10, + 0x51, 0xf1, 0x31, 0x54, 0xbd, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xf3, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x2b, 0x40, 0x6B, 0x50, 0x10, + 0x51, 0xF2, 0x32, 0x54, 0xec, 0x84, 0x00, 0x10, 0x38, 0x00, 0xB8, + 0x10, 0xE0, 0x22, 0x40, 0xc2, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x1e, 0x20, 0x6B, 0x10, 0x02, + 0x51, 0xf1, 0x31, 0x54, 0xbd, 0x84, 0x00, 0x10, 0x38, 0x00, 0xA4, + 0x10, 0xE0, 0x22, 0x40, 0xa2, 0x26, 0x00, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 27 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x10, 0x02, + 0x51, 0xDf, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x08, 0x6A, 0x10, 0x02, + 0x51, 0xCf, 0xF1, 0x54, 0xa9, 0x84, 0x00, 0x10, 0x38, 0x00, 0xB8, + 0x10, 0xE0, 0x22, 0x40, 0xb5, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xfc, 0x08, 0x6B, 0x10, 0x02, + 0x51, 0x2f, 0xF2, 0x54, 0xcb, 0x84, 0x00, 0x10, 0x38, 0x00, 0xA4, + 0x10, 0xE0, 0x22, 0x40, 0x97, 0x26, 0x00, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 27.027 MHz */ + { 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, 0x6B, 0x10, 0x02, + 0x51, 0xDf, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xe2, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x31, 0x50, 0x6B, 0x10, 0x02, + 0x51, 0x8f, 0xF3, 0x54, 0xa9, 0x84, 0x00, 0x30, 0x38, 0x00, 0xB8, + 0x10, 0xE0, 0x22, 0x40, 0xb5, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0x1b, 0x64, 0x6F, 0x10, 0x02, + 0x51, 0x7f, 0xF8, 0x54, 0xcb, 0x84, 0x00, 0x32, 0x38, 0x00, 0xA4, + 0x10, 0xE0, 0x22, 0x40, 0x97, 0x26, 0x00, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 54 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x10, 0x01, + 0x51, 0xDf, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xe3, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x08, 0x6A, 0x10, 0x01, + 0x51, 0xCf, 0xF1, 0x54, 0xa9, 0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0xb5, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xfc, 0x08, 0x6B, 0x10, 0x01, + 0x51, 0x2f, 0xF2, 0x54, 0xcb, 0x84, 0x00, 0x10, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0x97, 0x26, 0x01, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 54.054 MHz */ + { 0x01, 0x05, 0x00, 0xd4, 0x10, 0x9C, 0x09, 0x64, 0x6B, 0x10, 0x01, + 0x51, 0xDf, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xe2, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xd4, 0x10, 0x9C, 0x31, 0x50, 0x6B, 0x10, 0x01, + 0x51, 0x8f, 0xF3, 0x54, 0xa9, 0x84, 0x00, 0x30, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0xb5, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0x1b, 0x64, 0x6F, 0x10, 0x01, + 0x51, 0x7f, 0xF8, 0x54, 0xcb, 0x84, 0x00, 0x32, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0x97, 0x26, 0x01, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 74.250 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40, 0x6A, 0x10, 0x01, + 0x51, 0xff, 0xF1, 0x54, 0xba, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd6, 0x40, 0x6B, 0x10, 0x01, + 0x51, 0x7f, 0xF2, 0x54, 0xe8, 0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0x83, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x34, 0x40, 0x6B, 0x10, 0x01, + 0x51, 0xef, 0xF2, 0x54, 0x16, 0x85, 0x00, 0x10, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0xdc, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 74.176 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B, 0x6D, 0x10, 0x01, + 0x51, 0xef, 0xF3, 0x54, 0xb9, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0xab, 0x5B, 0x6F, 0x10, 0x01, + 0x51, 0xbf, 0xF9, 0x54, 0xe8, 0x84, 0x00, 0x32, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0x84, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0xcd, 0x5B, 0x6F, 0x10, 0x01, + 0x51, 0xdf, 0xF5, 0x54, 0x16, 0x85, 0x00, 0x30, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0xdc, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 148.500 MHz - Pre-emph + Higher Tx amp. */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40, 0x6A, 0x18, 0x00, + 0x51, 0xff, 0xF1, 0x54, 0xba, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd6, 0x40, 0x6B, 0x18, 0x00, + 0x51, 0x7f, 0xF2, 0x54, 0xe8, 0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x23, 0x41, 0x83, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x34, 0x40, 0x6B, 0x18, 0x00, + 0x51, 0xef, 0xF2, 0x54, 0x16, 0x85, 0x00, 0x10, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x23, 0x41, 0x6d, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 148.352 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B, 0x6D, 0x18, 0x00, + 0x51, 0xef, 0xF3, 0x54, 0xb9, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xa5, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0xab, 0x5B, 0x6F, 0x18, 0x00, + 0x51, 0xbf, 0xF9, 0x54, 0xe8, 0x84, 0x00, 0x32, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x23, 0x41, 0x84, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0xcd, 0x5B, 0x6F, 0x18, 0x00, + 0x51, 0xdf, 0xF5, 0x54, 0x16, 0x85, 0x00, 0x30, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x23, 0x41, 0x6d, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 108.108 MHz */ + { 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, 0x6B, 0x18, 0x00, + 0x51, 0xDf, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xe2, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x31, 0x50, 0x6D, 0x18, 0x00, + 0x51, 0x8f, 0xF3, 0x54, 0xa9, 0x84, 0x00, 0x30, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0xb5, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0x1b, 0x64, 0x6F, 0x18, 0x00, + 0x51, 0x7f, 0xF8, 0x54, 0xcb, 0x84, 0x00, 0x32, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0x97, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 72 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x10, 0x01, + 0x51, 0xEf, 0xF1, 0x54, 0xb4, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xaa, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6F, 0x10, 0x01, + 0x51, 0xBf, 0xF4, 0x54, 0xe1, 0x84, 0x00, 0x30, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0x88, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6B, 0x18, 0x00, + 0x51, 0xDf, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0xe3, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 25 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x20, 0x40, 0x6B, 0x50, 0x10, + 0x51, 0xff, 0xF1, 0x54, 0xbc, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xf5, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x08, 0x40, 0x6B, 0x50, 0x10, + 0x51, 0x7f, 0xF2, 0x54, 0xea, 0x84, 0x00, 0x10, 0x38, 0x00, 0xB8, + 0x10, 0xE0, 0x22, 0x40, 0xc4, 0x26, 0x00, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x20, 0x40, 0x6B, 0x10, 0x02, + 0x51, 0xff, 0xF1, 0x54, 0xbc, 0x84, 0x00, 0x10, 0x38, 0x00, 0xA4, + 0x10, 0xE0, 0x22, 0x40, 0xa3, 0x26, 0x00, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 65 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x0c, 0x6B, 0x10, 0x01, + 0x51, 0xBf, 0xF1, 0x54, 0xa3, 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xbc, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf2, 0x30, 0x6A, 0x10, 0x01, + 0x51, 0x2f, 0xF2, 0x54, 0xcb, 0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0x96, 0x26, 0x01, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd0, 0x40, 0x6B, 0x10, 0x01, + 0x51, 0x9f, 0xF2, 0x54, 0xf4, 0x84, 0x00, 0x10, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0x7D, 0x26, 0x01, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 108 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6D, 0x18, 0x00, + 0x51, 0xDf, 0xF2, 0x54, 0x87, 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0xe3, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x08, 0x6A, 0x18, 0x00, + 0x51, 0xCf, 0xF1, 0x54, 0xa9, 0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x22, 0x40, 0xb5, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xfc, 0x08, 0x6B, 0x18, 0x00, + 0x51, 0x2f, 0xF2, 0x54, 0xcb, 0x84, 0x00, 0x10, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x22, 0x40, 0x97, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, + + { /* freq = 162 MHz */ + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, 0x6F, 0x18, 0x00, + 0x51, 0x7f, 0xF8, 0x54, 0xcb, 0x84, 0x00, 0x32, 0x38, 0x00, 0x08, + 0x10, 0xE0, 0x22, 0x40, 0x97, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x18, 0x40, 0x6B, 0x18, 0x00, + 0x51, 0xAf, 0xF2, 0x54, 0xfd, 0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, + 0x10, 0xE0, 0x23, 0x41, 0x78, 0x26, 0x02, 0x00, 0x00, 0x80, }, + { 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd0, 0x40, 0x6B, 0x18, 0x00, + 0x51, 0x3f, 0xF3, 0x54, 0x30, 0x85, 0x00, 0x10, 0x38, 0x00, 0xE4, + 0x10, 0xE0, 0x23, 0x41, 0x64, 0x26, 0x02, 0x00, 0x00, 0x80, }, + }, +}; + diff --git a/drivers/media/video/samsung/tv20/s5pv210/hdmi_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/hdmi_s5pv210.c new file mode 100644 index 0000000..58bdcad --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/hdmi_s5pv210.c @@ -0,0 +1,2131 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/hdmi_s5pv210.c + * + * hdmi raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include <plat/clock.h> + +#include "tv_out_s5pv210.h" + +#include "regs/regs-hdmi.h" +#include "hdmi_param.h" + +#include "../hpd.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_HDMI_DEBUG 1 +#endif + +#ifdef S5P_HDMI_DEBUG +#define HDMIPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[HDMI] %s: " fmt, __func__ , ## args) +#else +#define HDMIPRINTK(fmt, args...) +#endif + +static struct resource *hdmi_mem; +void __iomem *hdmi_base; + +static struct resource *i2c_hdmi_phy_mem; +void __iomem *i2c_hdmi_phy_base; + +spinlock_t lock_hdmi; + +/* + * i2c_hdmi_phy related + */ + +#define PHY_I2C_ADDRESS 0x70 + +#define I2C_ACK (1<<7) +#define I2C_INT (1<<5) +#define I2C_PEND (1<<4) + +#define I2C_INT_CLEAR (0<<4) + +#define I2C_CLK (0<<6) +#define I2C_CLK_PEND_INT (I2C_CLK|I2C_INT_CLEAR|I2C_INT) + +#define I2C_ENABLE (1<<4) +#define I2C_START (1<<5) + +#define I2C_MODE_MTX (0x3<<6) +#define I2C_MODE_MRX (0x2<<6) +#define I2C_MODE_SRX (0x0<<6) + +#define I2C_IDLE 0 + +static struct { + s32 state; + u8 *buffer; + s32 bytes; +} i2c_hdmi_phy_context; + + +#define STATE_IDLE 0 +#define STATE_TX_EDDC_SEGADDR 1 +#define STATE_TX_EDDC_SEGNUM 2 +#define STATE_TX_DDC_ADDR 3 +#define STATE_TX_DDC_OFFSET 4 +#define STATE_RX_DDC_ADDR 5 +#define STATE_RX_DDC_DATA 6 +#define STATE_RX_ADDR 7 +#define STATE_RX_DATA 8 +#define STATE_TX_ADDR 9 +#define STATE_TX_DATA 10 +#define STATE_TX_STOP 11 +#define STATE_RX_STOP 12 + +static s32 i2c_hdmi_phy_interruptwait(void) +{ + u8 status, reg; + s32 retval = 0; + + do { + status = readb(i2c_hdmi_phy_base + I2C_HDMI_CON); + + if (status & I2C_PEND) { + /* check status flags */ + reg = readb(i2c_hdmi_phy_base + I2C_HDMI_STAT); + break; + } + } while (1); + + return retval; +} + +s32 i2c_hdmi_phy_read(u8 addr, u8 nbytes, u8 *buffer) +{ + u8 reg; + s32 ret = 0; + u32 proc = true; + + i2c_hdmi_phy_context.state = STATE_RX_ADDR; + i2c_hdmi_phy_context.buffer = buffer; + i2c_hdmi_phy_context.bytes = nbytes; + + writeb(I2C_CLK | I2C_INT | I2C_ACK, + i2c_hdmi_phy_base + I2C_HDMI_CON); + + writeb(I2C_ENABLE | I2C_MODE_MRX, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + writeb(addr & 0xFE, + i2c_hdmi_phy_base + I2C_HDMI_DS); + + writeb(I2C_ENABLE | I2C_START | I2C_MODE_MRX, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + while (proc) { + + if (i2c_hdmi_phy_context.state != STATE_RX_STOP) { + if (i2c_hdmi_phy_interruptwait() != 0) { + HDMIPRINTK("interrupt wait failed!!!\n"); + ret = EINVAL; + break; + } + } + + switch (i2c_hdmi_phy_context.state) { + + case STATE_RX_DATA: + + reg = readb(i2c_hdmi_phy_base + I2C_HDMI_DS); + *(i2c_hdmi_phy_context.buffer) = reg; + + i2c_hdmi_phy_context.buffer++; + --(i2c_hdmi_phy_context.bytes); + + if (i2c_hdmi_phy_context.bytes == 1) { + i2c_hdmi_phy_context.state = STATE_RX_STOP; + writeb(I2C_CLK_PEND_INT, + i2c_hdmi_phy_base + I2C_HDMI_CON); + } else { + writeb(I2C_CLK_PEND_INT | I2C_ACK, + i2c_hdmi_phy_base + I2C_HDMI_CON); + + } + break; + + case STATE_RX_ADDR: + i2c_hdmi_phy_context.state = STATE_RX_DATA; + + if (i2c_hdmi_phy_context.bytes == 1) { + i2c_hdmi_phy_context.state = STATE_RX_STOP; + writeb(I2C_CLK_PEND_INT, + i2c_hdmi_phy_base + I2C_HDMI_CON); + } else { + writeb(I2C_CLK_PEND_INT | I2C_ACK, + i2c_hdmi_phy_base + I2C_HDMI_CON); + } + + break; + + case STATE_RX_STOP: + + i2c_hdmi_phy_context.state = STATE_IDLE; + + reg = readb(i2c_hdmi_phy_base + I2C_HDMI_DS); + + *(i2c_hdmi_phy_context.buffer) = reg; + + writeb(I2C_MODE_MRX|I2C_ENABLE, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + writeb(I2C_CLK_PEND_INT, + i2c_hdmi_phy_base + I2C_HDMI_CON); + + writeb(I2C_MODE_MRX, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + while (readb(i2c_hdmi_phy_base + I2C_HDMI_STAT) & + (1<<5)) + msleep(1); + + proc = false; + + break; + + case STATE_IDLE: + + default: + HDMIPRINTK("error state!!!\n"); + + ret = EINVAL; + + proc = false; + + break; + } + } + + return ret; +} + +s32 i2c_hdmi_phy_write(u8 addr, u8 nbytes, u8 *buffer) +{ + u8 reg; + s32 ret = 0; + u32 proc = true; + + i2c_hdmi_phy_context.state = STATE_TX_ADDR; + i2c_hdmi_phy_context.buffer = buffer; + i2c_hdmi_phy_context.bytes = nbytes; + + writeb(I2C_CLK | I2C_INT | I2C_ACK, + i2c_hdmi_phy_base + I2C_HDMI_CON); + + writeb(I2C_ENABLE | I2C_MODE_MTX, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + writeb(addr & 0xFE, + i2c_hdmi_phy_base + I2C_HDMI_DS); + + writeb(I2C_ENABLE | I2C_START | I2C_MODE_MTX, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + while (proc) { + + if (i2c_hdmi_phy_interruptwait() != 0) { + HDMIPRINTK("interrupt wait failed!!!\n"); + ret = EINVAL; + break; + } + + switch (i2c_hdmi_phy_context.state) { + + case STATE_TX_ADDR: + + case STATE_TX_DATA: + i2c_hdmi_phy_context.state = STATE_TX_DATA; + + reg = *(i2c_hdmi_phy_context.buffer); + + writeb(reg, i2c_hdmi_phy_base + I2C_HDMI_DS); + + i2c_hdmi_phy_context.buffer++; + --(i2c_hdmi_phy_context.bytes); + + if (i2c_hdmi_phy_context.bytes == 0) { + i2c_hdmi_phy_context.state = STATE_TX_STOP; + writeb(I2C_CLK_PEND_INT, + i2c_hdmi_phy_base + I2C_HDMI_CON); + } else + writeb(I2C_CLK_PEND_INT | I2C_ACK, + i2c_hdmi_phy_base + I2C_HDMI_CON); + break; + + case STATE_TX_STOP: + i2c_hdmi_phy_context.state = STATE_IDLE; + + writeb(I2C_MODE_MTX | I2C_ENABLE, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + writeb(I2C_CLK_PEND_INT, + i2c_hdmi_phy_base + I2C_HDMI_CON); + + writeb(I2C_MODE_MTX, + i2c_hdmi_phy_base + I2C_HDMI_STAT); + + while (readb(i2c_hdmi_phy_base + I2C_HDMI_STAT) & + (1<<5)) + msleep(1); + + proc = false; + + break; + + case STATE_IDLE: + break; + + default: + HDMIPRINTK("error state!!!\n"); + + ret = EINVAL; + + proc = false; + + break; + } + } + + return ret; +} + +int hdmi_phy_down(bool on, u8 addr, u8 offset, u8 *read_buffer) +{ + u8 buff[2] = {0}; + + buff[0] = addr; + buff[1] = (on) ? (read_buffer[addr] & (~(1<<offset))) : + (read_buffer[addr] | (1<<offset)); + + if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + return EINVAL; + + return 0; +} + +int __s5p_hdmi_phy_power(bool on) +{ +#if !defined(CONFIG_MACH_P1) + /* for the case that + - only analog tv is supported + - and the power for the hdmi phy is not supported*/ + return 0; +#endif + + u32 size; + u8 *buffer; + u8 read_buffer[0x40] = {0, }; + + size = sizeof(phy_config[0][0]) + / sizeof(phy_config[0][0][0]); + + buffer = (u8 *) phy_config[0][0]; + + /* write offset */ + if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 1, buffer) != 0) { + HDMIPRINTK("%s I2C Write Error!...\n", __func__); + return EINVAL; + } + + /* read data */ + if (i2c_hdmi_phy_read(PHY_I2C_ADDRESS, size, read_buffer) != 0) { + HDMIPRINTK("i2c_hdmi_phy_read failed.\n"); + return EINVAL; + } + + /* i can't get the information about phy setting */ + if (on) { + /* on */ + /* biaspd */ + hdmi_phy_down(true, 0x1, 0x5, read_buffer); + /* clockgenpd */ + hdmi_phy_down(true, 0x1, 0x7, read_buffer); + /* pllpd */ + hdmi_phy_down(true, 0x5, 0x5, read_buffer); + /* pcgpd */ + hdmi_phy_down(true, 0x17, 0x0, read_buffer); + /* txpd */ + hdmi_phy_down(true, 0x17, 0x1, read_buffer); + } else { + /* off */ + /* biaspd */ + hdmi_phy_down(false, 0x1, 0x5, read_buffer); + /* clockgenpd */ + hdmi_phy_down(false, 0x1, 0x7, read_buffer); + /* pllpd */ + hdmi_phy_down(false, 0x5, 0x5, read_buffer); + /* pcgpd */ + hdmi_phy_down(false, 0x17, 0x0, read_buffer); + /* txpd */ + hdmi_phy_down(false, 0x17, 0x1, read_buffer); + } + + return 0; +} + +s32 hdmi_corereset(void) +{ + writeb(0x0, hdmi_base + S5P_HDMI_CTRL_CORE_RSTOUT); + + mdelay(10); + + writeb(0x1, hdmi_base + S5P_HDMI_CTRL_CORE_RSTOUT); + + return 0; +} + +s32 hdmi_phy_config(enum phy_freq freq, enum s5p_hdmi_color_depth cd) +{ + s32 index; + s32 size; + u8 buffer[32] = {0, }; + u8 reg; + + switch (cd) { + + case HDMI_CD_24: + index = 0; + break; + + case HDMI_CD_30: + index = 1; + break; + + case HDMI_CD_36: + index = 2; + break; + + default: + return false; + } + + /* i2c_hdmi init - set i2c filtering */ + buffer[0] = PHY_REG_MODE_SET_DONE; + buffer[1] = 0x00; + + if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 2, buffer) != 0) { + HDMIPRINTK("i2c_hdmi_phy_write failed.\n"); + return EINVAL; + } + + writeb(0x5, i2c_hdmi_phy_base + I2C_HDMI_LC); + + size = sizeof(phy_config[freq][index]) + / sizeof(phy_config[freq][index][0]); + + memcpy(buffer, phy_config[freq][index], sizeof(buffer)); + + if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, size, buffer) != 0) + return EINVAL; + + /* write offset */ + buffer[0] = 0x01; + + if (i2c_hdmi_phy_write(PHY_I2C_ADDRESS, 1, buffer) != 0) { + HDMIPRINTK("i2c_hdmi_phy_write failed.\n"); + return EINVAL; + } + +#ifdef S5P_HDMI_DEBUG + { + int i = 0; + u8 read_buffer[0x40] = {0, }; + + /* read data */ + if (i2c_hdmi_phy_read(PHY_I2C_ADDRESS, size, read_buffer) != 0) { + HDMIPRINTK("i2c_hdmi_phy_read failed.\n"); + return EINVAL; + } + + HDMIPRINTK("read buffer :\n\t\t"); + + for (i = 1; i < size; i++) { + + printk("0x%02x", read_buffer[i]); + + if (i % 8) + printk(" "); + else + printk("\n\t\t"); + } + printk("\n"); +} +#endif + hdmi_corereset(); + + do { + reg = readb(hdmi_base + HDMI_PHY_STATUS); + } while (!(reg & HDMI_PHY_READY)); + + writeb(I2C_CLK_PEND_INT, i2c_hdmi_phy_base + I2C_HDMI_CON); + /* disable */ + writeb(I2C_IDLE, i2c_hdmi_phy_base + I2C_HDMI_STAT); + + return 0; +} + +s32 hdmi_set_tg(enum s5p_hdmi_v_fmt mode) +{ + u16 temp_reg; + u8 tc_cmd; + + temp_reg = hdmi_tg_param[mode].h_fsz; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_H_FSZ_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_H_FSZ_H); + + /* set Horizontal Active Start Position */ + temp_reg = hdmi_tg_param[mode].hact_st ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_HACT_ST_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_HACT_ST_H); + + /* set Horizontal Active Size */ + temp_reg = hdmi_tg_param[mode].hact_sz ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_HACT_SZ_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_HACT_SZ_H); + + /* set Vertical Full Size */ + temp_reg = hdmi_tg_param[mode].v_fsz ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_V_FSZ_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_V_FSZ_H); + + /* set VSYNC Position */ + temp_reg = hdmi_tg_param[mode].vsync ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_VSYNC_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_VSYNC_H); + + /* set Bottom Field VSYNC Position */ + temp_reg = hdmi_tg_param[mode].vsync2; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_VSYNC2_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_VSYNC2_H); + + /* set Vertical Active Start Position */ + temp_reg = hdmi_tg_param[mode].vact_st ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_VACT_ST_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_VACT_ST_H); + + /* set Vertical Active Size */ + temp_reg = hdmi_tg_param[mode].vact_sz ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_VACT_SZ_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_VACT_SZ_H); + + /* set Field Change Position */ + temp_reg = hdmi_tg_param[mode].field_chg ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_FIELD_CHG_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_FIELD_CHG_H); + + /* set Bottom Field Vertical Active Start Position */ + temp_reg = hdmi_tg_param[mode].vact_st2; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_VACT_ST2_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_VACT_ST2_H); + + /* set VSYNC Position for HDMI */ + temp_reg = hdmi_tg_param[mode].vsync_top_hdmi; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_VSYNC_TOP_HDMI_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_VSYNC_TOP_HDMI_H); + + /* set Bottom Field VSYNC Position */ + temp_reg = hdmi_tg_param[mode].vsync_bot_hdmi; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_VSYNC_BOT_HDMI_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_VSYNC_BOT_HDMI_H); + + /* set Top Field Change Position for HDMI */ + temp_reg = hdmi_tg_param[mode].field_top_hdmi ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_FIELD_TOP_HDMI_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_FIELD_TOP_HDMI_H); + + /* set Bottom Field Change Position for HDMI */ + temp_reg = hdmi_tg_param[mode].field_bot_hdmi ; + writeb((u8)(temp_reg&0xff) , hdmi_base + S5P_TG_FIELD_BOT_HDMI_L); + writeb((u8)(temp_reg >> 8) , hdmi_base + S5P_TG_FIELD_BOT_HDMI_H); + + tc_cmd = readb(hdmi_base + S5P_TG_CMD); + + if (video_params[mode].interlaced == 1) + /* Field Mode enable(interlace mode) */ + tc_cmd |= (1<<1); + else + /* Field Mode disable */ + tc_cmd &= ~(1<<1); + + writeb(tc_cmd, hdmi_base + S5P_TG_CMD); + + return 0; +} + +/** + * Set registers related to color depth. + */ +static s32 hdmi_set_clr_depth(enum s5p_hdmi_color_depth cd) +{ + /* if color depth is supported by RX, set GCP packet */ + switch (cd) { + + case HDMI_CD_48: + writeb(GCP_CD_48BPP, hdmi_base + S5P_GCP_BYTE2); + break; + + case HDMI_CD_36: + writeb(GCP_CD_36BPP, hdmi_base + S5P_GCP_BYTE2); + /* set DC register */ + writeb(HDMI_DC_CTL_12, hdmi_base + S5P_HDMI_DC_CONTROL); + break; + + case HDMI_CD_30: + writeb(GCP_CD_30BPP, hdmi_base + S5P_GCP_BYTE2); + /* set DC register */ + writeb(HDMI_DC_CTL_10, hdmi_base + S5P_HDMI_DC_CONTROL); + break; + + case HDMI_CD_24: + writeb(GCP_CD_24BPP, hdmi_base + S5P_GCP_BYTE2); + /* set DC register */ + writeb(HDMI_DC_CTL_8, hdmi_base + S5P_HDMI_DC_CONTROL); + /* disable GCP */ + writeb(DO_NOT_TRANSMIT, hdmi_base + S5P_GCP_CON); + break; + + default: + HDMIPRINTK("HDMI core does not support \ + requested Deep Color mode\n"); + return -EINVAL; + } + + return 0; +} + +s32 hdmi_set_video_mode(enum s5p_hdmi_v_fmt mode, enum s5p_hdmi_color_depth cd, + enum s5p_tv_hdmi_pxl_aspect pxl_ratio, u8 *avidata) +{ + u8 temp_reg8; + u16 temp_reg16; + u32 temp_reg32, temp_sync2, temp_sync3; + + /* check if HDMI code support that mode */ + if (mode > (sizeof(video_params)/sizeof(struct hdmi_v_params)) || + (s32)mode < 0) { + HDMIPRINTK("This video mode is not Supported\n"); + return -EINVAL; + } + + hdmi_set_tg(mode); + + /* set HBlank */ + temp_reg16 = video_params[mode].h_blank; + writeb((u8)(temp_reg16&0xff), hdmi_base + S5P_H_BLANK_0); + writeb((u8)(temp_reg16 >> 8), hdmi_base + S5P_H_BLANK_1); + + /* set VBlank */ + temp_reg32 = video_params[mode].v_blank; + writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_V_BLANK_0); + writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_V_BLANK_1); + writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_V_BLANK_2); + + /* set HVLine */ + temp_reg32 = video_params[mode].hvline; + writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_H_V_LINE_0); + writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_H_V_LINE_1); + writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_H_V_LINE_2); + + /* set VSYNC polarity */ + writeb(video_params[mode].polarity, hdmi_base + S5P_SYNC_MODE); + + /* set HSyncGen */ + temp_reg32 = video_params[mode].h_sync_gen; + writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_H_SYNC_GEN_0); + writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_H_SYNC_GEN_1); + writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_H_SYNC_GEN_2); + + /* set VSyncGen1 */ + temp_reg32 = video_params[mode].v_sync_gen; + writeb((u8)(temp_reg32&0xff), hdmi_base + S5P_V_SYNC_GEN_1_0); + writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_V_SYNC_GEN_1_1); + writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_V_SYNC_GEN_1_2); + + if (video_params[mode].interlaced) { + /* set up v_blank_f, v_sync_gen2, v_sync_gen3 */ + temp_reg32 = video_params[mode].v_blank_f; + temp_sync2 = video_params[mode].v_sync_gen2; + temp_sync3 = video_params[mode].v_sync_gen3; + + writeb((u8)(temp_reg32 & 0xff), hdmi_base + S5P_V_BLANK_F_0); + writeb((u8)(temp_reg32 >> 8), hdmi_base + S5P_V_BLANK_F_1); + writeb((u8)(temp_reg32 >> 16), hdmi_base + S5P_V_BLANK_F_2); + + writeb((u8)(temp_sync2 & 0xff), + hdmi_base + S5P_V_SYNC_GEN_2_0); + writeb((u8)(temp_sync2 >> 8), hdmi_base + S5P_V_SYNC_GEN_2_1); + writeb((u8)(temp_sync2 >> 16), hdmi_base + S5P_V_SYNC_GEN_2_2); + + writeb((u8)(temp_sync3 & 0xff), + hdmi_base + S5P_V_SYNC_GEN_3_0); + writeb((u8)(temp_sync3 >> 8), hdmi_base + S5P_V_SYNC_GEN_3_1); + writeb((u8)(temp_sync3 >> 16), hdmi_base + S5P_V_SYNC_GEN_3_2); + } else { + /* progressive mode */ + writeb(0x00, hdmi_base + S5P_V_BLANK_F_0); + writeb(0x00, hdmi_base + S5P_V_BLANK_F_1); + writeb(0x00, hdmi_base + S5P_V_BLANK_F_2); + + writeb(0x01, hdmi_base + S5P_V_SYNC_GEN_2_0); + writeb(0x10, hdmi_base + S5P_V_SYNC_GEN_2_1); + writeb(0x00, hdmi_base + S5P_V_SYNC_GEN_2_2); + + writeb(0x01, hdmi_base + S5P_V_SYNC_GEN_3_0); + writeb(0x10, hdmi_base + S5P_V_SYNC_GEN_3_1); + writeb(0x00, hdmi_base + S5P_V_SYNC_GEN_3_2); + } + + /* set interlaced mode */ + writeb(video_params[mode].interlaced, hdmi_base + S5P_INT_PRO_MODE); + + /* pixel repetition */ + temp_reg8 = readb(hdmi_base + S5P_HDMI_CON_1); + + /* clear */ + temp_reg8 &= ~HDMI_CON_PXL_REP_RATIO_MASK; + + if (video_params[mode].repetition) { + /* set pixel repetition */ + temp_reg8 |= HDMI_DOUBLE_PIXEL_REPETITION; + /* AVI Packet */ + avidata[4] = AVI_PIXEL_REPETITION_DOUBLE; + } else { /* clear pixel repetition */ + /* AVI Packet */ + avidata[4] = 0; + } + + /* set pixel repetition */ + writeb(temp_reg8, hdmi_base + S5P_HDMI_CON_1); + + /* set AVI packet VIC */ + + if (pxl_ratio == HDMI_PIXEL_RATIO_16_9) + avidata[3] = video_params[mode].avi_vic_16_9; + else + avidata[3] = video_params[mode].avi_vic; + + /* clear */ + temp_reg8 = readb(hdmi_base + S5P_AVI_BYTE2) & + ~(AVI_PICTURE_ASPECT_4_3 | AVI_PICTURE_ASPECT_16_9); + + if (pxl_ratio == HDMI_PIXEL_RATIO_16_9) + temp_reg8 |= AVI_PICTURE_ASPECT_16_9; + else + temp_reg8 |= AVI_PICTURE_ASPECT_4_3; + + /* set color depth */ + if (hdmi_set_clr_depth(cd) != 0) { + HDMIPRINTK("[ERR] Can't set hdmi clr. depth.\n"); + return -EINVAL; + } + + if (video_params[mode].interlaced == 1) { + u32 gcp_con; + + gcp_con = readb(hdmi_base + S5P_GCP_CON); + gcp_con |= (3<<2); + + writeb(gcp_con, hdmi_base + S5P_GCP_CON); + } else { + u32 gcp_con; + + gcp_con = readb(hdmi_base + S5P_GCP_CON); + gcp_con &= (~(3<<2)); + + writeb(gcp_con, hdmi_base + S5P_GCP_CON); + } + +#if 0 + /* config Phy */ + if (hdmi_phy_config(video_params[mode].pixel_clock, cd) == EINVAL) { + HDMIPRINTK("[ERR] hdmi_phy_config() failed.\n"); + return EINVAL; + } +#endif + return 0; +} + +void __s5p_hdmi_set_hpd_onoff(bool on_off) +{ + HDMIPRINTK("hpd is %s\n\r", on_off ? "on" : "off"); + + if (on_off) + writel(SW_HPD_PLUGGED, hdmi_base + S5P_HPD); + else + writel(SW_HPD_UNPLUGGED, hdmi_base + S5P_HPD); + + + HDMIPRINTK("0x%08x\n\r", readl(hdmi_base + S5P_HPD)); +} + +void __s5p_hdmi_audio_set_config(enum s5p_tv_audio_codec_type audio_codec) +{ + + u32 data_type = (audio_codec == PCM) ? CONFIG_LINEAR_PCM_TYPE : + (audio_codec == AC3) ? CONFIG_NON_LINEAR_PCM_TYPE : + 0xff; + + HDMIPRINTK("audio codec type = %s\n\r", + (audio_codec&PCM) ? "PCM" : + (audio_codec&AC3) ? "AC3" : + (audio_codec&MP3) ? "MP3" : + (audio_codec&WMA) ? "WMA" : "Unknown"); + + /* open SPDIF path on HDMI_I2S */ + writel(0x01, hdmi_base + S5P_HDMI_I2S_CLK_CON); + writel(readl(hdmi_base + S5P_HDMI_I2S_MUX_CON) | 0x11, + hdmi_base + S5P_HDMI_I2S_MUX_CON); + writel(0xFF, hdmi_base + S5P_HDMI_I2S_MUX_CH); + writel(0x03, hdmi_base + S5P_HDMI_I2S_MUX_CUV); + + writel(CONFIG_FILTER_2_SAMPLE | data_type + | CONFIG_PCPD_MANUAL_SET | CONFIG_WORD_LENGTH_MANUAL_SET + | CONFIG_U_V_C_P_REPORT | CONFIG_BURST_SIZE_2 + | CONFIG_DATA_ALIGN_32BIT + , hdmi_base + S5P_SPDIFIN_CONFIG_1); + writel(0, hdmi_base + S5P_SPDIFIN_CONFIG_2); +} + +void __s5p_hdmi_audio_set_acr(u32 sample_rate) +{ + u32 value_n = (sample_rate == 32000) ? 4096 : + (sample_rate == 44100) ? 6272 : + (sample_rate == 88200) ? 12544 : + (sample_rate == 176400) ? 25088 : + (sample_rate == 48000) ? 6144 : + (sample_rate == 96000) ? 12288 : + (sample_rate == 192000) ? 24576 : 0; + + u32 cts = (sample_rate == 32000) ? 27000 : + (sample_rate == 44100) ? 30000 : + (sample_rate == 88200) ? 30000 : + (sample_rate == 176400) ? 30000 : + (sample_rate == 48000) ? 27000 : + (sample_rate == 96000) ? 27000 : + (sample_rate == 192000) ? 27000 : 0; + + HDMIPRINTK("sample rate = %d\n\r", sample_rate); + HDMIPRINTK("cts = %d\n\r", cts); + + writel(value_n & 0xff, hdmi_base + S5P_ACR_N0); + writel((value_n >> 8) & 0xff, hdmi_base + S5P_ACR_N1); + writel((value_n >> 16) & 0xff, hdmi_base + S5P_ACR_N2); + + writel(cts & 0xff, hdmi_base + S5P_ACR_MCTS0); + writel((cts >> 8) & 0xff, hdmi_base + S5P_ACR_MCTS1); + writel((cts >> 16) & 0xff, hdmi_base + S5P_ACR_MCTS2); + + writel(cts & 0xff, hdmi_base + S5P_ACR_CTS0); + writel((cts >> 8) & 0xff, hdmi_base + S5P_ACR_CTS1); + writel((cts >> 16) & 0xff, hdmi_base + S5P_ACR_CTS2); + + writel(4, hdmi_base + S5P_ACR_CON); +} + +void __s5p_hdmi_audio_set_asp(void) +{ + writel(0x0, hdmi_base + S5P_ASP_CON); + /* All Subpackets contain audio samples */ + writel(0x0, hdmi_base + S5P_ASP_SP_FLAT); + + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG0); + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG1); + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG2); + writel(1 << 3 | 0, hdmi_base + S5P_ASP_CHCFG3); +} + +void __s5p_hdmi_audio_clock_enable(void) +{ + writel(0x1, hdmi_base + S5P_SPDIFIN_CLK_CTRL); + /* HDMI operation mode */ + writel(0x3, hdmi_base + S5P_SPDIFIN_OP_CTRL); +} + + +void __s5p_hdmi_audio_set_repetition_time( + enum s5p_tv_audio_codec_type audio_codec, + u32 bits, u32 frame_size_code) +{ + /* Only 4'b1011 24bit */ + u32 wl = 5 << 1 | 1; + u32 rpt_cnt = (audio_codec == AC3) ? 1536 * 2 - 1 : 0; + + HDMIPRINTK("repetition count = %d\n\r", rpt_cnt); + + /* 24bit and manual mode */ + writel(((rpt_cnt&0xf) << 4) | wl, + hdmi_base + S5P_SPDIFIN_USER_VALUE_1); + /* if PCM this value is 0 */ + writel((rpt_cnt >> 4)&0xff, + hdmi_base + S5P_SPDIFIN_USER_VALUE_2); + /* if PCM this value is 0 */ + writel(frame_size_code&0xff, + hdmi_base + S5P_SPDIFIN_USER_VALUE_3); + /* if PCM this value is 0 */ + writel((frame_size_code >> 8)&0xff, + hdmi_base + S5P_SPDIFIN_USER_VALUE_4); +} + +void __s5p_hdmi_audio_irq_enable(u32 irq_en) +{ + writel(irq_en, hdmi_base + S5P_SPDIFIN_IRQ_MASK); +} + + +void __s5p_hdmi_audio_set_aui(enum s5p_tv_audio_codec_type audio_codec, + u32 sample_rate, + u32 bits) +{ + u8 sum_of_bits, bytes1, bytes2, bytes3, check_sum; +#if 1 + /* Fix TestID 7-31 Audio InfoFrame issue*/ + u32 bit_rate; + u32 type = 0; + u32 ch = (audio_codec == PCM) ? 1 : 0; + u32 sample = 0; + u32 bpsType = 0; +#else + /* Ac3 16bit only */ + u32 bps = (audio_codec == PCM) ? bits : 16; + + /* AUI Packet set. */ + u32 type = (audio_codec == PCM) ? 1 : /* PCM */ + (audio_codec == AC3) ? 2 : 0; + /* AC3 or Refer stream header */ + u32 ch = (audio_codec == PCM) ? 1 : 0; + /* 2ch or refer to stream header */ + + u32 sample = (sample_rate == 32000) ? 1 : + (sample_rate == 44100) ? 2 : + (sample_rate == 48000) ? 3 : + (sample_rate == 88200) ? 4 : + (sample_rate == 96000) ? 5 : + (sample_rate == 176400) ? 6 : + (sample_rate == 192000) ? 7 : 0; + + u32 bpsType = (bps == 16) ? 1 : + (bps == 20) ? 2 : + (bps == 24) ? 3 : 0; +#endif + + bpsType = (audio_codec == PCM) ? bpsType : 0; + + sum_of_bits = (0x84 + 0x1 + 10); + + bytes1 = (u8)((type << 4) | ch); + + bytes2 = (u8)((sample << 2) | bpsType); + + bit_rate = 256; + + bytes3 = (audio_codec == PCM) ? (u8)0 : (u8)(bit_rate / 8) ; + + + sum_of_bits += (bytes1 + bytes2 + bytes3); + check_sum = 256 - sum_of_bits; + + /* AUI Packet set. */ + writel(check_sum , hdmi_base + S5P_AUI_CHECK_SUM); + writel(bytes1 , hdmi_base + S5P_AUI_BYTE1); + writel(bytes2 , hdmi_base + S5P_AUI_BYTE2); + writel(bytes3 , hdmi_base + S5P_AUI_BYTE3);/* Pcm or stream */ + writel(0x00 , hdmi_base + S5P_AUI_BYTE4); /* 2ch pcm or Stream */ + writel(0x00 , hdmi_base + S5P_AUI_BYTE5); /* 2ch pcm or Stream */ + + writel(HDMI_DO_NOT_TANS, hdmi_base + S5P_ACP_CON); + writel(1 , hdmi_base + S5P_ACP_TYPE); + + writel(0x10 , hdmi_base + S5P_GCP_BYTE1); + /* + * packet will be transmitted within 384 cycles + * after active sync. + */ +} + +void __s5p_hdmi_video_set_bluescreen(bool en, + u8 cb_b, + u8 y_g, + u8 cr_r) +{ + HDMIPRINTK("%d, %d, %d, %d\n\r", en, cb_b, y_g, cr_r); + + if (en) { + writel(SET_BLUESCREEN_0(cb_b), hdmi_base + S5P_BLUE_SCREEN_0); + writel(SET_BLUESCREEN_1(y_g), hdmi_base + S5P_BLUE_SCREEN_1); + writel(SET_BLUESCREEN_2(cr_r), hdmi_base + S5P_BLUE_SCREEN_2); + writel(readl(hdmi_base + S5P_HDMI_CON_0) | BLUE_SCR_EN, + hdmi_base + S5P_HDMI_CON_0); + + HDMIPRINTK("HDMI_BLUE_SCREEN0 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_0)); + HDMIPRINTK("HDMI_BLUE_SCREEN1 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_1)); + HDMIPRINTK("HDMI_BLUE_SCREEN2 = 0x%08x \n\r", + readl(hdmi_base + S5P_BLUE_SCREEN_2)); + } else + writel(readl(hdmi_base + S5P_HDMI_CON_0)&~BLUE_SCR_EN, + hdmi_base + S5P_HDMI_CON_0); + + HDMIPRINTK("HDMI_CON0 = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CON_0)); +} + +enum s5p_tv_hdmi_err __s5p_hdmi_init_spd_infoframe( + enum s5p_hdmi_transmit trans_type, + u8 *spd_header, + u8 *spd_data) +{ + HDMIPRINTK("%d, %d, %d\n\r", (u32)trans_type, + (u32)spd_header, + (u32)spd_data); + + switch (trans_type) { + + case HDMI_DO_NOT_TANS: + writel(SPD_TX_CON_NO_TRANS, hdmi_base + S5P_SPD_CON); + break; + + case HDMI_TRANS_ONCE: + writel(SPD_TX_CON_TRANS_ONCE, hdmi_base + S5P_SPD_CON); + break; + + case HDMI_TRANS_EVERY_SYNC: + writel(SPD_TX_CON_TRANS_EVERY_VSYNC, hdmi_base + S5P_SPD_CON); + break; + + default: + HDMIPRINTK(" invalid out_mode parameter(%d)\n\r", trans_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + /* + * spd_data, spd_header be specified by Vendor's specific + * data. below codes is sample usage + */ + + if (spd_data == NULL || spd_header == NULL) { + HDMIPRINTK("Set default SPD\n"); + writel(SET_SPD_HEADER(0x83), hdmi_base + S5P_SPD_HEADER0); + writel(SET_SPD_HEADER(0x01), hdmi_base + S5P_SPD_HEADER1); + writel(SET_SPD_HEADER(0x19), hdmi_base + S5P_SPD_HEADER2); + + writel(0x0, hdmi_base + S5P_SPD_DATA0); + writel(SET_SPD_DATA('S'), hdmi_base + S5P_SPD_DATA1); + writel(SET_SPD_DATA('A'), hdmi_base + S5P_SPD_DATA2); + writel(SET_SPD_DATA('M'), hdmi_base + S5P_SPD_DATA3); + writel(SET_SPD_DATA('S'), hdmi_base + S5P_SPD_DATA4); + writel(SET_SPD_DATA('U'), hdmi_base + S5P_SPD_DATA5); + writel(SET_SPD_DATA('N'), hdmi_base + S5P_SPD_DATA6); + writel(SET_SPD_DATA('G'), hdmi_base + S5P_SPD_DATA7); + + writel(0x0, hdmi_base + S5P_SPD_DATA8); + writel(SET_SPD_DATA('S'), hdmi_base + S5P_SPD_DATA9); + writel(SET_SPD_DATA('5'), hdmi_base + S5P_SPD_DATA10); + writel(SET_SPD_DATA('P'), hdmi_base + S5P_SPD_DATA11); + writel(SET_SPD_DATA('C'), hdmi_base + S5P_SPD_DATA12); + writel(SET_SPD_DATA('1'), hdmi_base + S5P_SPD_DATA13); + writel(SET_SPD_DATA('1'), hdmi_base + S5P_SPD_DATA14); + writel(SET_SPD_DATA('0'), hdmi_base + S5P_SPD_DATA15); + writel(0x0, hdmi_base + S5P_SPD_DATA16); + writel(0x0, hdmi_base + S5P_SPD_DATA17); + writel(0x0, hdmi_base + S5P_SPD_DATA18); + writel(0x0, hdmi_base + S5P_SPD_DATA19); + writel(0x0, hdmi_base + S5P_SPD_DATA20); + writel(0x0, hdmi_base + S5P_SPD_DATA21); + writel(0x0, hdmi_base + S5P_SPD_DATA22); + writel(0x0, hdmi_base + S5P_SPD_DATA23); + writel(0x0, hdmi_base + S5P_SPD_DATA24); + writel(0x0, hdmi_base + S5P_SPD_DATA25); + writel(SET_SPD_DATA(0x2), hdmi_base + S5P_SPD_DATA26); + writel(0x0, hdmi_base + S5P_SPD_DATA27); + } else { + + writel(SET_SPD_HEADER(*(spd_header)), + hdmi_base + S5P_SPD_HEADER0); + + writel(SET_SPD_HEADER(*(spd_header + 1)) , + hdmi_base + S5P_SPD_HEADER1); + writel(SET_SPD_HEADER(*(spd_header + 2)) , + hdmi_base + S5P_SPD_HEADER2); + + writel(SET_SPD_DATA(*(spd_data)) , + hdmi_base + S5P_SPD_DATA0); + writel(SET_SPD_DATA(*(spd_data + 1)) , + hdmi_base + S5P_SPD_DATA1); + writel(SET_SPD_DATA(*(spd_data + 2)) , + hdmi_base + S5P_SPD_DATA2); + writel(SET_SPD_DATA(*(spd_data + 3)) , + hdmi_base + S5P_SPD_DATA3); + writel(SET_SPD_DATA(*(spd_data + 4)) , + hdmi_base + S5P_SPD_DATA4); + writel(SET_SPD_DATA(*(spd_data + 5)) , + hdmi_base + S5P_SPD_DATA5); + writel(SET_SPD_DATA(*(spd_data + 6)) , + hdmi_base + S5P_SPD_DATA6); + writel(SET_SPD_DATA(*(spd_data + 7)) , + hdmi_base + S5P_SPD_DATA7); + writel(SET_SPD_DATA(*(spd_data + 8)) , + hdmi_base + S5P_SPD_DATA8); + writel(SET_SPD_DATA(*(spd_data + 9)) , + hdmi_base + S5P_SPD_DATA9); + writel(SET_SPD_DATA(*(spd_data + 10)) , + hdmi_base + S5P_SPD_DATA10); + writel(SET_SPD_DATA(*(spd_data + 11)) , + hdmi_base + S5P_SPD_DATA11); + writel(SET_SPD_DATA(*(spd_data + 12)) , + hdmi_base + S5P_SPD_DATA12); + writel(SET_SPD_DATA(*(spd_data + 13)) , + hdmi_base + S5P_SPD_DATA13); + writel(SET_SPD_DATA(*(spd_data + 14)) , + hdmi_base + S5P_SPD_DATA14); + writel(SET_SPD_DATA(*(spd_data + 15)) , + hdmi_base + S5P_SPD_DATA15); + writel(SET_SPD_DATA(*(spd_data + 16)) , + hdmi_base + S5P_SPD_DATA16); + writel(SET_SPD_DATA(*(spd_data + 17)) , + hdmi_base + S5P_SPD_DATA17); + writel(SET_SPD_DATA(*(spd_data + 18)) , + hdmi_base + S5P_SPD_DATA18); + writel(SET_SPD_DATA(*(spd_data + 19)) , + hdmi_base + S5P_SPD_DATA19); + writel(SET_SPD_DATA(*(spd_data + 20)) , + hdmi_base + S5P_SPD_DATA20); + writel(SET_SPD_DATA(*(spd_data + 21)) , + hdmi_base + S5P_SPD_DATA21); + writel(SET_SPD_DATA(*(spd_data + 22)) , + hdmi_base + S5P_SPD_DATA22); + writel(SET_SPD_DATA(*(spd_data + 23)) , + hdmi_base + S5P_SPD_DATA23); + writel(SET_SPD_DATA(*(spd_data + 24)) , + hdmi_base + S5P_SPD_DATA24); + writel(SET_SPD_DATA(*(spd_data + 25)) , + hdmi_base + S5P_SPD_DATA25); + writel(SET_SPD_DATA(*(spd_data + 26)) , + hdmi_base + S5P_SPD_DATA26); + writel(SET_SPD_DATA(*(spd_data + 27)) , + hdmi_base + S5P_SPD_DATA27); + } + + HDMIPRINTK("SPD_CON = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_CON)); + HDMIPRINTK("SPD_HEADER0 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_HEADER0)); + HDMIPRINTK("SPD_HEADER1 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_HEADER1)); + HDMIPRINTK("SPD_HEADER2 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_HEADER2)); + HDMIPRINTK("SPD_DATA0 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA0)); + HDMIPRINTK("SPD_DATA1 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA1)); + HDMIPRINTK("SPD_DATA2 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA2)); + HDMIPRINTK("SPD_DATA3 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA3)); + HDMIPRINTK("SPD_DATA4 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA4)); + HDMIPRINTK("SPD_DATA5 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA5)); + HDMIPRINTK("SPD_DATA6 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA6)); + HDMIPRINTK("SPD_DATA7 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA7)); + HDMIPRINTK("SPD_DATA8 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA8)); + HDMIPRINTK("SPD_DATA9 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA9)); + HDMIPRINTK("SPD_DATA10 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA10)); + HDMIPRINTK("SPD_DATA11 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA11)); + HDMIPRINTK("SPD_DATA12 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA12)); + HDMIPRINTK("SPD_DATA13 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA13)); + HDMIPRINTK("SPD_DATA14 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA14)); + HDMIPRINTK("SPD_DATA15 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA15)); + HDMIPRINTK("SPD_DATA16 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA16)); + HDMIPRINTK("SPD_DATA17 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA17)); + HDMIPRINTK("SPD_DATA18 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA18)); + HDMIPRINTK("SPD_DATA19 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA19)); + HDMIPRINTK("SPD_DATA20 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA20)); + HDMIPRINTK("SPD_DATA21 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA21)); + HDMIPRINTK("SPD_DATA22 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA22)); + HDMIPRINTK("SPD_DATA23 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA23)); + HDMIPRINTK("SPD_DATA24 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA24)); + HDMIPRINTK("SPD_DATA25 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA25)); + HDMIPRINTK("SPD_DATA26 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA26)); + HDMIPRINTK("SPD_DATA27 = 0x%08x \n\r", + readl(hdmi_base + S5P_SPD_DATA27)); + + return HDMI_NO_ERROR; +} + +void __s5p_hdmi_init_hpd_onoff(bool on_off) +{ + HDMIPRINTK("%d\n\r", on_off); + __s5p_hdmi_set_hpd_onoff(on_off); + HDMIPRINTK("0x%08x\n\r", readl(hdmi_base + S5P_HPD)); +} + +#ifndef CONFIG_SND_S5P_SPDIF +static void __s5p_hdmi_audio_i2s_config( + enum s5p_tv_audio_codec_type audio_codec, + u32 sample_rate, + u32 bits_per_sample, + u32 frame_size_code) +{ + u32 data_num, bit_ch, sample_frq; + + if (bits_per_sample == 20) { + data_num = 2; + bit_ch = 1; + } else if (bits_per_sample == 24) { + data_num = 3; + bit_ch = 1; + } else { + data_num = 1; + bit_ch = 0; + } + sample_frq = (sample_rate == 44100) ? 0 : + (sample_rate == 48000) ? 2 : + (sample_rate == 32000) ? 3 : + (sample_rate == 96000) ? 0xa : 0x0; + + /* readl(hdmi_base + S5P_HDMI_YMAX) */ + writel(0x00, hdmi_base + S5P_HDMI_I2S_CLK_CON); + writel(0x01, hdmi_base + S5P_HDMI_I2S_CLK_CON); + + writel(readl(hdmi_base + S5P_HDMI_I2S_DSD_CON) | 0x01, + hdmi_base + S5P_HDMI_I2S_DSD_CON); + + /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */ + writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_0) & + ~(7<<4 | 7<<0)) | (5<<4|6<<0), + hdmi_base + S5P_HDMI_I2S_PIN_SEL_0); + writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_1) & + ~(7<<4 | 7<<0)) | (1<<4|4<<0), + hdmi_base + S5P_HDMI_I2S_PIN_SEL_1); + writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_2) & + ~(7<<4 | 7<<0)) | (1<<4|2<<0), + hdmi_base + S5P_HDMI_I2S_PIN_SEL_2); + writel((readl(hdmi_base + S5P_HDMI_I2S_PIN_SEL_3) & + ~(7<<0)) | (0<<0), + hdmi_base + S5P_HDMI_I2S_PIN_SEL_3); + + /* I2S_CON_1 & 2 */ + writel((readl(hdmi_base + S5P_HDMI_I2S_CON_1) & + ~(1<<1 | 1<<0)) | (1<<1|0<<0), + hdmi_base + S5P_HDMI_I2S_CON_1); + writel((readl(hdmi_base + S5P_HDMI_I2S_CON_2) & + ~(1<<6 | 3<<4 | 3<<2 | 3<<0)) + | (0<<6 | bit_ch<<4 | data_num<<2 | 0<<0), + hdmi_base + S5P_HDMI_I2S_CON_2); + + /* Configure register related to CUV information */ + writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_0) & + ~(3<<6 | 7<<3 | 1<<2 | 1<<1 | 1<<0)) + | (0<<6 | 0<<3 | 0<<2 | 0<<1 | 1<<0), + hdmi_base + S5P_HDMI_I2S_CH_ST_0); + writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_1) & + ~(0xff<<0)) | (0<<0), + hdmi_base + S5P_HDMI_I2S_CH_ST_1); + writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_2) & + ~(0xff<<0)) | (0<<0), + hdmi_base + S5P_HDMI_I2S_CH_ST_2); + writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_3) & + ~(3<<4 | 0xf<<0)) + | (0<<4 | sample_frq<<0), + hdmi_base + S5P_HDMI_I2S_CH_ST_3); + writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_4) & + ~(0xf<<4 | 7<<1 | 1<<0)) + | (0xf<<4 | 5<<1 | 1<<0), + hdmi_base + S5P_HDMI_I2S_CH_ST_4); + + writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_0); + writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_1); + writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_2); + writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_3); + writel(0x00, hdmi_base + S5P_HDMI_I2S_CH_ST_SH_4); + + writel((readl(hdmi_base + S5P_HDMI_I2S_CH_ST_CON) & + ~(1<<0)) | (1<<0), + hdmi_base + S5P_HDMI_I2S_CH_ST_CON); + + writel((readl(hdmi_base + S5P_HDMI_I2S_MUX_CON) & + ~(1<<4 | 3<<2 | 1<<1 | 1<<0)) + | (1<<4 | 1<<2 | 1<<1 | 1<<0), + hdmi_base + S5P_HDMI_I2S_MUX_CON); + + writel((readl(hdmi_base + S5P_HDMI_I2S_MUX_CH) & + ~(0xff<<0)) | (0x3f<<0), + hdmi_base + S5P_HDMI_I2S_MUX_CH); + + writel((readl(hdmi_base + S5P_HDMI_I2S_MUX_CUV) & + ~(0x3<<0)) | (0x3<<0), + hdmi_base + S5P_HDMI_I2S_MUX_CUV); +} +#endif + +enum s5p_tv_hdmi_err __s5p_hdmi_audio_init( + enum s5p_tv_audio_codec_type audio_codec, + u32 sample_rate, u32 bits, u32 frame_size_code) +{ +#ifdef CONFIG_SND_S5P_SPDIF + __s5p_hdmi_audio_set_config(audio_codec); + __s5p_hdmi_audio_set_repetition_time(audio_codec, bits, + frame_size_code); + __s5p_hdmi_audio_irq_enable(IRQ_BUFFER_OVERFLOW_ENABLE); + __s5p_hdmi_audio_clock_enable(); +#else + __s5p_hdmi_audio_i2s_config(audio_codec, sample_rate, bits, + frame_size_code); +#endif + __s5p_hdmi_audio_set_asp(); + __s5p_hdmi_audio_set_acr(sample_rate); + + __s5p_hdmi_audio_set_aui(audio_codec, sample_rate, bits); + + return HDMI_NO_ERROR; +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_display_mode( + enum s5p_tv_disp_mode disp_mode, + enum s5p_tv_o_mode out_mode, u8 *avidata) +{ + enum s5p_hdmi_v_fmt hdmi_v_fmt; + enum s5p_tv_hdmi_pxl_aspect aspect; + + HDMIPRINTK("disp mode %d, output mode%d\n\r", disp_mode, out_mode); + + aspect = HDMI_PIXEL_RATIO_16_9; + + switch (disp_mode) { + /* 480p */ + case TVOUT_480P_60_16_9: + hdmi_v_fmt = v720x480p_60Hz; + break; + + case TVOUT_480P_60_4_3: + hdmi_v_fmt = v720x480p_60Hz; + aspect = HDMI_PIXEL_RATIO_4_3; + break; + + case TVOUT_480P_59: + hdmi_v_fmt = v720x480p_59Hz; + break; + + /* 576p */ + case TVOUT_576P_50_16_9: + hdmi_v_fmt = v720x576p_50Hz; + break; + + case TVOUT_576P_50_4_3: + hdmi_v_fmt = v720x576p_50Hz; + aspect = HDMI_PIXEL_RATIO_4_3; + break; + + /* 720p */ + case TVOUT_720P_60: + hdmi_v_fmt = v1280x720p_60Hz; + break; + + case TVOUT_720P_59: + hdmi_v_fmt = v1280x720p_59Hz; + break; + + case TVOUT_720P_50: + hdmi_v_fmt = v1280x720p_50Hz; + break; + + /* 1080p */ + case TVOUT_1080P_30: + hdmi_v_fmt = v1920x1080p_30Hz; + break; + + case TVOUT_1080P_60: + hdmi_v_fmt = v1920x1080p_60Hz; + break; + + case TVOUT_1080P_59: + hdmi_v_fmt = v1920x1080p_59Hz; + break; + + case TVOUT_1080P_50: + hdmi_v_fmt = v1920x1080p_50Hz; + break; + + /* 1080i */ + case TVOUT_1080I_60: + hdmi_v_fmt = v1920x1080i_60Hz; + break; + + case TVOUT_1080I_59: + hdmi_v_fmt = v1920x1080i_59Hz; + break; + + case TVOUT_1080I_50: + hdmi_v_fmt = v1920x1080i_50Hz; + break; + + default: + HDMIPRINTK(" invalid disp_mode parameter(%d)\n\r", disp_mode); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + if (hdmi_phy_config(video_params[hdmi_v_fmt].pixel_clock, HDMI_CD_24) + == EINVAL) { + HDMIPRINTK("[ERR] hdmi_phy_config() failed.\n"); + return EINVAL; + } + + switch (out_mode) { + case TVOUT_OUTPUT_HDMI_RGB: + s5p_hdmi_set_dvi(false); + writel(PX_LMT_CTRL_RGB, hdmi_base + S5P_HDMI_CON_1); + writel(VID_PREAMBLE_EN | GUARD_BAND_EN, + hdmi_base + S5P_HDMI_CON_2); + writel(HDMI_MODE_EN | DVI_MODE_DIS, + hdmi_base + S5P_MODE_SEL); + + /* there's no ACP packet api */ + writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_ACP_CON); + writel(HDMI_TRANS_EVERY_SYNC , hdmi_base + S5P_AUI_CON); + break; + + case TVOUT_OUTPUT_HDMI: + s5p_hdmi_set_dvi(false); + writel(PX_LMT_CTRL_BYPASS, hdmi_base + S5P_HDMI_CON_1); + writel(VID_PREAMBLE_EN | GUARD_BAND_EN, + hdmi_base + S5P_HDMI_CON_2); + writel(HDMI_MODE_EN | DVI_MODE_DIS, + hdmi_base + S5P_MODE_SEL); + + /* there's no ACP packet api */ + writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_ACP_CON); + writel(HDMI_TRANS_EVERY_SYNC , hdmi_base + S5P_AUI_CON); + break; + + + case TVOUT_OUTPUT_DVI: + s5p_hdmi_set_dvi(true); + writel(PX_LMT_CTRL_RGB, hdmi_base + S5P_HDMI_CON_1); + writel(VID_PREAMBLE_DIS | GUARD_BAND_DIS, + hdmi_base + S5P_HDMI_CON_2); + writel(HDMI_MODE_DIS | DVI_MODE_EN, + hdmi_base + S5P_MODE_SEL); + + /* disable ACP & Audio Info.frame packet */ + writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_ACP_CON); + writel(HDMI_DO_NOT_TANS , hdmi_base + S5P_AUI_CON); + break; + + default: + HDMIPRINTK("invalid out_mode parameter(%d)\n\r", out_mode); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + hdmi_set_video_mode(hdmi_v_fmt, HDMI_CD_24, aspect, avidata); + + return HDMI_NO_ERROR; +} + +void __s5p_hdmi_video_init_bluescreen(bool en, + u8 cb_b, + u8 y_g, + u8 cr_r) +{ + __s5p_hdmi_video_set_bluescreen(en, cb_b, y_g, cr_r); + +} + +void __s5p_hdmi_video_init_color_range(u8 y_min, + u8 y_max, + u8 c_min, + u8 c_max) +{ + HDMIPRINTK("%d, %d, %d, %d\n\r", y_max, y_min, c_max, c_min); + + writel(y_max, hdmi_base + S5P_HDMI_YMAX); + writel(y_min, hdmi_base + S5P_HDMI_YMIN); + writel(c_max, hdmi_base + S5P_HDMI_CMAX); + writel(c_min, hdmi_base + S5P_HDMI_CMIN); + + HDMIPRINTK("HDMI_YMAX = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_YMAX)); + HDMIPRINTK("HDMI_YMIN = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_YMIN)); + HDMIPRINTK("HDMI_CMAX = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CMAX)); + HDMIPRINTK("HDMI_CMIN = 0x%08x \n\r", + readl(hdmi_base + S5P_HDMI_CMIN)); +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_csc( + enum s5p_tv_hdmi_csc_type csc_type) +{ + unsigned short us_csc_coeff[10]; + + HDMIPRINTK("%d)\n\r", csc_type); + + switch (csc_type) { + + case HDMI_CSC_YUV601_TO_RGB_LR: + us_csc_coeff[0] = 0x23; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 938; + us_csc_coeff[3] = 846; + us_csc_coeff[4] = 256; + us_csc_coeff[5] = 443; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 256; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 350; + break; + + case HDMI_CSC_YUV601_TO_RGB_FR: + us_csc_coeff[0] = 0x03; + us_csc_coeff[1] = 298; + us_csc_coeff[2] = 924; + us_csc_coeff[3] = 816; + us_csc_coeff[4] = 298; + us_csc_coeff[5] = 516; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 298; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 408; + break; + + case HDMI_CSC_YUV709_TO_RGB_LR: + us_csc_coeff[0] = 0x23; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 978; + us_csc_coeff[3] = 907; + us_csc_coeff[4] = 256; + us_csc_coeff[5] = 464; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 256; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 394; + break; + + case HDMI_CSC_YUV709_TO_RGB_FR: + us_csc_coeff[0] = 0x03; + us_csc_coeff[1] = 298; + us_csc_coeff[2] = 970; + us_csc_coeff[3] = 888; + us_csc_coeff[4] = 298; + us_csc_coeff[5] = 540; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 298; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 458; + break; + + case HDMI_CSC_YUV601_TO_YUV709: + us_csc_coeff[0] = 0x33; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 995; + us_csc_coeff[3] = 971; + us_csc_coeff[4] = 0; + us_csc_coeff[5] = 260; + us_csc_coeff[6] = 29; + us_csc_coeff[7] = 0; + us_csc_coeff[8] = 19; + us_csc_coeff[9] = 262; + break; + + case HDMI_CSC_RGB_FR_TO_RGB_LR: + us_csc_coeff[0] = 0x20; + us_csc_coeff[1] = 220; + us_csc_coeff[2] = 0; + us_csc_coeff[3] = 0; + us_csc_coeff[4] = 0; + us_csc_coeff[5] = 220; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 0; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 220; + break; + + case HDMI_CSC_RGB_FR_TO_YUV601: + us_csc_coeff[0] = 0x30; + us_csc_coeff[1] = 129; + us_csc_coeff[2] = 25; + us_csc_coeff[3] = 65; + us_csc_coeff[4] = 950; + us_csc_coeff[5] = 112; + us_csc_coeff[6] = 986; + us_csc_coeff[7] = 930; + us_csc_coeff[8] = 1006; + us_csc_coeff[9] = 112; + break; + + case HDMI_CSC_RGB_FR_TO_YUV709: + us_csc_coeff[0] = 0x30; + us_csc_coeff[1] = 157; + us_csc_coeff[2] = 16; + us_csc_coeff[3] = 47; + us_csc_coeff[4] = 937; + us_csc_coeff[5] = 112; + us_csc_coeff[6] = 999; + us_csc_coeff[7] = 922; + us_csc_coeff[8] = 1014; + us_csc_coeff[9] = 112; + break; + + case HDMI_BYPASS: + us_csc_coeff[0] = 0x33; + us_csc_coeff[1] = 256; + us_csc_coeff[2] = 0; + us_csc_coeff[3] = 0; + us_csc_coeff[4] = 0; + us_csc_coeff[5] = 256; + us_csc_coeff[6] = 0; + us_csc_coeff[7] = 0; + us_csc_coeff[8] = 0; + us_csc_coeff[9] = 256; + break; + + default: + HDMIPRINTK("invalid out_mode parameter(%d)\n\r", csc_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + return HDMI_NO_ERROR; +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_avi_infoframe( + enum s5p_hdmi_transmit trans_type, u8 check_sum, u8 *avi_data) +{ + HDMIPRINTK("%d, %d, %d\n\r", (u32)trans_type, (u32)check_sum, + (u32)avi_data); + + switch (trans_type) { + + case HDMI_DO_NOT_TANS: + writel(AVI_TX_CON_NO_TRANS, hdmi_base + S5P_AVI_CON); + break; + + case HDMI_TRANS_ONCE: + writel(AVI_TX_CON_TRANS_ONCE, hdmi_base + S5P_AVI_CON); + break; + + case HDMI_TRANS_EVERY_SYNC: + writel(AVI_TX_CON_TRANS_EVERY_VSYNC, hdmi_base + S5P_AVI_CON); + break; + + default: + HDMIPRINTK(" invalid out_mode parameter(%d)\n\r", trans_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + writel(SET_AVI_CHECK_SUM(check_sum), hdmi_base + S5P_AVI_CHECK_SUM); + + writel(SET_AVI_BYTE(*(avi_data)), hdmi_base + S5P_AVI_BYTE1); + writel(SET_AVI_BYTE(*(avi_data + 1)), hdmi_base + S5P_AVI_BYTE2); + writel(SET_AVI_BYTE(*(avi_data + 2)), hdmi_base + S5P_AVI_BYTE3); + writel(SET_AVI_BYTE(*(avi_data + 3)), hdmi_base + S5P_AVI_BYTE4); + writel(SET_AVI_BYTE(*(avi_data + 4)), hdmi_base + S5P_AVI_BYTE5); + writel(SET_AVI_BYTE(*(avi_data + 5)), hdmi_base + S5P_AVI_BYTE6); + writel(SET_AVI_BYTE(*(avi_data + 6)), hdmi_base + S5P_AVI_BYTE7); + writel(SET_AVI_BYTE(*(avi_data + 7)), hdmi_base + S5P_AVI_BYTE8); + writel(SET_AVI_BYTE(*(avi_data + 8)), hdmi_base + S5P_AVI_BYTE9); + writel(SET_AVI_BYTE(*(avi_data + 9)), hdmi_base + S5P_AVI_BYTE10); + writel(SET_AVI_BYTE(*(avi_data + 10)), hdmi_base + S5P_AVI_BYTE11); + writel(SET_AVI_BYTE(*(avi_data + 11)), hdmi_base + S5P_AVI_BYTE12); + writel(SET_AVI_BYTE(*(avi_data + 12)), hdmi_base + S5P_AVI_BYTE13); + + HDMIPRINTK("AVI_CON = 0x%08x \n\r", readl(hdmi_base + S5P_AVI_CON)); + HDMIPRINTK("AVI_CHECK_SUM = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_CHECK_SUM)); + HDMIPRINTK("AVI_BYTE1 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE1)); + HDMIPRINTK("AVI_BYTE2 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE2)); + HDMIPRINTK("AVI_BYTE3 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE3)); + HDMIPRINTK("AVI_BYTE4 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE4)); + HDMIPRINTK("AVI_BYTE5 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE5)); + HDMIPRINTK("AVI_BYTE6 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE6)); + HDMIPRINTK("AVI_BYTE7 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE7)); + HDMIPRINTK("AVI_BYTE8 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE8)); + HDMIPRINTK("AVI_BYTE9 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE9)); + HDMIPRINTK("AVI_BYTE10 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE10)); + HDMIPRINTK("AVI_BYTE11 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE11)); + HDMIPRINTK("AVI_BYTE12 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE12)); + HDMIPRINTK("AVI_BYTE13 = 0x%08x \n\r", + readl(hdmi_base + S5P_AVI_BYTE13)); + + return HDMI_NO_ERROR; +} + +enum s5p_tv_hdmi_err __s5p_hdmi_video_init_mpg_infoframe( + enum s5p_hdmi_transmit trans_type, u8 check_sum, u8 *mpg_data) +{ + HDMIPRINTK("trans_type : %d, %d, %d\n\r", (u32)trans_type, + (u32)check_sum, (u32)mpg_data); + + switch (trans_type) { + + case HDMI_DO_NOT_TANS: + writel(MPG_TX_CON_NO_TRANS, + hdmi_base + S5P_MPG_CON); + break; + + case HDMI_TRANS_ONCE: + writel(MPG_TX_CON_TRANS_ONCE, + hdmi_base + S5P_MPG_CON); + break; + + case HDMI_TRANS_EVERY_SYNC: + writel(MPG_TX_CON_TRANS_EVERY_VSYNC, + hdmi_base + S5P_MPG_CON); + break; + + default: + HDMIPRINTK("invalid out_mode parameter(%d)\n\r", + trans_type); + return S5P_TV_HDMI_ERR_INVALID_PARAM; + break; + } + + writel(SET_MPG_CHECK_SUM(check_sum), + + hdmi_base + S5P_MPG_CHECK_SUM); + + writel(SET_MPG_BYTE(*(mpg_data)), + hdmi_base + S5P_MPEG_BYTE1); + writel(SET_MPG_BYTE(*(mpg_data + 1)), + hdmi_base + S5P_MPEG_BYTE2); + writel(SET_MPG_BYTE(*(mpg_data + 2)), + hdmi_base + S5P_MPEG_BYTE3); + writel(SET_MPG_BYTE(*(mpg_data + 3)), + hdmi_base + S5P_MPEG_BYTE4); + writel(SET_MPG_BYTE(*(mpg_data + 4)), + hdmi_base + S5P_MPEG_BYTE5); + + HDMIPRINTK("MPG_CON = 0x%08x \n\r", + readl(hdmi_base + S5P_MPG_CON)); + HDMIPRINTK("MPG_CHECK_SUM = 0x%08x \n\r", + readl(hdmi_base + S5P_MPG_CHECK_SUM)); + HDMIPRINTK("MPEG_BYTE1 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE1)); + HDMIPRINTK("MPEG_BYTE2 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE2)); + HDMIPRINTK("MPEG_BYTE3 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE3)); + HDMIPRINTK("MPEG_BYTE4 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE4)); + HDMIPRINTK("MPEG_BYTE5 = 0x%08x \n\r", + readl(hdmi_base + S5P_MPEG_BYTE5)); + + return HDMI_NO_ERROR; +} + +void __s5p_hdmi_video_init_tg_cmd(bool time_c_e, + bool bt656_sync_en, + bool tg_en) +{ + u32 temp_reg = 0; + + temp_reg = readl(hdmi_base + S5P_TG_CMD); + + if (time_c_e) + temp_reg |= GETSYNC_TYPE_EN; + else + temp_reg &= GETSYNC_TYPE_DIS; + + if (bt656_sync_en) + temp_reg |= GETSYNC_EN; + else + temp_reg &= GETSYNC_DIS; + + if (tg_en) + temp_reg |= TG_EN; + else + temp_reg &= TG_DIS; + + writel(temp_reg, hdmi_base + S5P_TG_CMD); + + HDMIPRINTK("TG_CMD = 0x%08x \n\r", readl(hdmi_base + S5P_TG_CMD)); +} + +bool __s5p_hdmi_start(enum s5p_hdmi_audio_type hdmi_audio_type, + bool hdcp_en, + struct i2c_client *ddc_port) +{ + u32 temp_reg = HDMI_EN; + + HDMIPRINTK("aud type : %d, hdcp enable : %d\n\r", + hdmi_audio_type, hdcp_en); + + switch (hdmi_audio_type) { + + case HDMI_AUDIO_PCM: + temp_reg |= ASP_EN; + break; + + case HDMI_AUDIO_NO: + break; + + default: + HDMIPRINTK(" invalid hdmi_audio_type(%d)\n\r", + hdmi_audio_type); + return false; + break; + } + if (hdcp_en) { + writel(HDCP_ENC_DISABLE, hdmi_base + S5P_ENC_EN); + s5p_hdmi_mute_en(true); + } + + writel(readl(hdmi_base + S5P_HDMI_CON_0) | temp_reg, + hdmi_base + S5P_HDMI_CON_0); + +#ifdef CONFIG_HDMI_HPD + s5p_hpd_set_hdmiint(); +#endif + +#if 1 + if (hdcp_en) { + + + if (!__s5p_start_hdcp()) + HDMIPRINTK("HDCP start failed\n"); + + } + +#endif + HDMIPRINTK("HPD : 0x%08x, HDMI_CON_0 : 0x%08x\n\r", + readl(hdmi_base + S5P_HPD), + readl(hdmi_base + S5P_HDMI_CON_0)); + + return true; +} + +/* +* stop - stop functions are only called under running HDMI +*/ +void __s5p_hdmi_stop(void) +{ + u32 temp = 0, result = 0; + + HDMIPRINTK("\n\r"); + + __s5p_stop_hdcp(); + + /* + * Before stopping hdmi, stop the hdcp first. However, + * if there's no delay between hdcp stop & hdmi stop, + * re-opening would be failed. + */ + mdelay(100); + + temp = readl(hdmi_base + S5P_HDMI_CON_0); + result = temp & HDMI_EN; + + if (result) + writel(temp & ~(HDMI_EN | ASP_EN), + hdmi_base + S5P_HDMI_CON_0); + + do { + temp = readl(hdmi_base + S5P_HDMI_CON_0); + } while (temp & HDMI_EN); + +#ifdef CONFIG_HDMI_HPD + s5p_hpd_set_eint(); +#endif + HDMIPRINTK("HPD 0x%08x, HDMI_CON_0 0x%08x\n\r", + readl(hdmi_base + S5P_HPD), + readl(hdmi_base + S5P_HDMI_CON_0)); +} + +int __init __s5p_hdmi_probe(struct platform_device *pdev, + u32 res_num, u32 res_num2) +{ + struct resource *res; + size_t size; + u32 reg; + + spin_lock_init(&lock_hdmi); + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + goto error; + } + + size = (res->end - res->start) + 1; + + hdmi_mem = request_mem_region(res->start, size, pdev->name); + + if (hdmi_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + goto error; + } + + hdmi_base = ioremap(res->start, size); + + if (hdmi_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + goto error; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num2); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + goto error; + } + + size = (res->end - res->start) + 1; + + i2c_hdmi_phy_mem = request_mem_region(res->start, size, pdev->name); + + if (i2c_hdmi_phy_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + goto error; + } + + i2c_hdmi_phy_base = ioremap(res->start, size); + + if (i2c_hdmi_phy_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + goto error; + } + + /* PMU Block : HDMI PHY Enable */ + reg = readl(S3C_VA_SYS+0xE804); + reg |= (1<<0); + writel(reg, S3C_VA_SYS+0xE804); + + /* i2c_hdmi init - set i2c filtering */ + writeb(0x5, i2c_hdmi_phy_base + I2C_HDMI_LC); + + /* temp for test - hdmi intr. global enable */ + reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_CON); + writeb(reg | (1<<HDMI_IRQ_GLOBAL), hdmi_base+S5P_HDMI_CTRL_INTC_CON); + + return 0; +error: + return -ENOENT; +} + +int __init __s5p_hdmi_release(struct platform_device *pdev) +{ + iounmap(hdmi_base); + + /* remove memory region */ + if (hdmi_mem != NULL) { + if (release_resource(hdmi_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(hdmi_mem); + + hdmi_mem = NULL; + } + + return 0; +} + +/* + * HDCP ISR. + * If HDCP IRQ occurs, set hdcp_event and wake up the waitqueue. + */ + +#define HDMI_IRQ_TOTAL_NUM 6 + +hdmi_isr hdmi_isr_ftn[HDMI_IRQ_TOTAL_NUM]; + +int s5p_hdmi_register_isr(hdmi_isr isr, u8 irq_num) +{ + HDMIPRINTK("Try to register ISR for IRQ number (%d)\n", irq_num); + + if (isr == NULL) { + HDMIPRINTK("Invaild ISR\n"); + return -EINVAL; + } + + /* check IRQ number */ + if (irq_num > HDMI_IRQ_TOTAL_NUM) { + HDMIPRINTK("irq_num exceeds allowed IRQ number(%d)\n", + HDMI_IRQ_TOTAL_NUM); + return -EINVAL; + } + + /* check if is the number already registered? */ + if (hdmi_isr_ftn[irq_num]) { + HDMIPRINTK("the %d th ISR is already registered\n", + irq_num); + } + + hdmi_isr_ftn[irq_num] = isr; + + HDMIPRINTK("Success to register ISR for IRQ number (%d)\n", + irq_num); + + return 0; +} +EXPORT_SYMBOL(s5p_hdmi_register_isr); + +irqreturn_t __s5p_hdmi_irq(int irq, void *dev_id) +{ + u8 irq_state, irq_num; + + spin_lock_irq(&lock_hdmi); + + irq_state = readb(hdmi_base+S5P_HDMI_CTRL_INTC_FLAG); + + HDMIPRINTK("S5P_HDMI_CTRL_INTC_FLAG = 0x%02x\n", irq_state); + + /* Check interrupt happened */ + /* Priority of Interrupt HDCP> I2C > Audio > CEC (Not implemented) */ + + if (irq_state) { + /* HDCP IRQ*/ + irq_num = 0; + /* check if ISR is null or not */ + while (irq_num < HDMI_IRQ_TOTAL_NUM) { + if (irq_state & (1<<irq_num)) { + if (hdmi_isr_ftn[irq_num] != NULL) + (hdmi_isr_ftn[irq_num])(irq_num); + else + HDMIPRINTK( + "No registered ISR for IRQ[%d]\n", + irq_num); + + } + ++irq_num; + } + + } else { + HDMIPRINTK("Undefined IRQ happened[%x]\n", irq_state); + } + + spin_unlock_irq(&lock_hdmi); + + return IRQ_HANDLED; +} + +u8 s5p_hdmi_get_enabled_interrupt(void) +{ + u8 reg; + reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_CON); + return reg; +} + +void s5p_hdmi_enable_interrupts(enum s5p_tv_hdmi_interrrupt intr) +{ + u8 reg; + reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_CON); + writeb(reg | (1<<intr) | (1<<HDMI_IRQ_GLOBAL), + hdmi_base+S5P_HDMI_CTRL_INTC_CON); +} +EXPORT_SYMBOL(s5p_hdmi_enable_interrupts); + +void s5p_hdmi_disable_interrupts(enum s5p_tv_hdmi_interrrupt intr) +{ + u8 reg; + reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_CON); + writeb(reg & ~(1<<intr), hdmi_base+S5P_HDMI_CTRL_INTC_CON); +} +EXPORT_SYMBOL(s5p_hdmi_disable_interrupts); + +void s5p_hdmi_clear_pending(enum s5p_tv_hdmi_interrrupt intr) +{ + u8 reg; + reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_FLAG); + writeb(reg | (1<<intr), hdmi_base+S5P_HDMI_CTRL_INTC_FLAG); +} +EXPORT_SYMBOL(s5p_hdmi_clear_pending); + +u8 s5p_hdmi_get_interrupts(void) +{ + u8 reg; + reg = readb(hdmi_base+S5P_HDMI_CTRL_INTC_FLAG); + return reg; +} +EXPORT_SYMBOL(s5p_hdmi_get_interrupts); + +u8 s5p_hdmi_get_swhpd_status(void) +{ + u8 reg; + reg = readb(hdmi_base+S5P_HPD) & HPD_SW_ENABLE; + return reg; +} +EXPORT_SYMBOL(s5p_hdmi_get_swhpd_status); + +u8 s5p_hdmi_get_hpd_status(void) +{ + u8 reg; + reg = readb(hdmi_base+S5P_HDMI_CTRL_HPD); + return reg; +} +EXPORT_SYMBOL(s5p_hdmi_get_hpd_status); + +void s5p_hdmi_swhpd_disable(void) +{ + writeb(HPD_SW_DISABLE, hdmi_base+S5P_HPD); +} +EXPORT_SYMBOL(s5p_hdmi_swhpd_disable); + +void s5p_hdmi_hpd_gen(void) +{ + writeb(0xFF, hdmi_base+S5P_HDMI_HPD_GEN); +} +EXPORT_SYMBOL(s5p_hdmi_hpd_gen); + diff --git a/drivers/media/video/samsung/tv20/s5pv210/regs/regs-cec.h b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-cec.h new file mode 100644 index 0000000..9e29d0e --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-cec.h @@ -0,0 +1,101 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc110/regs/regs-cec.h + * + * CEC register header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __REGS_CEC_H +#define __REGS_CEC_H + +#define HDMIDP_CECREG(x) (x) + +/** + * @name CEC config/status registers + */ +#define CEC_STATUS_0 HDMIDP_CECREG(0x0000) +#define CEC_STATUS_1 HDMIDP_CECREG(0x0004) +#define CEC_STATUS_2 HDMIDP_CECREG(0x0008) +#define CEC_STATUS_3 HDMIDP_CECREG(0x000C) +#define CEC_IRQ_MASK HDMIDP_CECREG(0x0010) +#define CEC_IRQ_CLEAR HDMIDP_CECREG(0x0014) +#define CEC_LOGIC_ADDR HDMIDP_CECREG(0x0020) +#define CEC_DIVISOR_0 HDMIDP_CECREG(0x0030) +#define CEC_DIVISOR_1 HDMIDP_CECREG(0x0034) +#define CEC_DIVISOR_2 HDMIDP_CECREG(0x0038) +#define CEC_DIVISOR_3 HDMIDP_CECREG(0x003C) + +/** + * @name CEC Tx related registers + */ +#define CEC_TX_CTRL HDMIDP_CECREG(0x0040) +#define CEC_TX_BYTES HDMIDP_CECREG(0x0044) +#define CEC_TX_STAT0 HDMIDP_CECREG(0x0060) +#define CEC_TX_STAT1 HDMIDP_CECREG(0x0064) +#define CEC_TX_BUFF0 HDMIDP_CECREG(0x0080) +#define CEC_TX_BUFF1 HDMIDP_CECREG(0x0084) +#define CEC_TX_BUFF2 HDMIDP_CECREG(0x0088) +#define CEC_TX_BUFF3 HDMIDP_CECREG(0x008C) +#define CEC_TX_BUFF4 HDMIDP_CECREG(0x0090) +#define CEC_TX_BUFF5 HDMIDP_CECREG(0x0094) +#define CEC_TX_BUFF6 HDMIDP_CECREG(0x0098) +#define CEC_TX_BUFF7 HDMIDP_CECREG(0x009C) +#define CEC_TX_BUFF8 HDMIDP_CECREG(0x00A0) +#define CEC_TX_BUFF9 HDMIDP_CECREG(0x00A4) +#define CEC_TX_BUFF10 HDMIDP_CECREG(0x00A8) +#define CEC_TX_BUFF11 HDMIDP_CECREG(0x00AC) +#define CEC_TX_BUFF12 HDMIDP_CECREG(0x00B0) +#define CEC_TX_BUFF13 HDMIDP_CECREG(0x00B4) +#define CEC_TX_BUFF14 HDMIDP_CECREG(0x00B8) +#define CEC_TX_BUFF15 HDMIDP_CECREG(0x00BC) + +/** + * @name CEC Rx related registers + */ +#define CEC_RX_CTRL HDMIDP_CECREG(0x00C0) +#define CEC_RX_STAT0 HDMIDP_CECREG(0x00E0) +#define CEC_RX_STAT1 HDMIDP_CECREG(0x00E4) +#define CEC_RX_BUFF0 HDMIDP_CECREG(0x0100) +#define CEC_RX_BUFF1 HDMIDP_CECREG(0x0104) +#define CEC_RX_BUFF2 HDMIDP_CECREG(0x0108) +#define CEC_RX_BUFF3 HDMIDP_CECREG(0x010C) +#define CEC_RX_BUFF4 HDMIDP_CECREG(0x0110) +#define CEC_RX_BUFF5 HDMIDP_CECREG(0x0114) +#define CEC_RX_BUFF6 HDMIDP_CECREG(0x0118) +#define CEC_RX_BUFF7 HDMIDP_CECREG(0x011C) +#define CEC_RX_BUFF8 HDMIDP_CECREG(0x0120) +#define CEC_RX_BUFF9 HDMIDP_CECREG(0x0124) +#define CEC_RX_BUFF10 HDMIDP_CECREG(0x0128) +#define CEC_RX_BUFF11 HDMIDP_CECREG(0x012C) +#define CEC_RX_BUFF12 HDMIDP_CECREG(0x0130) +#define CEC_RX_BUFF13 HDMIDP_CECREG(0x0134) +#define CEC_RX_BUFF14 HDMIDP_CECREG(0x0138) +#define CEC_RX_BUFF15 HDMIDP_CECREG(0x013C) + +#define CEC_RX_FILTER_CTRL HDMIDP_CECREG(0x0180) +#define CEC_RX_FILTER_TH HDMIDP_CECREG(0x0184) + +/** + * @name Bit values + */ +#define CEC_IRQ_TX_DONE (1<<0) +#define CEC_IRQ_TX_ERROR (1<<1) +#define CEC_IRQ_RX_DONE (1<<4) +#define CEC_IRQ_RX_ERROR (1<<5) + +#define CEC_TX_CTRL_START (1<<0) +#define CEC_TX_CTRL_BCAST (1<<1) +#define CEC_TX_CTRL_RETRY (0x04<<4) +#define CEC_TX_CTRL_RESET (1<<7) + +#define CEC_RX_CTRL_ENABLE (1<<0) +#define CEC_RX_CTRL_RESET (1<<7) + +#define CEC_LOGIC_ADDR_MASK 0x0F + +#endif /* __REGS_CEC_H */ diff --git a/drivers/media/video/samsung/tv20/s5pv210/regs/regs-clock_extra.h b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-clock_extra.h new file mode 100644 index 0000000..d4cede6 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-clock_extra.h @@ -0,0 +1,103 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-clock_extra.h + * + * Clock Other header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_CLK_EXTRA_H +#define __ASM_ARCH_REGS_CLK_EXTRA_H + +#include <mach/map.h> + +#define S5P_CLK_OTHER_BASE(x) (x) +/* + * Registers + * */ +/* Generate software reset 0x0000_0000 */ +#define S5P_CLK_OTHER_SWRESET S5P_CLK_OTHER_BASE(0x0000) +/* OneNAND controller setting 0x0000_0000 */ +#define S5P_CLK_OTHER_ONENAND_SWRESET S5P_CLK_OTHER_BASE(0x0008) +/* General Control Register 0x0000_0000 */ +#define S5P_CLK_OTHER_GENERAL_CTRL S5P_CLK_OTHER_BASE(0x0100) +/* General Status Register 0x0000_0000 */ +#define S5P_CLK_OTHER_GENERAL_STATUS S5P_CLK_OTHER_BASE(0x0104) +/* ENDIAN & EBI configuration 0x0000_0000 */ +#define S5P_CLK_OTHER_MEM_SYS_CFG S5P_CLK_OTHER_BASE(0x0200) +/* Camera mapping to FIMC selection 0x0000_0000 */ +#define S5P_CLK_OTHER_CAM_MUX_SEL S5P_CLK_OTHER_BASE(0x0300) +/* Video Mixer output to TVENC / HDMI selection 0x0000_0000*/ +#define S5P_CLK_OTHER_MIXER_OUT_SEL S5P_CLK_OTHER_BASE(0x0304) +/* Low power MP3 mode selection 0x0000_0000 */ +#define S5P_CLK_OTHER_LPMP3_MODE_SEL S5P_CLK_OTHER_BASE(0x0308) +/* MIPI D-PHY control register0 0x0000_0000 */ +#define S5P_CLK_OTHER_MIPI_PHY_CON0 S5P_CLK_OTHER_BASE(0x0400) +/* MIPI D-PHY control register1 0x0000_0000 */ +#define S5P_CLK_OTHER_MIPI_PHY_CON1 S5P_CLK_OTHER_BASE(0x0414) +/* HDMI PHY control register0 0x0000_0000 */ +#define S5P_CLK_OTHER_HDMI_PHY_CON0 S5P_CLK_OTHER_BASE(0x0420) + +/* + * Macros + * */ +/* VPLL_LOCK */ +#define VPLL_LOCKTIME(a) (0xffff&a) + +/* VPLL_CON */ +#define VPLL_ENABLE (1<<31) +#define VPLL_DISABLE (0<<31) +#define VPLL_LOCKED(a) ((1<<29)&a) +#define VCO_FREQ_SEL (1<<27) +#define MDIV(a) ((0xff&a)<<16) +#define PDIV(a) ((0x3f&a)<<8) +#define SDIV(a) (0x7&a) + +/* CLK_SRC0 */ +#define HREF_SEL_FIN_27M (0<<20) +#define HREF_SEL_SRCLK (1<<20) +#define HREF_SEL_MASK (~(1<<20)) +#define VPLL_SEL_CLK27M (0<<12) +#define VPLL_SEL_FOUT_VPLL (1<<12) +#define VPLL_SEL_MASK (~(1<<12)) + +/* CLK_SRC2 */ +#define VMIXER_SEL_MOUT_VPLL (1<<4) +#define VMIXER_SEL_MASK (~(1<<4)) +#define HDMI_SEL_HDMIPHY (1<<0) +#define HDMI_SEL_MASK (~(1<<0)) + +/* CLK_DIV3 */ +#define HDMI_DIV_RATIO(a) (0xf&(a)) +#define HDMI_DIV_RATIO_MASK (~(0xf)) + +/* CLK_GATE_D1_2 */ +#define CLK_HCLK_HDMI_PASS (1<<11) +#define CLK_HCLK_SDOUT_PASS (1<<10) +#define CLK_HCLK_VMIXER_PASS (1<<9) +#define CLK_HCLK_VP_PASS (1<<8) +#define CLK_HCLK_MASK (~0xf) + +/* CLK_GATE_D1_4 */ +#define CLK_PCLK_IIC_HDMI_PASS (1<<5) +#define CLK_PCLK_IIC_HDMI_MASK (~(1<<5)) + +/* CLK_GATE_SCLK_1 */ +#define CLK_SCLK_HDMI_PASS (1<<19) +#define CLK_SCLK_VMIXER_PASS (1<<20) +#define CLK_SCLK_VDAC54_PASS (1<<21) +#define CLK_SCLK_TV54_PASS (1<<22) +#define CLK_SCLK_HDMI_MASK (~(1<<19)) +#define CLK_SCLK_VMIXER_MASK (~(1<<20)) +#define CLK_SCLK_VDAC54_MASK (~(1<<21)) +#define CLK_SCLK_TV54_MASK (~(1<<22)) + +/* MIXER_OUT_SEL */ +#define VMIXER_OUT_SEL_SDOUT (0) +#define VMIXER_OUT_SEL_HDMI (1) + +#endif /*__ASM_ARCH_REGS_CLK_EXTRA_H */ diff --git a/drivers/media/video/samsung/tv20/s5pv210/regs/regs-hdmi.h b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-hdmi.h new file mode 100644 index 0000000..8094417 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-hdmi.h @@ -0,0 +1,1552 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-hdmi.h + * + * Hdmi register header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_HDMI_H + +#include <mach/map.h> + +#define S5P_I2C_HDMI_PHY_BASE(x) (x) + +/* + * HDMI PHY is configured through the dedicated I2C. + * The dedicated I2C for HDMI PHY is only used as TX mode + * I2C-BUS Interface for HDMI PHY is internally connected + */ +#define I2C_HDMI_CON S5P_I2C_HDMI_PHY_BASE(0x0000) +#define I2C_HDMI_STAT S5P_I2C_HDMI_PHY_BASE(0x0004) +#define I2C_HDMI_ADD S5P_I2C_HDMI_PHY_BASE(0x0008) +#define I2C_HDMI_DS S5P_I2C_HDMI_PHY_BASE(0x000c) +#define I2C_HDMI_LC S5P_I2C_HDMI_PHY_BASE(0x0010) + +#define S5P_HDMI_CTRL_BASE(x) (x) +#define S5P_HDMI_BASE(x) (x + 0x00010000) +#define S5P_HDMI_SPDIF_BASE(x) (x + 0x00030000) +#define S5P_HDMI_I2S_BASE(x) (x + 0x00040000) +#define S5P_HDMI_TG_BASE(x) (x + 0x00050000) +#define S5P_HDMI_EFUSE_BASE(x) (x + 0x00060000) + +#define S5P_HDMI_CTRL_INTC_CON S5P_HDMI_CTRL_BASE(0x0000) /* Interrupt Control Register */ +#define S5P_HDMI_CTRL_INTC_FLAG S5P_HDMI_CTRL_BASE(0x0004) /* Interrupt Flag Register */ +#define S5P_HDMI_CTRL_HDCP_KEY_LOAD S5P_HDMI_CTRL_BASE(0x0008) /* HDCP KEY Status */ +#define S5P_HDMI_CTRL_HPD S5P_HDMI_CTRL_BASE(0x000C) /* HPD signal */ +#define S5P_HDMI_CTRL_AUDIO_CLKSEL S5P_HDMI_CTRL_BASE(0x0010) /* Audio system clock selection */ +#define S5P_HDMI_CTRL_PHY_RSTOUT S5P_HDMI_CTRL_BASE(0x0014) /* HDMI PHY Reset Out */ +#define S5P_HDMI_CTRL_PHY_VPLL S5P_HDMI_CTRL_BASE(0x0018) /* HDMI PHY VPLL Monitor */ +#define S5P_HDMI_CTRL_PHY_CMU S5P_HDMI_CTRL_BASE(0x001C) /* HDMI PHY CMU Monitor */ +#define S5P_HDMI_CTRL_CORE_RSTOUT S5P_HDMI_CTRL_BASE(0x0020) /* HDMI TX Core S/W reset */ + +#define S5P_HDMI_CON_0 S5P_HDMI_BASE(0x0000) /* HDMI System Control Register 0 0x00 */ +#define S5P_HDMI_CON_1 S5P_HDMI_BASE(0x0004) /* HDMI System Control Register 1 0x00 */ +#define S5P_HDMI_CON_2 S5P_HDMI_BASE(0x0008) /* HDMI System Control Register 2. 0x00 */ +#define S5P_STATUS S5P_HDMI_BASE(0x0010) /* HDMI System Status Register 0x00 */ +#define HDMI_PHY_STATUS S5P_HDMI_BASE(0x0014) /* HDMI Phy Status */ +#define S5P_STATUS_EN S5P_HDMI_BASE(0x0020) /* HDMI System Status Enable Register 0x00 */ +#define S5P_HPD S5P_HDMI_BASE(0x0030) /* Hot Plug Detection Control Register 0x00 */ +#define S5P_MODE_SEL S5P_HDMI_BASE(0x0040) /* HDMI/DVI Mode Selection 0x00 */ +#define S5P_ENC_EN S5P_HDMI_BASE(0x0044) /* HDCP Encryption Enable Register 0x00 */ + +#define S5P_BLUE_SCREEN_0 S5P_HDMI_BASE(0x0050) /* Pixel Values for Blue Screen 0x00 */ +#define S5P_BLUE_SCREEN_1 S5P_HDMI_BASE(0x0054) /* Pixel Values for Blue Screen 0x00 */ +#define S5P_BLUE_SCREEN_2 S5P_HDMI_BASE(0x0058) /* Pixel Values for Blue Screen 0x00 */ + +#define S5P_HDMI_YMAX S5P_HDMI_BASE(0x0060) /* Maximum Y (or R,G,B) Pixel Value 0xEB */ +#define S5P_HDMI_YMIN S5P_HDMI_BASE(0x0064) /* Minimum Y (or R,G,B) Pixel Value 0x10 */ +#define S5P_HDMI_CMAX S5P_HDMI_BASE(0x0068) /* Maximum Cb/ Cr Pixel Value 0xF0 */ +#define S5P_HDMI_CMIN S5P_HDMI_BASE(0x006C) /* Minimum Cb/ Cr Pixel Value 0x10 */ + +#define S5P_H_BLANK_0 S5P_HDMI_BASE(0x00A0) /* Horizontal Blanking Setting 0x00 */ +#define S5P_H_BLANK_1 S5P_HDMI_BASE(0x00A4) /* Horizontal Blanking Setting 0x00 */ +#define S5P_V_BLANK_0 S5P_HDMI_BASE(0x00B0) /* Vertical Blanking Setting 0x00 */ +#define S5P_V_BLANK_1 S5P_HDMI_BASE(0x00B4) /* Vertical Blanking Setting 0x00 */ +#define S5P_V_BLANK_2 S5P_HDMI_BASE(0x00B8) /* Vertical Blanking Setting 0x00 */ +#define S5P_H_V_LINE_0 S5P_HDMI_BASE(0x00C0) /* Hori. Line and Ver. Line 0x00 */ +#define S5P_H_V_LINE_1 S5P_HDMI_BASE(0x00C4) /* Hori. Line and Ver. Line 0x00 */ +#define S5P_H_V_LINE_2 S5P_HDMI_BASE(0x00C8) /* Hori. Line and Ver. Line 0x00 */ + +#define S5P_SYNC_MODE S5P_HDMI_BASE(0x00E4) /* Vertical Sync Polarity Control Register 0x00 */ +#define S5P_INT_PRO_MODE S5P_HDMI_BASE(0x00E8) /* Interlace/ Progressive Control Register 0x00 */ + +#define S5P_V_BLANK_F_0 S5P_HDMI_BASE(0x0110) /* Vertical Blanking Setting for Bottom Field 0x00 */ +#define S5P_V_BLANK_F_1 S5P_HDMI_BASE(0x0114) /* Vertical Blanking Setting for Bottom Field 0x00 */ +#define S5P_V_BLANK_F_2 S5P_HDMI_BASE(0x0118) /* Vertical Blanking Setting for Bottom Field 0x00 */ +#define S5P_H_SYNC_GEN_0 S5P_HDMI_BASE(0x0120) /* Horizontal Sync Generation Setting 0x00 */ +#define S5P_H_SYNC_GEN_1 S5P_HDMI_BASE(0x0124) /* Horizontal Sync Generation Setting 0x00 */ +#define S5P_H_SYNC_GEN_2 S5P_HDMI_BASE(0x0128) /* Horizontal Sync Generation Setting 0x00 */ +#define S5P_V_SYNC_GEN_1_0 S5P_HDMI_BASE(0x0130) /* Vertical Sync Generation for Top Field or Frame. 0x01 */ +#define S5P_V_SYNC_GEN_1_1 S5P_HDMI_BASE(0x0134) /* Vertical Sync Generation for Top Field or Frame. 0x10 */ +#define S5P_V_SYNC_GEN_1_2 S5P_HDMI_BASE(0x0138) /* Vertical Sync Generation for Top Field or Frame. 0x00 */ +#define S5P_V_SYNC_GEN_2_0 S5P_HDMI_BASE(0x0140) /* Vertical Sync Generation for Bottom field ? Vertical position. 0x01 */ +#define S5P_V_SYNC_GEN_2_1 S5P_HDMI_BASE(0x0144) /* Vertical Sync Generation for Bottom field ? Vertical position. 0x10 */ +#define S5P_V_SYNC_GEN_2_2 S5P_HDMI_BASE(0x0148) /* Vertical Sync Generation for Bottom field ? Vertical position. 0x00 */ +#define S5P_V_SYNC_GEN_3_0 S5P_HDMI_BASE(0x0150) /* Vertical Sync Generation for Bottom field ? Horizontal position. 0x01 */ +#define S5P_V_SYNC_GEN_3_1 S5P_HDMI_BASE(0x0154) /* Vertical Sync Generation for Bottom field ? Horizontal position. 0x10 */ +#define S5P_V_SYNC_GEN_3_2 S5P_HDMI_BASE(0x0158) /* Vertical Sync Generation for Bottom field ? Horizontal position. 0x00 */ + +#define S5P_ASP_CON S5P_HDMI_BASE(0x0160) /* ASP Packet Control Register 0x00 */ +#define S5P_ASP_SP_FLAT S5P_HDMI_BASE(0x0164) /* ASP Packet sp_flat Bit Control 0x00 */ +#define S5P_ASP_CHCFG0 S5P_HDMI_BASE(0x0170) /* ASP Audio Channel Configuration 0x04 */ +#define S5P_ASP_CHCFG1 S5P_HDMI_BASE(0x0174) /* ASP Audio Channel Configuration 0x1A */ +#define S5P_ASP_CHCFG2 S5P_HDMI_BASE(0x0178) /* ASP Audio Channel Configuration 0x2C */ +#define S5P_ASP_CHCFG3 S5P_HDMI_BASE(0x017C) /* ASP Audio Channel Configuration 0x3E */ + +#define S5P_ACR_CON S5P_HDMI_BASE(0x0180) /* ACR Packet Control Register 0x00 */ +#define S5P_ACR_MCTS0 S5P_HDMI_BASE(0x0184) /* Measured CTS Value 0x01 */ +#define S5P_ACR_MCTS1 S5P_HDMI_BASE(0x0188) /* Measured CTS Value 0x00 */ +#define S5P_ACR_MCTS2 S5P_HDMI_BASE(0x018C) /* Measured CTS Value 0x00 */ +#define S5P_ACR_CTS0 S5P_HDMI_BASE(0x0190) /* CTS Value for Fixed CTS Transmission Mode. 0xE8 */ +#define S5P_ACR_CTS1 S5P_HDMI_BASE(0x0194) /* CTS Value for Fixed CTS Transmission Mode. 0x03 */ +#define S5P_ACR_CTS2 S5P_HDMI_BASE(0x0198) /* CTS Value for Fixed CTS Transmission Mode. 0x00 */ +#define S5P_ACR_N0 S5P_HDMI_BASE(0x01A0) /* N Value for ACR Packet. 0xE8 */ +#define S5P_ACR_N1 S5P_HDMI_BASE(0x01A4) /* N Value for ACR Packet. 0x03 */ +#define S5P_ACR_N2 S5P_HDMI_BASE(0x01A8) /* N Value for ACR Packet. 0x00 */ +#define S5P_ACR_LSB2 S5P_HDMI_BASE(0x01B0) /* Altenate LSB for Fixed CTS Transmission Mode 0x00 */ +#define S5P_ACR_TXCNT S5P_HDMI_BASE(0x01B4) /* Number of ACR Packet Transmission per frame 0x1F */ +#define S5P_ACR_TXINTERVAL S5P_HDMI_BASE(0x01B8) /* Interval for ACR Packet Transmission 0x63 */ +#define S5P_ACR_CTS_OFFSET S5P_HDMI_BASE(0x01BC) /* CTS Offset for Measured CTS mode. 0x00 */ + +#define S5P_GCP_CON S5P_HDMI_BASE(0x01C0) /* ACR Packet Control register 0x00 */ +#define S5P_GCP_BYTE1 S5P_HDMI_BASE(0x01D0) /* GCP Packet Body 0x00 */ +#define S5P_GCP_BYTE2 S5P_HDMI_BASE(0x01D4) /* GCP Packet Body 0x01 */ +#define S5P_GCP_BYTE3 S5P_HDMI_BASE(0x01D8) /* GCP Packet Body 0x02 */ + +#define S5P_ACP_CON S5P_HDMI_BASE(0x01E0) /* ACP Packet Control register 0x00 */ +#define S5P_ACP_TYPE S5P_HDMI_BASE(0x01E4) /* ACP Packet Header 0x00 */ + +#define S5P_ACP_DATA0 S5P_HDMI_BASE(0x0200) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA1 S5P_HDMI_BASE(0x0204) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA2 S5P_HDMI_BASE(0x0208) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA3 S5P_HDMI_BASE(0x020c) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA4 S5P_HDMI_BASE(0x0210) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA5 S5P_HDMI_BASE(0x0214) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA6 S5P_HDMI_BASE(0x0218) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA7 S5P_HDMI_BASE(0x021c) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA8 S5P_HDMI_BASE(0x0220) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA9 S5P_HDMI_BASE(0x0224) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA10 S5P_HDMI_BASE(0x0228) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA11 S5P_HDMI_BASE(0x022c) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA12 S5P_HDMI_BASE(0x0230) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA13 S5P_HDMI_BASE(0x0234) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA14 S5P_HDMI_BASE(0x0238) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA15 S5P_HDMI_BASE(0x023c) /* ACP Packet Body 0x00 */ +#define S5P_ACP_DATA16 S5P_HDMI_BASE(0x0240) /* ACP Packet Body 0x00 */ + +#define S5P_ISRC_CON S5P_HDMI_BASE(0x0250) /* ACR Packet Control Register 0x00 */ +#define S5P_ISRC1_HEADER1 S5P_HDMI_BASE(0x0264) /* ISCR1 Packet Header 0x00 */ + +#define S5P_ISRC1_DATA0 S5P_HDMI_BASE(0x0270) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA1 S5P_HDMI_BASE(0x0274) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA2 S5P_HDMI_BASE(0x0278) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA3 S5P_HDMI_BASE(0x027c) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA4 S5P_HDMI_BASE(0x0280) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA5 S5P_HDMI_BASE(0x0284) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA6 S5P_HDMI_BASE(0x0288) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA7 S5P_HDMI_BASE(0x028c) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA8 S5P_HDMI_BASE(0x0290) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA9 S5P_HDMI_BASE(0x0294) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA10 S5P_HDMI_BASE(0x0298) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA11 S5P_HDMI_BASE(0x029c) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA12 S5P_HDMI_BASE(0x02a0) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA13 S5P_HDMI_BASE(0x02a4) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA14 S5P_HDMI_BASE(0x02a8) /* ISRC1 Packet Body 0x00 */ +#define S5P_ISRC1_DATA15 S5P_HDMI_BASE(0x02ac) /* ISRC1 Packet Body 0x00 */ + +#define S5P_ISRC2_DATA0 S5P_HDMI_BASE(0x02b0) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA1 S5P_HDMI_BASE(0x02b4) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA2 S5P_HDMI_BASE(0x02b8) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA3 S5P_HDMI_BASE(0x02bc) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA4 S5P_HDMI_BASE(0x02c0) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA5 S5P_HDMI_BASE(0x02c4) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA6 S5P_HDMI_BASE(0x02c8) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA7 S5P_HDMI_BASE(0x02cc) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA8 S5P_HDMI_BASE(0x02d0) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA9 S5P_HDMI_BASE(0x02d4) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA10 S5P_HDMI_BASE(0x02d8) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA11 S5P_HDMI_BASE(0x02dc) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA12 S5P_HDMI_BASE(0x02e0) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA13 S5P_HDMI_BASE(0x02e4) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA14 S5P_HDMI_BASE(0x02e8) /* ISRC2 Packet Body 0x00 */ +#define S5P_ISRC2_DATA15 S5P_HDMI_BASE(0x02ec) /* ISRC2 Packet Body 0x00 */ + +#define S5P_AVI_CON S5P_HDMI_BASE(0x0300) /* AVI Packet Control Register 0x00 */ +#define S5P_AVI_CHECK_SUM S5P_HDMI_BASE(0x0310) /* AVI Packet Checksum 0x00 */ + +#define S5P_AVI_BYTE1 S5P_HDMI_BASE(0x0320) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE2 S5P_HDMI_BASE(0x0324) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE3 S5P_HDMI_BASE(0x0328) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE4 S5P_HDMI_BASE(0x032c) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE5 S5P_HDMI_BASE(0x0330) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE6 S5P_HDMI_BASE(0x0334) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE7 S5P_HDMI_BASE(0x0338) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE8 S5P_HDMI_BASE(0x033c) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE9 S5P_HDMI_BASE(0x0340) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE10 S5P_HDMI_BASE(0x0344) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE11 S5P_HDMI_BASE(0x0348) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE12 S5P_HDMI_BASE(0x034c) /* AVI Packet Body 0x00 */ +#define S5P_AVI_BYTE13 S5P_HDMI_BASE(0x0350) /* AVI Packet Body 0x00 */ + +#define S5P_AUI_CON S5P_HDMI_BASE(0x0360) /* AUI Packet Control Register 0x00 */ +#define S5P_AUI_CHECK_SUM S5P_HDMI_BASE(0x0370) /* AUI Packet Checksum 0x00 */ + +#define S5P_AUI_BYTE1 S5P_HDMI_BASE(0x0380) /* AUI Packet Body 0x00 */ +#define S5P_AUI_BYTE2 S5P_HDMI_BASE(0x0384) /* AUI Packet Body 0x00 */ +#define S5P_AUI_BYTE3 S5P_HDMI_BASE(0x0388) /* AUI Packet Body 0x00 */ +#define S5P_AUI_BYTE4 S5P_HDMI_BASE(0x038c) /* AUI Packet Body 0x00 */ +#define S5P_AUI_BYTE5 S5P_HDMI_BASE(0x0390) /* AUI Packet Body 0x00 */ + +#define S5P_MPG_CON S5P_HDMI_BASE(0x03A0) /* ACR Packet Control Register 0x00 */ +#define S5P_MPG_CHECK_SUM S5P_HDMI_BASE(0x03B0) /* MPG Packet Checksum 0x00 */ + +#define S5P_MPEG_BYTE1 S5P_HDMI_BASE(0x03c0) /* MPEG Packet Body 0x00 */ +#define S5P_MPEG_BYTE2 S5P_HDMI_BASE(0x03c4) /* MPEG Packet Body 0x00 */ +#define S5P_MPEG_BYTE3 S5P_HDMI_BASE(0x03c8) /* MPEG Packet Body 0x00 */ +#define S5P_MPEG_BYTE4 S5P_HDMI_BASE(0x03cc) /* MPEG Packet Body 0x00 */ +#define S5P_MPEG_BYTE5 S5P_HDMI_BASE(0x03d0) /* MPEG Packet Body 0x00 */ + +#define S5P_SPD_CON S5P_HDMI_BASE(0x0400) /* SPD Packet Control Register 0x00 */ +#define S5P_SPD_HEADER0 S5P_HDMI_BASE(0x0410) /* SPD Packet Header 0x00 */ +#define S5P_SPD_HEADER1 S5P_HDMI_BASE(0x0414) /* SPD Packet Header 0x00 */ +#define S5P_SPD_HEADER2 S5P_HDMI_BASE(0x0418) /* SPD Packet Header 0x00 */ + +#define S5P_SPD_DATA0 S5P_HDMI_BASE(0x0420) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA1 S5P_HDMI_BASE(0x0424) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA2 S5P_HDMI_BASE(0x0428) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA3 S5P_HDMI_BASE(0x042c) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA4 S5P_HDMI_BASE(0x0430) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA5 S5P_HDMI_BASE(0x0434) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA6 S5P_HDMI_BASE(0x0438) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA7 S5P_HDMI_BASE(0x043c) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA8 S5P_HDMI_BASE(0x0440) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA9 S5P_HDMI_BASE(0x0444) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA10 S5P_HDMI_BASE(0x0448) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA11 S5P_HDMI_BASE(0x044c) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA12 S5P_HDMI_BASE(0x0450) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA13 S5P_HDMI_BASE(0x0454) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA14 S5P_HDMI_BASE(0x0458) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA15 S5P_HDMI_BASE(0x045c) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA16 S5P_HDMI_BASE(0x0460) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA17 S5P_HDMI_BASE(0x0464) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA18 S5P_HDMI_BASE(0x0468) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA19 S5P_HDMI_BASE(0x046c) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA20 S5P_HDMI_BASE(0x0470) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA21 S5P_HDMI_BASE(0x0474) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA22 S5P_HDMI_BASE(0x0478) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA23 S5P_HDMI_BASE(0x048c) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA24 S5P_HDMI_BASE(0x0480) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA25 S5P_HDMI_BASE(0x0484) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA26 S5P_HDMI_BASE(0x0488) /* SPD Packet Body 0x00 */ +#define S5P_SPD_DATA27 S5P_HDMI_BASE(0x048c) /* SPD Packet Body 0x00 */ + +#define S5P_HDCP_RX_SHA1_0_0 S5P_HDMI_BASE(0x0600) /* SHA-1 Value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_0_1 S5P_HDMI_BASE(0x0604) /* SHA-1 Value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_0_2 S5P_HDMI_BASE(0x0608) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_0_3 S5P_HDMI_BASE(0x060C) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_1_0 S5P_HDMI_BASE(0x0610) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_1_1 S5P_HDMI_BASE(0x0614) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_1_2 S5P_HDMI_BASE(0x0618) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_1_3 S5P_HDMI_BASE(0x061C) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_2_0 S5P_HDMI_BASE(0x0620) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_2_1 S5P_HDMI_BASE(0x0624) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_2_2 S5P_HDMI_BASE(0x0628) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_2_3 S5P_HDMI_BASE(0x062C) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_3_0 S5P_HDMI_BASE(0x0630) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_3_1 S5P_HDMI_BASE(0x0634) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_3_2 S5P_HDMI_BASE(0x0638) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_3_3 S5P_HDMI_BASE(0x063C) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_4_0 S5P_HDMI_BASE(0x0640) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_4_1 S5P_HDMI_BASE(0x0644) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_4_2 S5P_HDMI_BASE(0x0648) /* SHA-1 value from Repeater 0x00 */ +#define S5P_HDCP_RX_SHA1_4_3 S5P_HDMI_BASE(0x064C) /* SHA-1 value from Repeater 0x00 */ + +#define S5P_HDCP_RX_KSV_0_0 S5P_HDMI_BASE(0x0650) /* Receiver¡¯s KSV 0 0x00 */ +#define S5P_HDCP_RX_KSV_0_1 S5P_HDMI_BASE(0x0654) /* Receiver¡¯s KSV 0 0x00 */ +#define S5P_HDCP_RX_KSV_0_2 S5P_HDMI_BASE(0x0658) /* Receiver¡¯s KSV 0 0x00 */ +#define S5P_HDCP_RX_KSV_0_3 S5P_HDMI_BASE(0x065C) /* Receiver¡¯s KSV 0 0x00 */ +#define S5P_HDCP_RX_KSV_0_4 S5P_HDMI_BASE(0x0660) /* Receiver¡¯s KSV 1 0x00 */ + +#define S5P_HDCP_RX_KSV_LIST_CTRL S5P_HDMI_BASE(0x0664) /* Receiver¡¯s KSV 1 0x00 */ +#define S5P_HDCP_AUTH_STATUS S5P_HDMI_BASE(0x0670) /* 2nd authentication status 0x00 */ +#define S5P_HDCP_CTRL1 S5P_HDMI_BASE(0x0680) /* HDCP Control 0x00 */ +#define S5P_HDCP_CTRL2 S5P_HDMI_BASE(0x0684) /* HDCP Control 0x00 */ +#define S5P_HDCP_CHECK_RESULT S5P_HDMI_BASE(0x0690) /* HDCP Ri, Pj, V result 0x00 */ + +#define S5P_HDCP_BKSV_0_0 S5P_HDMI_BASE(0x06A0) /* Receiver¡¯s BKSV 0x00 */ +#define S5P_HDCP_BKSV_0_1 S5P_HDMI_BASE(0x06A4) /* Receiver¡¯s BKSV 0x00 */ +#define S5P_HDCP_BKSV_0_2 S5P_HDMI_BASE(0x06A8) /* Receiver¡¯s BKSV 0x00 */ +#define S5P_HDCP_BKSV_0_3 S5P_HDMI_BASE(0x06AC) /* Receiver¡¯s BKSV 0x00 */ +#define S5P_HDCP_BKSV_1 S5P_HDMI_BASE(0x06B0) /* Receiver¡¯s BKSV 0x00 */ + +#define S5P_HDCP_AKSV_0_0 S5P_HDMI_BASE(0x06C0) /* Transmitter¡¯s AKSV 0x00 */ +#define S5P_HDCP_AKSV_0_1 S5P_HDMI_BASE(0x06C4) /* Transmitter¡¯s AKSV 0x00 */ +#define S5P_HDCP_AKSV_0_2 S5P_HDMI_BASE(0x06C8) /* Transmitter¡¯s AKSV 0x00 */ +#define S5P_HDCP_AKSV_0_3 S5P_HDMI_BASE(0x06CC) /* Transmitter¡¯s AKSV 0x00 */ +#define S5P_HDCP_AKSV_1 S5P_HDMI_BASE(0x06D0) /* Transmitter¡¯s AKSV 0x00 */ + +#define S5P_HDCP_An_0_0 S5P_HDMI_BASE(0x06E0) /* Transmitter¡¯s An 0x00 */ +#define S5P_HDCP_An_0_1 S5P_HDMI_BASE(0x06E4) /* Transmitter¡¯s An 0x00 */ +#define S5P_HDCP_An_0_2 S5P_HDMI_BASE(0x06E8) /* Transmitter¡¯s An 0x00 */ +#define S5P_HDCP_An_0_3 S5P_HDMI_BASE(0x06EC) /* Transmitter¡¯s An 0x00 */ +#define S5P_HDCP_An_1_0 S5P_HDMI_BASE(0x06F0) /* Transmitter¡¯s An 0x00 */ +#define S5P_HDCP_An_1_1 S5P_HDMI_BASE(0x06F4) /* Transmitter¡¯s An 0x00 */ +#define S5P_HDCP_An_1_2 S5P_HDMI_BASE(0x06F8) /* Transmitter¡¯s An 0x00 */ +#define S5P_HDCP_An_1_3 S5P_HDMI_BASE(0x06FC) /* Transmitter¡¯s An 0x00 */ + +#define S5P_HDCP_BCAPS S5P_HDMI_BASE(0x0700) /* Receiver¡¯s BCAPS 0x00 */ +#define S5P_HDCP_BSTATUS_0 S5P_HDMI_BASE(0x0710) /* Receiver¡¯s BSTATUS 0x00 */ +#define S5P_HDCP_BSTATUS_1 S5P_HDMI_BASE(0x0714) /* Receiver¡¯s BSTATUS 0x00 */ +#define S5P_HDCP_Ri_0 S5P_HDMI_BASE(0x0740) /* Transmitter¡¯s Ri 0x00 */ +#define S5P_HDCP_Ri_1 S5P_HDMI_BASE(0x0744) /* Transmitter¡¯s Ri 0x00 */ + +#define S5P_HDCP_I2C_INT S5P_HDMI_BASE(0x0780) /* HDCP I2C interrupt status */ +#define S5P_HDCP_AN_INT S5P_HDMI_BASE(0x0790) /* HDCP An interrupt status */ +#define S5P_HDCP_WDT_INT S5P_HDMI_BASE(0x07a0) /* HDCP Watchdog interrupt status */ +#define S5P_HDCP_RI_INT S5P_HDMI_BASE(0x07b0) /* HDCP RI interrupt status */ + +#define S5P_HDCP_RI_COMPARE_0 S5P_HDMI_BASE(0x07d0) /* HDCP Ri Interrupt Frame number index register 0 */ +#define S5P_HDCP_RI_COMPARE_1 S5P_HDMI_BASE(0x07d4) /* HDCP Ri Interrupt Frame number index register 1 */ +#define S5P_HDCP_FRAME_COUNT S5P_HDMI_BASE(0x07e0) /* Current value of the frame count index in the hardware */ + +#define HDMI_GAMUT_CON S5P_HDMI_BASE(0x0500) /* Gamut Metadata packet transmission control register */ +#define HDMI_GAMUT_HEADER0 S5P_HDMI_BASE(0x0504) /* Gamut metadata packet header */ +#define HDMI_GAMUT_HEADER1 S5P_HDMI_BASE(0x0508) /* Gamut metadata packet header */ +#define HDMI_GAMUT_HEADER2 S5P_HDMI_BASE(0x050c) /* Gamut metadata packet header */ +#define HDMI_GAMUT_DATA00 S5P_HDMI_BASE(0x0510) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA01 S5P_HDMI_BASE(0x0514) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA02 S5P_HDMI_BASE(0x0518) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA03 S5P_HDMI_BASE(0x051c) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA04 S5P_HDMI_BASE(0x0520) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA05 S5P_HDMI_BASE(0x0524) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA06 S5P_HDMI_BASE(0x0528) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA07 S5P_HDMI_BASE(0x052c) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA08 S5P_HDMI_BASE(0x0530) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA09 S5P_HDMI_BASE(0x0534) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA10 S5P_HDMI_BASE(0x0538) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA11 S5P_HDMI_BASE(0x053c) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA12 S5P_HDMI_BASE(0x0540) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA13 S5P_HDMI_BASE(0x0544) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA14 S5P_HDMI_BASE(0x0548) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA15 S5P_HDMI_BASE(0x054c) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA16 S5P_HDMI_BASE(0x0550) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA17 S5P_HDMI_BASE(0x0554) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA18 S5P_HDMI_BASE(0x0558) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA19 S5P_HDMI_BASE(0x055c) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA20 S5P_HDMI_BASE(0x0560) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA21 S5P_HDMI_BASE(0x0564) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA22 S5P_HDMI_BASE(0x0568) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA23 S5P_HDMI_BASE(0x056c) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA24 S5P_HDMI_BASE(0x0570) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA25 S5P_HDMI_BASE(0x0574) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA26 S5P_HDMI_BASE(0x0578) /* Gamut Metadata packet body data */ +#define HDMI_GAMUT_DATA27 S5P_HDMI_BASE(0x057c) /* Gamut Metadata packet body data */ + +#define S5P_HDMI_DC_CONTROL S5P_HDMI_BASE(0x05C0) /* Gamut Metadata packet body data */ +#define S5P_HDMI_VIDEO_PATTERN_GEN S5P_HDMI_BASE(0x05C4) /* Gamut Metadata packet body data */ +#define S5P_HDMI_HPD_GEN S5P_HDMI_BASE(0x05C8) /* Gamut Metadata packet body data */ + +#define S5P_TG_CMD S5P_HDMI_TG_BASE(0x0000) /* Command Register 0x00 */ +#define S5P_TG_H_FSZ_L S5P_HDMI_TG_BASE(0x0018) /* Horizontal Full Size 0x72 */ +#define S5P_TG_H_FSZ_H S5P_HDMI_TG_BASE(0x001C) /* Horizontal Full Size 0x06 */ +#define S5P_TG_HACT_ST_L S5P_HDMI_TG_BASE(0x0020) /* Horizontal Active Start 0x05 */ +#define S5P_TG_HACT_ST_H S5P_HDMI_TG_BASE(0x0024) /* Horizontal Active Start 0x01 */ +#define S5P_TG_HACT_SZ_L S5P_HDMI_TG_BASE(0x0028) /* Horizontal Active Size 0x00 */ +#define S5P_TG_HACT_SZ_H S5P_HDMI_TG_BASE(0x002C) /* Horizontal Active Size 0x05 */ +#define S5P_TG_V_FSZ_L S5P_HDMI_TG_BASE(0x0030) /* Vertical Full Line Size 0xEE */ +#define S5P_TG_V_FSZ_H S5P_HDMI_TG_BASE(0x0034) /* Vertical Full Line Size 0x02 */ +#define S5P_TG_VSYNC_L S5P_HDMI_TG_BASE(0x0038) /* Vertical Sync Position 0x01 */ +#define S5P_TG_VSYNC_H S5P_HDMI_TG_BASE(0x003C) /* Vertical Sync Position 0x00 */ +#define S5P_TG_VSYNC2_L S5P_HDMI_TG_BASE(0x0040) /* Vertical Sync Position for Bottom Field 0x33 */ +#define S5P_TG_VSYNC2_H S5P_HDMI_TG_BASE(0x0044) /* Vertical Sync Position for Bottom Field 0x02 */ +#define S5P_TG_VACT_ST_L S5P_HDMI_TG_BASE(0x0048) /* Vertical Sync Active Start Position 0x1a */ +#define S5P_TG_VACT_ST_H S5P_HDMI_TG_BASE(0x004C) /* Vertical Sync Active Start Position 0x00 */ +#define S5P_TG_VACT_SZ_L S5P_HDMI_TG_BASE(0x0050) /* Vertical Active Size 0xd0 */ +#define S5P_TG_VACT_SZ_H S5P_HDMI_TG_BASE(0x0054) /* Vertical Active Size 0x02 */ +#define S5P_TG_FIELD_CHG_L S5P_HDMI_TG_BASE(0x0058) /* Field Change Position 0x33 */ +#define S5P_TG_FIELD_CHG_H S5P_HDMI_TG_BASE(0x005C) /* Field Change Position 0x02 */ +#define S5P_TG_VACT_ST2_L S5P_HDMI_TG_BASE(0x0060) /* Vertical Sync Active Start Position for Bottom Field 0x48 */ +#define S5P_TG_VACT_ST2_H S5P_HDMI_TG_BASE(0x0064) /* Vertical Sync Active Start Position for Bottom Field 0x02 */ + +#define S5P_TG_VSYNC_TOP_HDMI_L S5P_HDMI_TG_BASE(0x0078) /* HDMI Vsync Positon for Top Field 0x01 */ +#define S5P_TG_VSYNC_TOP_HDMI_H S5P_HDMI_TG_BASE(0x007C) /* HDMI Vsync Positon for Top Field 0x00 */ +#define S5P_TG_VSYNC_BOT_HDMI_L S5P_HDMI_TG_BASE(0x0080) /* HDMI Vsync Positon for Bottom Field 0x33 */ +#define S5P_TG_VSYNC_BOT_HDMI_H S5P_HDMI_TG_BASE(0x0084) /* HDMI Vsync Positon for Bottom Field 0x02 */ +#define S5P_TG_FIELD_TOP_HDMI_L S5P_HDMI_TG_BASE(0x0088) /* HDMI Top Field Start Position 0x01 */ +#define S5P_TG_FIELD_TOP_HDMI_H S5P_HDMI_TG_BASE(0x008C) /* HDMI Top Field Start Position 0x00 */ +#define S5P_TG_FIELD_BOT_HDMI_L S5P_HDMI_TG_BASE(0x0090) /* HDMI Bottom Field Start Position 0x33 */ +#define S5P_TG_FIELD_BOT_HDMI_H S5P_HDMI_TG_BASE(0x0094) /* HDMI Bottom Field Start Position 0x02 */ + +#define S5P_EFUSE_CTRL S5P_HDMI_EFUSE_BASE(0x0000) +#define S5P_EFUSE_STATUS S5P_HDMI_EFUSE_BASE(0x0004) +#define S5P_EFUSE_ADDR_WIDTH S5P_HDMI_EFUSE_BASE(0x0008) +#define S5P_EFUSE_SIGDEV_ASSERT S5P_HDMI_EFUSE_BASE(0x000c) +#define S5P_EFUSE_SIGDEV_DEASSERT S5P_HDMI_EFUSE_BASE(0x0010) +#define S5P_EFUSE_PRCHG_ASSERT S5P_HDMI_EFUSE_BASE(0x0014) +#define S5P_EFUSE_PRCHG_DEASSERT S5P_HDMI_EFUSE_BASE(0x0018) +#define S5P_EFUSE_FSET_ASSERT S5P_HDMI_EFUSE_BASE(0x001c) +#define S5P_EFUSE_FSET_DEASSERT S5P_HDMI_EFUSE_BASE(0x0020) +#define S5P_EFUSE_SENSING S5P_HDMI_EFUSE_BASE(0x0024) +#define S5P_EFUSE_SCK_ASSERT S5P_HDMI_EFUSE_BASE(0x0028) +#define S5P_EFUSE_SCK_DEASSERT S5P_HDMI_EFUSE_BASE(0x002c) +#define S5P_EFUSE_SDOUT_OFFSET S5P_HDMI_EFUSE_BASE(0x0030) +#define S5P_EFUSE_READ_OFFSET S5P_HDMI_EFUSE_BASE(0x0034) + +#define S5P_HDMI_I2S_CLK_CON S5P_HDMI_I2S_BASE(0x0000) /* I2S Clock Enable Register0x00 */ +#define S5P_HDMI_I2S_CON_1 S5P_HDMI_I2S_BASE(0x0004) /* I2S Control Register 10x00 */ +#define S5P_HDMI_I2S_CON_2 S5P_HDMI_I2S_BASE(0x0008) /* I2S Control Register 20x00 */ +#define S5P_HDMI_I2S_PIN_SEL_0 S5P_HDMI_I2S_BASE(0x000C) /* I2S Input Pin Selection Register 0 0x77 */ +#define S5P_HDMI_I2S_PIN_SEL_1 S5P_HDMI_I2S_BASE(0x0010) /* I2S Input Pin Selection Register 1 0x77 */ +#define S5P_HDMI_I2S_PIN_SEL_2 S5P_HDMI_I2S_BASE(0x0014) /* I2S Input Pin Selection Register 2 0x77 */ +#define S5P_HDMI_I2S_PIN_SEL_3 S5P_HDMI_I2S_BASE(0x0018) /* I2S Input Pin Selection Register 30x07 */ +#define S5P_HDMI_I2S_DSD_CON S5P_HDMI_I2S_BASE(0x001C) /* I2S DSD Control Register0x02 */ +#define S5P_HDMI_I2S_MUX_CON S5P_HDMI_I2S_BASE(0x0020) /* I2S In/Mux Control Register 0x60 */ +#define S5P_HDMI_I2S_CH_ST_CON S5P_HDMI_I2S_BASE(0x0024) /* I2S Channel Status Control Register0x00 */ +#define S5P_HDMI_I2S_CH_ST_0 S5P_HDMI_I2S_BASE(0x0028) /* I2S Channel Status Block 00x00 */ +#define S5P_HDMI_I2S_CH_ST_1 S5P_HDMI_I2S_BASE(0x002C) /* I2S Channel Status Block 10x00 */ +#define S5P_HDMI_I2S_CH_ST_2 S5P_HDMI_I2S_BASE(0x0030) /* I2S Channel Status Block 20x00 */ +#define S5P_HDMI_I2S_CH_ST_3 S5P_HDMI_I2S_BASE(0x0034) /* I2S Channel Status Block 30x00 */ +#define S5P_HDMI_I2S_CH_ST_4 S5P_HDMI_I2S_BASE(0x0038) /* I2S Channel Status Block 40x00 */ +#define S5P_HDMI_I2S_CH_ST_SH_0 S5P_HDMI_I2S_BASE(0x003C) /* I2S Channel Status Block Shadow Register 00x00 */ +#define S5P_HDMI_I2S_CH_ST_SH_1 S5P_HDMI_I2S_BASE(0x0040) /* I2S Channel Status Block Shadow Register 10x00 */ +#define S5P_HDMI_I2S_CH_ST_SH_2 S5P_HDMI_I2S_BASE(0x0044) /* I2S Channel Status Block Shadow Register 20x00 */ +#define S5P_HDMI_I2S_CH_ST_SH_3 S5P_HDMI_I2S_BASE(0x0048) /* I2S Channel Status Block Shadow Register 30x00 */ +#define S5P_HDMI_I2S_CH_ST_SH_4 S5P_HDMI_I2S_BASE(0x004C) /* I2S Channel Status Block Shadow Register 40x00 */ +#define S5P_HDMI_I2S_VD_DATA S5P_HDMI_I2S_BASE(0x0050) /* I2S Audio Sample Validity Register0x00 */ +#define S5P_HDMI_I2S_MUX_CH S5P_HDMI_I2S_BASE(0x0054) /* I2S Channel Enable Register0x03 */ +#define S5P_HDMI_I2S_MUX_CUV S5P_HDMI_I2S_BASE(0x0058) /* I2S CUV Enable Register0x03 */ +#define S5P_HDMI_I2S_IRQ_MASK S5P_HDMI_I2S_BASE(0x005C) /* I2S Interrupt Request Mask Register0x03 */ +#define S5P_HDMI_I2S_IRQ_STATUS S5P_HDMI_I2S_BASE(0x0060) /* I2S Interrupt Request Status Register0x00 */ +#define S5P_HDMI_I2S_CH0_L_0 S5P_HDMI_I2S_BASE(0x0064) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH0_L_1 S5P_HDMI_I2S_BASE(0x0068) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH0_L_2 S5P_HDMI_I2S_BASE(0x006C) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH0_L_3 S5P_HDMI_I2S_BASE(0x0070) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH0_R_0 S5P_HDMI_I2S_BASE(0x0074) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH0_R_1 S5P_HDMI_I2S_BASE(0x0078) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH0_R_2 S5P_HDMI_I2S_BASE(0x007C) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH0_R_3 S5P_HDMI_I2S_BASE(0x0080) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_L_0 S5P_HDMI_I2S_BASE(0x0084) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_L_1 S5P_HDMI_I2S_BASE(0x0088) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_L_2 S5P_HDMI_I2S_BASE(0x008C) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_L_3 S5P_HDMI_I2S_BASE(0x0090) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_R_0 S5P_HDMI_I2S_BASE(0x0094) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_R_1 S5P_HDMI_I2S_BASE(0x0098) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_R_2 S5P_HDMI_I2S_BASE(0x009C) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH1_R_3 S5P_HDMI_I2S_BASE(0x00A0) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH2_L_0 S5P_HDMI_I2S_BASE(0x00A4) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH2_L_1 S5P_HDMI_I2S_BASE(0x00A8) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH2_L_2 S5P_HDMI_I2S_BASE(0x00AC) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH2_L_3 S5P_HDMI_I2S_BASE(0x00B0) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH2_R_0 S5P_HDMI_I2S_BASE(0x00B4) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH2_R_1 S5P_HDMI_I2S_BASE(0x00B8) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH2_R_2 S5P_HDMI_I2S_BASE(0x00BC) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_Ch2_R_3 S5P_HDMI_I2S_BASE(0x00C0) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH3_L_0 S5P_HDMI_I2S_BASE(0x00C4) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH3_L_1 S5P_HDMI_I2S_BASE(0x00C8) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH3_L_2 S5P_HDMI_I2S_BASE(0x00CC) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH3_R_0 S5P_HDMI_I2S_BASE(0x00D0) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH3_R_1 S5P_HDMI_I2S_BASE(0x00D4) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CH3_R_2 S5P_HDMI_I2S_BASE(0x00D8) /* I2S PCM Output Data Register0x00 */ +#define S5P_HDMI_I2S_CUV_L_R S5P_HDMI_I2S_BASE(0x00DC) /* I2S CUV Output Data Register0x00 */ + +#define S5P_SPDIFIN_CLK_CTRL S5P_HDMI_SPDIF_BASE(0x0000) /* SPDIFIN_CLK_CTRL [1:0] 0x02 */ +#define S5P_SPDIFIN_OP_CTRL S5P_HDMI_SPDIF_BASE(0x0004) /* SPDIFIN_OP_CTRL [1:0] 0x00 */ +#define S5P_SPDIFIN_IRQ_MASK S5P_HDMI_SPDIF_BASE(0x0008) /* SPDIFIN_IRQ_MASK[7:0] 0x00 */ +#define S5P_SPDIFIN_IRQ_STATUS S5P_HDMI_SPDIF_BASE(0x000C) /* SPDIFIN_IRQ_STATUS [7:0] 0x00 */ +#define S5P_SPDIFIN_CONFIG_1 S5P_HDMI_SPDIF_BASE(0x0010) /* SPDIFIN_CONFIG [7:0] 0x00 */ +#define S5P_SPDIFIN_CONFIG_2 S5P_HDMI_SPDIF_BASE(0x0014) /* SPDIFIN_CONFIG [11:8] 0x00 */ +#define S5P_SPDIFIN_USER_VALUE_1 S5P_HDMI_SPDIF_BASE(0x0020) /* SPDIFIN_USER_VALUE [7:0] 0x00 */ +#define S5P_SPDIFIN_USER_VALUE_2 S5P_HDMI_SPDIF_BASE(0x0024) /* SPDIFIN_USER_VALUE [15:8] 0x00 */ +#define S5P_SPDIFIN_USER_VALUE_3 S5P_HDMI_SPDIF_BASE(0x0028) /* SPDIFIN_USER_VALUE [23:16] 0x00 */ +#define S5P_SPDIFIN_USER_VALUE_4 S5P_HDMI_SPDIF_BASE(0x002C) /* SPDIFIN_USER_VALUE [31:24] 0x00 */ +#define S5P_SPDIFIN_CH_STATUS_0_1 S5P_HDMI_SPDIF_BASE(0x0030) /* SPDIFIN_CH_STATUS_0 [7:0] 0x00 */ +#define S5P_SPDIFIN_CH_STATUS_0_2 S5P_HDMI_SPDIF_BASE(0x0034) /* SPDIFIN_CH_STATUS_0 [15:8] 0x00 */ +#define S5P_SPDIFIN_CH_STATUS_0_3 S5P_HDMI_SPDIF_BASE(0x0038) /* SPDIFIN_CH_STATUS_0 [23:16] 0x00 */ +#define S5P_SPDIFIN_CH_STATUS_0_4 S5P_HDMI_SPDIF_BASE(0x003C) /* SPDIFIN_CH_STATUS_0 [31:24] 0x00 */ +#define S5P_SPDIFIN_CH_STATUS_1 S5P_HDMI_SPDIF_BASE(0x0040) /* SPDIFIN_CH_STATUS_1 0x00 */ +#define S5P_SPDIFIN_FRAME_PERIOD_1 S5P_HDMI_SPDIF_BASE(0x0048) /* SPDIF_FRAME_PERIOD [7:0] 0x00 */ +#define S5P_SPDIFIN_FRAME_PERIOD_2 S5P_HDMI_SPDIF_BASE(0x004C) /* SPDIF_FRAME_PERIOD [15:8] 0x00 */ +#define S5P_SPDIFIN_Pc_INFO_1 S5P_HDMI_SPDIF_BASE(0x0050) /* SPDIFIN_Pc_INFO [7:0] 0x00 */ +#define S5P_SPDIFIN_Pc_INFO_2 S5P_HDMI_SPDIF_BASE(0x0054) /* SPDIFIN_Pc_INFO [15:8] 0x00 */ +#define S5P_SPDIFIN_Pd_INFO_1 S5P_HDMI_SPDIF_BASE(0x0058) /* SPDIFIN_Pd_INFO [7:0] 0x00 */ +#define S5P_SPDIFIN_Pd_INFO_2 S5P_HDMI_SPDIF_BASE(0x005C) /* SPDIFIN_Pd_INFO [15:8] 0x00 */ +#define S5P_SPDIFIN_DATA_BUF_0_1 S5P_HDMI_SPDIF_BASE(0x0060) /* SPDIFIN_DATA_BUF_0 [7:0] 0x00 */ +#define S5P_SPDIFIN_DATA_BUF_0_2 S5P_HDMI_SPDIF_BASE(0x0064) /* SPDIFIN_DATA_BUF_0 [15:8] 0x00 */ +#define S5P_SPDIFIN_DATA_BUF_0_3 S5P_HDMI_SPDIF_BASE(0x0068) /* SPDIFIN_DATA_BUF_0 [23:16] 0x00 */ +#define S5P_SPDIFIN_USER_BUF_0 S5P_HDMI_SPDIF_BASE(0x006C) /* SPDIFIN_DATA_BUF_0 [31:28] 0x00 */ +#define S5P_SPDIFIN_DATA_BUF_1_1 S5P_HDMI_SPDIF_BASE(0x0070) /* SPDIFIN_DATA_BUF_1 [7:0] 0x00 */ +#define S5P_SPDIFIN_DATA_BUF_1_2 S5P_HDMI_SPDIF_BASE(0x0074) /* SPDIFIN_DATA_BUF_1 [15:8] 0x00 */ +#define S5P_SPDIFIN_DATA_BUF_1_3 S5P_HDMI_SPDIF_BASE(0x0078) /* SPDIFIN_DATA_BUF_1 [23:16] 0x00 */ +#define S5P_SPDIFIN_USER_BUF_1 S5P_HDMI_SPDIF_BASE(0x007C) /* SPDIFIN_DATA_BUF_1 [31:28] 0x00 */ + +/* HDMI_CON0 */ +#define BLUE_SCR_EN (1<<5) +#define BLUE_SCR_DIS (0<<5) +#define ASP_EN (1<<2) +#define ASP_DIS (0<<2) +#define PWDN_ENB_NORMAL (1<<1) +#define PWDN_ENB_PD (0<<1) +#define HDMI_EN (1<<0) +#define HDMI_DIS (~HDMI_EN) + +/* HDMI_CON1 */ +#define PX_LMT_CTRL_BYPASS (0<<5) +#define PX_LMT_CTRL_RGB (1<<5) +#define PX_LMT_CTRL_YPBPR (2<<5) +#define PX_LMT_CTRL_RESERVED (3<<5) + +/* HDMI_CON2 */ +#define VID_PREAMBLE_EN (0<<5) +#define VID_PREAMBLE_DIS (1<<5) +#define GUARD_BAND_EN (0<<1) +#define GUARD_BAND_DIS (1<<1) + +/* HDMI_STATUS */ +#define AUTHEN_ACK_AUTH (1<<7) +#define AUTHEN_ACK_NOT (0<<7) +#define AUD_FIFO_OVF_FULL (1<<6) +#define AUD_FIFO_OVF_NOT (0<<6) +#define UPDATE_RI_INT_OCC (1<<4) +#define UPDATE_RI_INT_NOT (0<<4) +#define UPDATE_RI_INT_CLEAR (1<<4) +#define UPDATE_PJ_INT_OCC (1<<3) +#define UPDATE_PJ_INT_NOT (0<<3) +#define UPDATE_PJ_INT_CLEAR (1<<3) +#define EXCHANGEKSV_INT_OCC (1<<2) +#define EXCHANGEKSV_INT_NOT (0<<2) +#define EXCHANGEKSV_INT_CLEAR (1<<2) +#define WATCHDOG_INT_OCC (1<<1) +#define WATCHDOG_INT_NOT (0<<1) +#define WATCHDOG_INT_CLEAR (1<<1) +#define WTFORACTIVERX_INT_OCC (1) +#define WTFORACTIVERX_INT_NOT (0) +#define WTFORACTIVERX_INT_CLEAR (1) + +/* HDMI_STATUS_EN */ +#define AUD_FIFO_OVF_EN (1<<6) +#define AUD_FIFO_OVF_DIS (0<<6) +#define UPDATE_RI_INT_EN (1<<4) +#define UPDATE_RI_INT_DIS (0<<4) +#define UPDATE_PJ_INT_EN (1<<3) +#define UPDATE_PJ_INT_DIS (0<<3) +#define EXCHANGEKSV_INT_EN (1<<2) +#define EXCHANGEKSV_INT_DIS (0<<2) +#define WATCHDOG_INT_EN (1<<1) +#define WATCHDOG_INT_DIS (0<<1) +#define WTFORACTIVERX_INT_EN (1) +#define WTFORACTIVERX_INT_DIS (0) +#define HDCP_STATUS_EN_ALL UPDATE_RI_INT_EN|\ + UPDATE_PJ_INT_DIS|\ + EXCHANGEKSV_INT_EN|\ + WATCHDOG_INT_EN|\ + WTFORACTIVERX_INT_EN + +#define HDCP_STATUS_DIS_ALL (~0x1f) + +/* HDMI_HPD */ +#define SW_HPD_PLUGGED (1<<1) +#define SW_HPD_UNPLUGGED (0<<1) + +/* HDMI_MODE_SEL */ +#define HDMI_MODE_EN (1<<1) +#define HDMI_MODE_DIS (0<<1) +#define DVI_MODE_EN (1) +#define DVI_MODE_DIS (0) + +/* HDCP_ENC_EN */ +#define HDCP_ENC_ENABLE (1) +#define HDCP_ENC_DISABLE (0) + +/* HDMI_BLUE_SCREEN0 */ +#define SET_BLUESCREEN_0(a) (0xff&(a)) + +/* HDMI_BLUE_SCREEN1 */ +#define SET_BLUESCREEN_1(a) (0xff&(a)) + +/* HDMI_BLUE_SCREEN2 */ +#define SET_BLUESCREEN_2(a) (0xff&(a)) + +/* HDMI_YMAX */ +#define SET_HDMI_YMAX(a) (0xff&(a)) + +/* HDMI_YMIN */ +#define SET_HDMI_YMIN(a) (0xff&(a)) + +/* HDMI_CMAX */ +#define SET_HDMI_CMAX(a) (0xff&(a)) + +/* HDMI_CMIN */ +#define SET_HDMI_CMIN(a) (0xff&(a)) + +/* HDMI_DI_PREFIX */ + +/* HDMI_VBI_ST_MG */ +#define SET_VBI_ST_MG(a) (0xff&(a)) + +/* HDMI_VBI_END_MG */ +#define SET_VBI_END_MG(a) (0xff&(a)) + +/* HDMI_VACT_ST_MG */ +#define SET_VACT_ST_MG(a) (0xff&(a)) + +/* HDMI_VACT_END_MG + HDMI_AUTH_ST_MG0 + HDMI_AUTH_ST_MG1 + HDMI_AUTH_END_MG0 + HDMI_AUTH_END_MG1 */ + +/* HDMI_H_BLANK0 */ +#define SET_H_BLANK_L(a) (0xff&(a)) + +/* HDMI_H_BLANK1 */ +#define SET_H_BLANK_H(a) (0x7&((a)>>8)) + +/* HDMI_V_BLANK0 */ +#define SET_V2_BLANK_L(a) (0xff&(a)) + +/* HDMI_V_BLANK1 */ +#define SET_V1_BLANK_L(a) ((0x1f&(a))<<3) +#define SET_V2_BLANK_H(a) (0x7&((a)>>8)) + +/* HDMI_V_BLANK2 */ +#define SET_V1_BLANK_H(a) (0x3f&((a)>>5)) + +/* HDMI_H_V_LINE0 */ +#define SET_V_LINE_L(a) (0xff&(a)) + +/* HDMI_H_V_LINE1 */ +#define SET_H_LINE_L(a) ((0xf&(a))<<4) +#define SET_V_LINE_H(a) (0xf&((a)>>8)) + +/* HDMI_H_V_LINE2 */ +#define SET_H_LINE_H(a) (0xff&((a)>>4)) + +/* HDMI_SYNC_MODE */ +#define V_SYNC_POL_ACT_LOW (1) +#define V_SYNC_POL_ACT_HIGH (0) + +/* HDMI_INT_PRO_MODE */ +#define INT_PRO_MODE_INTERLACE (1) +#define INT_PRO_MODE_PROGRESSIVE (0) + +/* HDMI_SEND_PER_START0 + HDMI_SEND_PER_START1 + HDMI_SEND_PER_END0 */ +#define SET_V_BOT_ST_L(a) (0xff&(a)) + +/* HDMI_SEND_PER_END1 */ +#define SET_V_BOT_END_L(a) ((0x1f&(a))<<3) +#define SET_V_BOT_ST_H(a) (0x7&((a)>>8)) + +/* HDMI_SEND_PER_END2 */ +#define SET_V_BOT_END_H(a) (0x3f&((a)>>5)) + +/* HDMI_V_BLANK_INTERLACE + HDMI_V_BLANK_INTERLACE + HDMI_V_BLANK_INTERLACE */ + +/* HDMI_H_SYNC_GEN0 */ +#define SET_HSYNC_START_L(a) (0xff&(a)) + +/* HDMI_H_SYNC_GEN1 */ +#define SET_HSYNC_END_L(a) ((0x3f&(a))<<2) +#define SET_HSYNC_START_H(a) (0x3&((a)>>8)) + +/* HDMI_H_SYNC_GEN2 */ +#define SET_HSYNC_POL_ACT_LOW (1<<4) +#define SET_HSYNC_POL_ACT_HIGH (0<<4) +#define SET_HSYNC_END_H(a) (0xf&((a)>>6)) + +/* HDMI_V_SYNC_GEN1_0 */ +#define SET_VSYNC_T_END_L(a) (0xff&(a)) + +/* HDMI_V_SYNC_GEN1_1 */ +#define SET_VSYNC_T_ST_L(a) ((0xf&(a))<<4) +#define SET_VSYNC_T_END_H(a) (0xf&((a)>>8)) + +/* HDMI_V_SYNC_GEN1_2 */ +#define SET_VSYNC_T_ST_H(a) (0xff&((a)>>4)) + +/* HDMI_V_SYNC_GEN2_0 */ +#define SET_VSYNC_B_END_L(a) (0xff&(a)) + +/* HDMI_V_SYNC_GEN2_1 */ +#define SET_VSYNC_B_ST_L(a) ((0xf&(a))<<4) +#define SET_VSYNC_B_END_H(a) (0xf&((a)>>8)) + +/* HDMI_V_SYNC_GEN2_2 */ +#define SET_VSYNC_B_ST_H(a) (0xff&((a)>>4)) + + +/* HDMI_V_SYNC_GEN3_0 */ +#define SET_VSYNC_H_POST_END_L(a) (0xff&(a)) + +/* HDMI_V_SYNC_GEN3_1 */ +#define SET_VSYNC_H_POST_ST_L(a) ((0xf&(a))<<4) +#define SET_VSYNC_H_POST_END_H(a) (0xf&((a)>>8)) + +/* HDMI_V_SYNC_GEN3_2 */ +#define SET_VSYNC_H_POST_ST_H(a) (0xff&((a)>>4)) + + +/* Audio releated packet register + HDMI_ASP_CON */ +#define SACD_EN (1<<5) +#define SACD_DIS (0<<5) +#define AUD_MODE_MULTI_CH (1<<4) +#define AUD_MODE_2_CH (0<<4) +#define SET_SP_PRE(a) (0xf&(a)) + +/* HDMI_ASP_SP_FLAT */ +#define SET_SP_FLAT(a) (0xf&(a)) + +/* HDMI_ASP_CHCFG0 + HDMI_ASP_CHCFG1 + HDMI_ASP_CHCFG2 + HDMI_ASP_CHCFG3 */ +#define SPK3R_SEL_I_PCM0L (0<<27) +#define SPK3R_SEL_I_PCM0R (1<<27) +#define SPK3R_SEL_I_PCM1L (2<<27) +#define SPK3R_SEL_I_PCM1R (3<<27) +#define SPK3R_SEL_I_PCM2L (4<<27) +#define SPK3R_SEL_I_PCM2R (5<<27) +#define SPK3R_SEL_I_PCM3L (6<<27) +#define SPK3R_SEL_I_PCM3R (7<<27) +#define SPK3L_SEL_I_PCM0L (0<<24) +#define SPK3L_SEL_I_PCM0R (1<<24) +#define SPK3L_SEL_I_PCM1L (2<<24) +#define SPK3L_SEL_I_PCM1R (3<<24) +#define SPK3L_SEL_I_PCM2L (4<<24) +#define SPK3L_SEL_I_PCM2R (5<<24) +#define SPK3L_SEL_I_PCM3L (6<<24) +#define SPK3L_SEL_I_PCM3R (7<<24) +#define SPK2R_SEL_I_PCM0L (0<<19) +#define SPK2R_SEL_I_PCM0R (1<<19) +#define SPK2R_SEL_I_PCM1L (2<<19) +#define SPK2R_SEL_I_PCM1R (3<<19) +#define SPK2R_SEL_I_PCM2L (4<<19) +#define SPK2R_SEL_I_PCM2R (5<<19) +#define SPK2R_SEL_I_PCM3L (6<<19) +#define SPK2R_SEL_I_PCM3R (7<<19) +#define SPK2L_SEL_I_PCM0L (0<<16) +#define SPK2L_SEL_I_PCM0R (1<<16) +#define SPK2L_SEL_I_PCM1L (2<<16) +#define SPK2L_SEL_I_PCM1R (3<<16) +#define SPK2L_SEL_I_PCM2L (4<<16) +#define SPK2L_SEL_I_PCM2R (5<<16) +#define SPK2L_SEL_I_PCM3L (6<<16) +#define SPK2L_SEL_I_PCM3R (7<<16) +#define SPK1R_SEL_I_PCM0L (0<<11) +#define SPK1R_SEL_I_PCM0R (1<<11) +#define SPK1R_SEL_I_PCM1L (2<<11) +#define SPK1R_SEL_I_PCM1R (3<<11) +#define SPK1R_SEL_I_PCM2L (4<<11) +#define SPK1R_SEL_I_PCM2R (5<<11) +#define SPK1R_SEL_I_PCM3L (6<<11) +#define SPK1R_SEL_I_PCM3R (7<<11) +#define SPK1L_SEL_I_PCM0L (0<<8) +#define SPK1L_SEL_I_PCM0R (1<<8) +#define SPK1L_SEL_I_PCM1L (2<<8) +#define SPK1L_SEL_I_PCM1R (3<<8) +#define SPK1L_SEL_I_PCM2L (4<<8) +#define SPK1L_SEL_I_PCM2R (5<<8) +#define SPK1L_SEL_I_PCM3L (6<<8) +#define SPK1L_SEL_I_PCM3R (7<<8) +#define SPK0R_SEL_I_PCM0L (0<<3) +#define SPK0R_SEL_I_PCM0R (1<<3) +#define SPK0R_SEL_I_PCM1L (2<<3) +#define SPK0R_SEL_I_PCM1R (3<<3) +#define SPK0R_SEL_I_PCM2L (4<<3) +#define SPK0R_SEL_I_PCM2R (5<<3) +#define SPK0R_SEL_I_PCM3L (6<<3) +#define SPK0R_SEL_I_PCM3R (7<<3) +#define SPK0L_SEL_I_PCM0L (0) +#define SPK0L_SEL_I_PCM0R (1) +#define SPK0L_SEL_I_PCM1L (2) +#define SPK0L_SEL_I_PCM1R (3) +#define SPK0L_SEL_I_PCM2L (4) +#define SPK0L_SEL_I_PCM2R (5) +#define SPK0L_SEL_I_PCM3L (6) +#define SPK0L_SEL_I_PCM3R (7) + +/* HDMI_ACR_CON */ +#define ALT_CTS_RATE_CTS_1 (0<<3) +#define ALT_CTS_RATE_CTS_11 (1<<3) +#define ALT_CTS_RATE_CTS_21 (2<<3) +#define ALT_CTS_RATE_CTS_31 (3<<3) +#define ACR_TX_MODE_NO_TX (0) +#define ACR_TX_MODE_TX_ONCE (1) +#define ACR_TX_MODE_TXCNT_VBI (2) +#define ACR_TX_MODE_TX_VPC (3) +#define ACR_TX_MODE_MESURE_CTS (4) + +/* HDMI_ACR_MCTS0 + HDMI_ACR_MCTS1 + HDMI_ACR_MCTS2 */ +#define SET_ACR_MCTS(a) (0xfffff&(a)) + +/* HDMI_ACR_CTS0 + HDMI_ACR_CTS1 + HDMI_ACR_CTS2 */ +#define SET_ACR_CTS(a) (0xfffff&(a)) + +/* HDMI_ACR_N0 + HDMI_ACR_N1 + HDMI_ACR_N2 */ +#define SET_ACR_N(a) (0xfffff&(a)) + +/* HDMI_ACR_LSB2 */ +#define SET_ACR_LSB2(a) (0xff&(a)) + +/* HDMI_ACR_TXCNT */ +#define SET_ACR_TXCNT(a) (0x1f&(a)) + +/* HDMI_ACR_TXINTERNAL */ +#define SET_ACR_TX_INTERNAL(a) (0xff&(a)) + +/* HDMI_ACR_CTS_OFFSET */ +#define SET_ACR_CTS_OFFSET(a) (0xff&(a)) + +/* HDMI_GCP_CON */ +#define GCP_CON_NO_TRAN (0) +#define GCP_CON_TRANS_ONCE (1) +#define GCP_CON_TRANS_EVERY_VSYNC (2) + +/* HDMI_GCP_BYTE1 */ +#define SET_GCP_BYTE1(a) (0xff&(a)) + + +/* ACP and ISRC1/2 packet registers + HDMI_ACP_CON */ +#define SET_ACP_FR_RATE(a) ((0x1f&(a))<<3) +#define ACP_CON_NO_TRAN (0) +#define ACP_CON_TRANS_ONCE (1) +#define ACP_CON_TRANS_EVERY_VSYNC (2) + +/* HDMI_ACP_TYPE */ +#define SET_ACP_TYPE(a) (0xff&(a)) + + +/* HDMI_ACP_DATA0 + HDMI_ACP_DATA1 + HDMI_ACP_DATA2 + HDMI_ACP_DATA3 + HDMI_ACP_DATA4 + HDMI_ACP_DATA5 + HDMI_ACP_DATA6 + HDMI_ACP_DATA7 + HDMI_ACP_DATA8 + HDMI_ACP_DATA9 + HDMI_ACP_DATA10 + HDMI_ACP_DATA11 + HDMI_ACP_DATA12 + HDMI_ACP_DATA13 + HDMI_ACP_DATA14 + HDMI_ACP_DATA15 + HDMI_ACP_DATA16 */ +#define SET_ACP_DATA(a) (0xff&(a)) + + +/* HDMI_ISRC_CON */ +#define SET_ISRC_FR_RATE(a) ((0x1f&(a))<<3) +#define ISRC_EN (1<<2) +#define ISRC_DIS (0<<2) +#define ISRC_TX_CON_NO_TRANS (0) +#define ISRC_TX_CON_TRANS_ONCE (1) +#define ISRC_TX_CON_TRANS_EVERY_VSYNC (2) + +/* HDMI_ISRC1_HEADER1 */ +#define SET_ISRC1_HEADER(a) (0xff&(a)) + +/* HDMI_ISRC1_DATA0 + HDMI_ISRC1_DATA1 + HDMI_ISRC1_DATA2 + HDMI_ISRC1_DATA3 + HDMI_ISRC1_DATA4 + HDMI_ISRC1_DATA5 + HDMI_ISRC1_DATA6 + HDMI_ISRC1_DATA7 + HDMI_ISRC1_DATA8 + HDMI_ISRC1_DATA9 + HDMI_ISRC1_DATA10 + HDMI_ISRC1_DATA11 + HDMI_ISRC1_DATA12 + HDMI_ISRC1_DATA13 + HDMI_ISRC1_DATA14 + HDMI_ISRC1_DATA15 */ +#define SET_ISRC1_DATA(a) (0xff&(a)) + +/* HDMI_ISRC2_DATA0 + HDMI_ISRC2_DATA1 + HDMI_ISRC2_DATA2 + HDMI_ISRC2_DATA3 + HDMI_ISRC2_DATA4 + HDMI_ISRC2_DATA5 + HDMI_ISRC2_DATA6 + HDMI_ISRC2_DATA7 + HDMI_ISRC2_DATA8 + HDMI_ISRC2_DATA9 + HDMI_ISRC2_DATA10 + HDMI_ISRC2_DATA11 + HDMI_ISRC2_DATA12 + HDMI_ISRC2_DATA13 + HDMI_ISRC2_DATA14 + HDMI_ISRC2_DATA15 */ +#define SET_ISRC2_DATA(a) (0xff&(a)) + + +/* AVI info-frame registers + HDMI_AVI_CON */ +#define AVI_TX_CON_NO_TRANS (0) +#define AVI_TX_CON_TRANS_ONCE (1) +#define AVI_TX_CON_TRANS_EVERY_VSYNC (2) + + +/* HDMI_AVI_CHECK_SUM */ +#define SET_AVI_CHECK_SUM(a) (0xff&(a)) + +#define HDMI_CON_PXL_REP_RATIO_MASK (1<<1 | 1<<0) +#define HDMI_DOUBLE_PIXEL_REPETITION (0x01) +#define AVI_PIXEL_REPETITION_DOUBLE (1<<0) +#define AVI_PICTURE_ASPECT_4_3 (1<<4) +#define AVI_PICTURE_ASPECT_16_9 (1<<5) + +/* HDMI_AVI_BYTE1 + HDMI_AVI_BYTE2 + HDMI_AVI_BYTE3 + HDMI_AVI_BYTE4 + HDMI_AVI_BYTE5 + HDMI_AVI_BYTE6 + HDMI_AVI_BYTE7 + HDMI_AVI_BYTE8 + HDMI_AVI_BYTE9 + HDMI_AVI_BYTE10 + HDMI_AVI_BYTE11 + HDMI_AVI_BYTE12 + HDMI_AVI_BYTE13 */ +#define SET_AVI_BYTE(a) (0xff&(a)) + +/* Audio info-frame registers + HDMI_AUI_CON */ +#define AUI_TX_CON_NO_TRANS (0) +#define AUI_TX_CON_TRANS_ONCE (1) +#define AUI_TX_CON_TRANS_EVERY_VSYNC (2) + +/* HDMI_AUI_CHECK_SUM + HDMI_AVI_CHECK_SUM */ +#define SET_AUI_CHECK_SUM(a) (0xff&(a)) + +/* HDMI_AUI_BYTE1 + HDMI_AUI_BYTE2 + HDMI_AUI_BYTE3 + HDMI_AUI_BYTE4 + HDMI_AUI_BYTE5 */ +#define SET_AUI_BYTE(a) (0xff&(a)) + +/* MPEG source info-frame registers + HDMI_MPG_CON */ +#define MPG_TX_CON_NO_TRANS (0) +#define MPG_TX_CON_TRANS_ONCE (1) +#define MPG_TX_CON_TRANS_EVERY_VSYNC (2) + +/* HDMI_MPG_CHECK_SUM */ +#define SET_MPG_CHECK_SUM(a) (0xff&(a)) + +/* HDMI_MPG_BYTE1 + HDMI_MPG_BYTE2 + HDMI_MPG_BYTE3 + HDMI_MPG_BYTE4 + HDMI_MPG_BYTE5 */ +#define SET_MPG_BYTE(a) (0xff&(a)) + +/* Souerce product desciptor info-f + HDMI_SPD_CON */ +#define SPD_TX_CON_NO_TRANS (0) +#define SPD_TX_CON_TRANS_ONCE (1) +#define SPD_TX_CON_TRANS_EVERY_VSYNC (2) + +/* HDMI_SPD_HEADER0 + HDMI_SPD_HEADER1 + HDMI_SPD_HEADER2 */ +#define SET_SPD_HEADER(a) (0xff&(a)) + +/* HDMI_SPD_DATA0 + HDMI_SPD_DATA1 + HDMI_SPD_DATA2 + HDMI_SPD_DATA3 + HDMI_SPD_DATA4 + HDMI_SPD_DATA5 + HDMI_SPD_DATA6 + HDMI_SPD_DATA7 + HDMI_SPD_DATA8 + HDMI_SPD_DATA9 + HDMI_SPD_DATA10 + HDMI_SPD_DATA11 + HDMI_SPD_DATA12 + HDMI_SPD_DATA13 + HDMI_SPD_DATA14 + HDMI_SPD_DATA15 + HDMI_SPD_DATA16 + HDMI_SPD_DATA17 + HDMI_SPD_DATA18 + HDMI_SPD_DATA19 + HDMI_SPD_DATA20 + HDMI_SPD_DATA21 + HDMI_SPD_DATA22 + HDMI_SPD_DATA23 + HDMI_SPD_DATA24 + HDMI_SPD_DATA25 + HDMI_SPD_DATA26 + HDMI_SPD_DATA27 */ +#define SET_SPD_DATA(a) (0xff&(a)) + + +/* HDMI_CSC_CON */ +#define OUT_OFFSET_SEL_RGB_FR (0<<4) +#define OUT_OFFSET_SEL_RGB_LR (2<<4) +#define OUT_OFFSET_SEL_YCBCR (3<<4) +#define IN_CLIP_EN (1<<2) +#define IN_CLIP_DIS (0<<2) +#define IN_OFFSET_SEL_RGB_FR (0) +#define IN_OFFSET_SEL_RGB_LR (2) +#define IN_OFFSET_SEL_YCBCR (3) + +/* HDMI_Y_G_COEF_L + HDMI_Y_G_COEF_H + HDMI_Y_B_COEF_L + HDMI_Y_B_COEF_H + HDMI_Y_R_COEF_L + HDMI_Y_R_COEF_H + HDMI_CB_G_COEF_L + HDMI_CB_G_COEF_H + HDMI_CB_B_COEF_L + HDMI_CB_B_COEF_H + HDMI_CB_R_COEF_L + HDMI_CB_R_COEF_H + HDMI_CR_G_COEF_L + HDMI_CR_G_COEF_H + HDMI_CR_B_COEF_L + HDMI_CR_B_COEF_H + HDMI_CR_R_COEF_L + HDMI_CR_R_COEF_H */ +#define SET_HDMI_CSC_COEF_L(a) (0xff&(a)) +#define SET_HDMI_CSC_COEF_H(a) (0x3&((a)>>8)) + +/* Test pattern generation register + HDMI_TPGEN_0 + HDMI_TPGEN_1 + HDMI_TPGEN_2 + HDMI_TPGEN_3 + HDMI_TPGEN_4 + HDMI_TPGEN_5 + HDMI_TPGEN_6 + + HDCP_RX_SHA_1_0_0 + HDCP_RX_SHA_1_0_1 + HDCP_RX_SHA_1_0_2 + HDCP_RX_SHA_1_0_3 + HDCP_RX_SHA_1_1_0 + HDCP_RX_SHA_1_1_1 + HDCP_RX_SHA_1_1_2 + HDCP_RX_SHA_1_1_3 + HDCP_RX_SHA_1_2_0 + HDCP_RX_SHA_1_2_1 + HDCP_RX_SHA_1_2_2 + HDCP_RX_SHA_1_2_3 + HDCP_RX_SHA_1_3_0 + HDCP_RX_SHA_1_3_1 + HDCP_RX_SHA_1_3_2 + HDCP_RX_SHA_1_3_3 + HDCP_RX_SHA_1_4_0 + HDCP_RX_SHA_1_4_1 + HDCP_RX_SHA_1_4_2 + HDCP_RX_SHA_1_4_3 */ +#define SET_HDMI_SHA1(a) (0xff&(a)) + +/* HDCP_RX_KSV_0_0 + HDCP_RX_KSV_0_1 + HDCP_RX_KSV_0_2 + HDCP_RX_KSV_0_3 + HDCP_RX_KSV_1_0 + HDCP_RX_KSV_1_1 + + HDCP_AUTH_STAT + + HDCP_CTRL + + HDCP_CHECK_RESULT + + HDCP_BKSV0_0 + HDCP_BKSV0_1 + HDCP_BKSV0_2 + HDCP_BKSV0_3 + HDCP_BKSV1 + HDCP_AKSV0_0 + HDCP_AKSV0_1 + HDCP_AKSV0_2 + HDCP_AKSV0_3 + HDCP_AKSV1 + + HDCP_AN0_0 + HDCP_AN0_1 + HDCP_AN0_2 + HDCP_AN0_3 + HDCP_AN1_0 + HDCP_AN1_1 + HDCP_AN1_2 + HDCP_AN1_3 + + HDCP_BCAPS + HDCP_BSTATUS0 + HDCP_BSTATUS1 + + HDCP_RI_0 + HDCP_RI_1 + HDCP_PJ + + HDCP_OFFSET_TX0 + HDCP_OFFSET_TX1 + HDCP_OFFSET_TX2 + HDCP_OFFSET_TX3 + HDCP_CYCLE_AA + HDCP_I2C_INT + HDCP_AN_INT + HDCP_WATCHDOG_INT + HDCP_RI_INT + HDCP_PJ_INT + + TG SFR + TG_CMD */ +#define GETSYNC_TYPE_EN (1<<4) +#define GETSYNC_TYPE_DIS (~GETSYNC_TYPE_EN) +#define GETSYNC_EN (1<<3) +#define GETSYNC_DIS (~GETSYNC_EN) +#define FIELD_EN (1<<1) +#define FIELD_DIS (~FIELD_EN) +#define TG_EN (1) +#define TG_DIS (~TG_EN) + +/* TG_CFG + TG_CB_SZ + TG_INDELAY_L + TG_INDELAY_H + TG_POL_CTRL + + TG_H_FSZ_L */ +#define SET_TG_H_FSZ_L(a) (0xff&(a)) + +/* TG_H_FSZ_H */ +#define SET_TG_H_FSZ_H(a) (0x1f&((a)>>8)) + +/* TG_HACT_ST_L */ +#define SET_TG_HACT_ST_L(a) (0xff&(a)) + +/* TG_HACT_ST_H */ +#define SET_TG_HACT_ST_H(a) (0xf&((a)>>8)) + +/* TG_HACT_SZ_L */ +#define SET_TG_HACT_SZ_L(a) (0xff&(a)) + +/* TG_HACT_SZ_H */ +#define SET_TG_HACT_SZ_H(a) (0xf&((a)>>8)) + +/* TG_V_FSZ_L */ +#define SET_TG_V_FSZ_L(a) (0xff&(a)) + +/* TG_V_FSZ_H */ +#define SET_TG_V_FSZ_H(a) (0x7&((a)>>8)) + +/* TG_VSYNC_L */ +#define SET_TG_VSYNC_L(a) (0xff&(a)) + +/* TG_VSYNC_H */ +#define SET_TG_VSYNC_H(a) (0x7&((a)>>8)) + +/* TG_VSYNC2_L */ +#define SET_TG_VSYNC2_L(a) (0xff&(a)) + +/* TG_VSYNC2_H */ +#define SET_TG_VSYNC2_H(a) (0x7&((a)>>8)) + +/* TG_VACT_ST_L */ +#define SET_TG_VACT_ST_L(a) (0xff&(a)) + +/* TG_VACT_ST_H */ +#define SET_TG_VACT_ST_H(a) (0x7&((a)>>8)) + +/* TG_VACT_SZ_L */ +#define SET_TG_VACT_SZ_L(a) (0xff&(a)) + +/* TG_VACT_SZ_H */ +#define SET_TG_VACT_SZ_H(a) (0x7&((a)>>8)) + +/* TG_FIELD_CHG_L */ +#define SET_TG_FIELD_CHG_L(a) (0xff&(a)) + +/* TG_FIELD_CHG_H */ +#define SET_TG_FIELD_CHG_H(a) (0x7&((a)>>8)) + +/* TG_VACT_ST2_L */ +#define SET_TG_VACT_ST2_L(a) (0xff&(a)) + +/* TG_VACT_ST2_H */ +#define SET_TG_VACT_ST2_H(a) (0x7&((a)>>8)) + +/* TG_VACT_SC_ST_L + TG_VACT_SC_ST_H + TG_VACT_SC_SZ_L + TG_VACT_SC_SZ_H + + TG_VSYNC_TOP_HDMI_L */ +#define SET_TG_VSYNC_TOP_HDMI_L(a) (0xff&(a)) + +/* TG_VSYNC_TOP_HDMI_H */ +#define SET_TG_VSYNC_TOP_HDMI_H(a) (0x7&((a)>>8)) + +/* TG_VSYNC_BOT_HDMI_L */ +#define SET_TG_VSYNC_BOT_HDMI_L(a) (0xff&(a)) + +/* TG_VSYNC_BOT_HDMI_H */ +#define SET_TG_VSYNC_BOT_HDMI_H(a) (0x7&((a)>>8)) + +/* TG_FIELD_TOP_HDMI_L */ +#define SET_TG_FIELD_TOP_HDMI_L(a) (0xff&(a)) + +/* TG_FIELD_TOP_HDMI_H */ +#define SET_TG_FIELD_TOP_HDMI_H(a) (0x7&((a)>>8)) + +/* TG_FIELD_BOT_HDMI_L */ +#define SET_TG_FIELD_BOT_HDMI_L(a) (0xff&(a)) + +/* TG_FIELD_BOT_HDMI_H */ +#define SET_TG_FIELD_BOT_HDMI_H(a) (0x7&((a)>>8)) + +/* TG_HSYNC_HDOUT_ST_L + TG_HSYNC_HDOUT_ST_H + TG_HSYNC_HDOUT_END_L + TG_HSYNC_HDOUT_END_H + TG_VSYNC_HDOUT_ST_L + TG_VSYNC_HDOUT_ST_H + TG_VSYNC_HDOUT_END_L + TG_VSYNC_HDOUT_END_H + TG_VSYNC_HDOUT_DLY_L + TG_VSYNC_HDOUT_DLY_H + TG_BT_ERR_RANGE + TG_BT_ERR_RESULT + TG_COR_THR + TG_COR_NUM + TG_BT_CON + TG_BT_H_FSZ_L + TG_BT_H_FSZ_H + TG_BT_HSYNC_ST + TG_BT_HSYNC_SZ + TG_BT_FSZ_L + TG_BT_FSZ_H + TG_BT_VACT_T_ST_L + TG_BT_VACT_T_ST_H + TG_BT_VACT_B_ST_L + TG_BT_VACT_B_ST_H + TG_BT_VACT_SZ_L + TG_BT_VACT_SZ_H + TG_BT_VSYNC_SZ + SPDIFIN_CLK_CTRL + SPDIFIN_OP_CTRL + + SPDIFIN_IRQ_MASK */ +#define IRQ_WRONG_SIGNAL_ENABLE (1<<0) +#define IRQ_CH_STATUS_RECOVERED_ENABLE (1<<1) +#define IRQ_WRONG_PREAMBLE_ENABLE (1<<2) +#define IRQ_STREAM_HEADER_NOT_DETECTED_ENABLE (1<<3) +#define IRQ_STREAM_HEADER_DETECTED_ENABLE (1<<4) +#define IRQ_STREAM_HEADER_NOT_DETECTED_AT_RIGHTTIME_ENABLE (1<<5) +#define IRQ_ABNORMAL_PD_ENABLE (1<<6) +#define IRQ_BUFFER_OVERFLOW_ENABLE (1<<7) + +/* SPDIFIN_IRQ_STATUS +SPDIFIN_CONFIG_1 */ + +#define CONFIG_FILTER_3_SAMPLE (0<<6) +#define CONFIG_FILTER_2_SAMPLE (1<<6) +#define CONFIG_LINEAR_PCM_TYPE (0<<5) +#define CONFIG_NON_LINEAR_PCM_TYPE (1<<5) +#define CONFIG_PCPD_AUTO_SET (0<<4) +#define CONFIG_PCPD_MANUAL_SET (1<<4) +#define CONFIG_WORD_LENGTH_AUTO_SET (0<<3) +#define CONFIG_WORD_LENGTH_MANUAL_SET (1<<3) +#define CONFIG_U_V_C_P_NEGLECT (0<<2) +#define CONFIG_U_V_C_P_REPORT (1<<2) +#define CONFIG_BURST_SIZE_1 (0<<1) +#define CONFIG_BURST_SIZE_2 (1<<1) +#define CONFIG_DATA_ALIGN_16BIT (0<<0) +#define CONFIG_DATA_ALIGN_32BIT (1<<0) + +/* SPDIFIN_CONFIG_2 + SPDIFIN_USER_VALUE_1 + SPDIFIN_USER_VALUE_2 + SPDIFIN_USER_VALUE_3 + SPDIFIN_USER_VALUE_4 + SPDIFIN_CH_STATUS_0_1 + SPDIFIN_CH_STATUS_0_2 + SPDIFIN_CH_STATUS_0_3 + SPDIFIN_CH_STATUS_0_4 + SPDIFIN_CH_STATUS_1 + SPDIFIN_FRAME_PERIOD_1 + SPDIFIN_FRAME_PERIOD_2 + SPDIFIN_PC_INFO_1 + SPDIFIN_PC_INFO_2 + SPDIFIN_PD_INFO_1 + SPDIFIN_PD_INFO_2 + SPDIFIN_DATA_BUF_0_1 + SPDIFIN_DATA_BUF_0_2 + SPDIFIN_DATA_BUF_0_3 + SPDIFIN_USER_BUF_0 + SPDIFIN_USER_BUF_1_1 + SPDIFIN_USER_BUF_1_2 + SPDIFIN_USER_BUF_1_3 + SPDIFIN_USER_BUF_1 + + HAES_START + HAES_DATA_SIZE_L + HAES_DATA_SIZE_H + HAES_DATA */ + +/* Macros - for HDCP */ + +/* HDMI SYSTEM STATUS FLAG REGISTER (STATUS, R/W, ADDRESS = 0XF030_0010) */ +#define AUTHEN_ACK_POS 7 +#define AUD_FIFO_OVF_POS 6 +/* RESERVED 5 */ +#define UPDATE_RI_INT_POS 4 +#define UPDATE_PJ_INT_POS 3 +#define EXCHANGEKSV_INT_POS 2 +#define WATCHDOG_INT_POS 1 +#define WTFORACTIVERX_INT_POS 0 + +#define AUTHENTICATED (0x1 << 7) +#define NOT_YET_AUTHENTICATED (0x0 << 7) +#define AUD_FIFO_OVF_INT_OCCURRED (0x1 << 6) +#define AUD_FIFO_OVF_INT_NOT_OCCURRED (0x0 << 6) +/* RESERVED 5 */ +#define UPDATE_RI_INT_OCCURRED (0x1 << 4) +#define UPDATE_RI_INT_NOT_OCCURRED (0x0 << 4) +#define UPDATE_PJ_INT_OCCURRED (0x1 << 3) +#define UPDATE_PJ_INT_NOT_OCCURRED (0x0 << 3) +#define EXCHANGEKSV_INT_OCCURRED (0x1 << 2) +#define EXCHANGEKSV_INT_NOT_OCCURRED (0x0 << 2) +#define WATCHDOG_INT_OCCURRED (0x1 << 1) +#define WATCHDOG_INT_NOT_OCCURRED (0x0 << 1) +#define WTFORACTIVERX_INT_OCCURRED (0x1 << 0) +#define WTFORACTIVERX_INT_NOT_OCCURRED (0x0 << 0) + +/* HDMI SYSTEM STATUS ENABLE REGISTER (STATUS_EN, R/W, ADDRESS = 0XF030_0020) */ +/* RESERVED 7 */ +#define AUD_FIFO_OVF_INT_EN (0x1 << 6) +#define AUD_FIFO_OVF_INT_DIS (0x0 << 6) +/* RESERVED 5 */ + +/* EFUSE CONTROL REGISTER */ +#define EFUSE_CTRL_ACTIVATE (1) +#define EFUSE_ADDR_WIDTH (240) +#define EFUSE_SIGDEV_ASSERT (0) +#define EFUSE_SIGDEV_DEASSERT (96) +#define EFUSE_PRCHG_ASSERT (0) +#define EFUSE_PRCHG_DEASSERT (144) +#define EFUSE_FSET_ASSERT (48) +#define EFUSE_FSET_DEASSERT (192) +#define EFUSE_SENSING (240) +#define EFUSE_SCK_ASSERT (48) +#define EFUSE_SCK_DEASSERT (144) +#define EFUSE_SDOUT_OFFSET (192) +#define EFUSE_READ_OFFSET (192) + +#define EFUSE_ECC_DONE (1<<0) +#define EFUSE_ECC_BUSY (1<<1) +#define EFUSE_ECC_FAIL (1<<2) + +/* HDCP CONTROL REGISTER (HDCP_CTRL1, R/W, ADDRESS = 0XF030_ 0680) */ +#define EN_PJ_EN (0x1 << 4) +#define EN_PJ_DIS (~EN_PJ_EN) +/* RESERVED 3 */ +#define SET_REPEATER_TIMEOUT (0x1 << 2) +#define CLEAR_REPEATER_TIMEOUT (~SET_REPEATER_TIMEOUT) +#define CP_DESIRED_EN (0x1 << 1) +#define CP_DESIRED_DIS (~CP_DESIRED_EN) +#define ENABLE_1_DOT_1_FEATURE_EN (0x1 << 0) +#define ENABLE_1_DOT_1_FEATURE_DIS (~ENABLE_1_DOT_1_FEATURE_EN) + +/* HDCP_CHECK_RESULT, R/W, ADDRESS = 0XF030_ 0690 */ +#define Pi_MATCH_RESULT__YES ((0x1<<3) | (0x1<<2)) +#define Pi_MATCH_RESULT__NO ((0x1<<3) | (0x0<<2)) +#define Ri_MATCH_RESULT__YES ((0x1<<1) | (0x1<<0)) +#define Ri_MATCH_RESULT__NO ((0x1<<1) | (0x0<<0)) +#define CLEAR_ALL_RESULTS 0x0 + +/* HDCP ENCRYPTION ENABLE REGISTER (ENC_EN, R/W, ADDRESS = 0XF030_0044) */ +#define HDCP_ENC_DIS (0x0 << 0) + +/* BCAPS INFORMATION FROM RX. THIS VALUE IS THE DATA READ FROM RX + * (HDCP_BCAPS, R/W,ADDRESS = 0XF030_0700) + RESERVED 7 */ +#define REPEATER_SET (0x1 << 6) +#define REPEATERP_CLEAR (0x1 << 6) +#define READY_SET (0x1 << 5) +#define READY_CLEAR (0x1 << 5) +#define FAST_SET (0x1 << 4) +#define FAST_CLEAR (0x1 << 4) +/* RESERVED 3 + RESERVED 2 */ +#define ONE_DOT_ONE_FEATURES_SET (0x1 << 1) +#define ONE_DOT_ONE_FEATURES_CLEAR (0x1 << 1) +#define FAST_REAUTHENTICATION_SET (0x1 << 0) +#define FAST_REAUTHENTICATION_CLEAR (0x1 << 0) + +/* HAES REGISTERS + HAES CONTROL */ +#define SCRAMBLER_KEY_START_EN (0x1 << 7) +#define SCRAMBLER_KEY_START_DIS (~SCRAMBLER_KEY_START_EN) +#define SCRAMBLER_KEY_DONE (0x1 << 6) +#define SCRAMBLER_KEY_GENERATING (0x0 << 6) +/* RESERVED 1<-->5 */ +#define HAES_START_EN (0x1 << 0) +#define HAES_DECRYPTION_DONE (0x0 << 0) + +#define AN_SIZE 8 +#define AKSV_SIZE 5 +#define BKSV_SIZE 5 +#define HDCPLink_Addr 0x74 + +#define CABLE_PLUGGED 1<<1 +#define CABLE_UNPLUGGED 0<<1 + +#define DDC_Addr 0xA0 +#define eDDC_Addr 0x60 +#define HDCPLink_Addr 0x74 + +#define HDCP_Bksv 0x00 +#define HDCP_Aksv 0x10 +#define HDCP_Ainfo 0x15 +#define HDCP_An 0x18 +#define HDCP_Ri 0x08 +#define HDCP_Bcaps 0x40 +#define HDCP_BStatus 0x41 +#define HDCP_Pj 0x0a + +#define HDCP_KSVFIFO 0x43 +#define HDCP_SHA1 0x20 + +#define HDMI_MODE_HDMI 0 +#define HDMI_MODE_DVI 1 + +#define EDID_SEGMENT_ID 0x60 +#define EDID_SEGMENT0 0x00 +#define EDID_SEGMENT1 0x01 + +#define EDID_DEVICE_ID 0xA0 +#define EDID_ADDR_START 0x00 +#define EDID_ADDR_EXT 0x80 +#define EDID_RCOUNT 127 + +#define EDID_POS_EXTENSION 0x7E +#define EDID_POS_CHECKSUM 0x7F +/* #define EDID_POS_ERROR 516 // 512+1 // move to hdmi.h by shin...1229 */ +#define VALID_EDID 0xA5 +#define NO_VALID_EDID 0 + +#define EDID_POS_RBUFFER0 0x00 //segment0, 128-byte +#define EDID_POS_RBUFFER1 0x80 //segment0, 256-byte +#define EDID_POS_RBUFFER2 0x100 //segment1, 128-byte +#define EDID_POS_RBUFFER3 0x180 //segment1, 256-byte + +#define EDID_TIMING_EXT_TAG_ADDR_POS 0x80 +#define EDID_TIMING_EXT_REV_NUMBER 0x81 +#define EDID_DETAILED_TIMING_OFFSET_POS 0x82 +#define EDID_COLOR_SPACE_ADDR 0x83 +#define EDID_DATA_BLOCK_ADDRESS 0x84 +#define EDID_TIMING_EXT_TAG_VAL 0x02 +#define EDID_YCBCR444_CS_MASK 0x20 +#define EDID_YCBCR422_CS_MASK 0x10 +#define EDID_TAG_CODE_MASK 0xE0 +#define EDID_DATA_BLOCK_SIZE_MASK 0x1F +#define EDID_NATIVE_RESOLUTION_MASK 0x80 + +#define EDID_SHORT_AUD_DEC_TAG 0x20 +#define EDID_SHORT_VID_DEC_TAG 0x40 +#define EDID_HDMI_VSDB_TAG 0x60 +#define EDID_SPEAKER_ALLOCATION_TAG 0x80 + +#define COLOR_SPACE_RGB 0 +#define COLOR_SPACE_YCBCR444 1 +#define COLOR_SPACE_YCBCR422 2 + +#define SHORT_VID_720_480P_4_3_NT 0x01 +#define SHORT_VID_720_480P_16_9_NT 0x02 +#define SHORT_VID_1280_720P_16_9_NT 0x04 +#define SHORT_VID_1920_1080i_16_9_NT 0x08 +#define SHORT_VID_720_576P_4_3_PAL 0x10 +#define SHORT_VID_720_576P_16_9_PAL 0x20 +#define SHORT_VID_1280_720P_16_9_PAL 0x40 +#define SHORT_VID_1920_1080i_16_9_PAL 0x80 + +#define SET_HDMI_RESOLUTION_480P 0x00 +#define SET_HDMI_RESOLUTION_720P 0x01 +#define SET_HDMI_RESOLUTION_1080i 0x02 + +#define HDMI_WAIT_TIMEOUT 20 +#define AUTHENTICATION_SUCCESS 0 +#define AUTHENTICATION_FAILURE 1 +#define AUTHENTICATION_FAIL_CNT 2 + +#define HDCP_MAX_DEVS 128 +#define HDCP_KSV_SIZE 5 + +#define CMD_IIC_ADDRMODE_CHANGE 0xFF + +/* IIC Addressing Mode Definition */ +#define IIC_ADDRMODE_1 0 +#define IIC_ADDRMODE_2 1 +#define IIC_ADDRMODE_3 2 +#define HDMI_IIC_ADDRMODE IIC_ADDRMODE_1 + +#define IIC_ACK 0 +#define IIC_NOACK 1 + +#define EDID_POS_ERROR 512 +#define R_VAL_RETRY_CNT 5 + +#define CABLE_INSERT 1 +#define CABLE_REMOVE (~CABLE_INSERT) + +#define HDMI_PHY_READY (1<<0) + +/* Color Depth + CD0, CD1, CD2, CD3 */ + +#define GCP_CD_NOT_INDICATED 0 +#define GCP_CD_24BPP (1<<2) +#define GCP_CD_30BPP (1<<0 | 1<<2) +#define GCP_CD_36BPP (1<<1 | 1<<2) +#define GCP_CD_48BPP (1<<0 | 1<<1 | 1<<2) + +#define GCP_DEFAULT_PHASE 1 + +/* for DC_CONTRAL */ +#define HDMI_DC_CTL_8 0 +#define HDMI_DC_CTL_10 (1<<0) +#define HDMI_DC_CTL_12 (1<<1) + +#define DO_NOT_TRANSMIT (0) + +#define HPD_SW_ENABLE (1<<0) +#define HPD_SW_DISABLE (0) +#define HPD_ON (1<<1) +#define HPD_OFF (0) + + +#endif /* __ASM_ARCH_REGS_HDMI_H */ + + diff --git a/drivers/media/video/samsung/tv20/s5pv210/regs/regs-sdaout.h b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-sdaout.h new file mode 100644 index 0000000..2553b57 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-sdaout.h @@ -0,0 +1,517 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-sdout.h + * + * TV Encoder register header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_SDAOUT_H + +#include <mach/map.h> + +#define S5P_SDAOUT_BASE(x) (x) +/* + Registers +*/ +#define S5P_SDO_CLKCON S5P_SDAOUT_BASE(0x0000) // Clock Control Register 0x0000_0000 +#define S5P_SDO_CONFIG S5P_SDAOUT_BASE(0x0008) // Video Standard Configuration Register 0x0024_2430 +#define S5P_SDO_SCALE S5P_SDAOUT_BASE(0x000C) // Video Scale Configuration Register 0x0000_0006 +#define S5P_SDO_SYNC S5P_SDAOUT_BASE(0x0010) // Video Sync Configuration Register 0x0000_0001 +#define S5P_SDO_VBI S5P_SDAOUT_BASE(0x0014) // VBI Configuration Register 0x0007_77FF +#define S5P_SDO_SCALE_CH0 S5P_SDAOUT_BASE(0x001C) // Scale Control Register for DAC Channel0 0x0000_0800 +#define S5P_SDO_SCALE_CH1 S5P_SDAOUT_BASE(0x0020) // Scale Control Register for DAC Channel1 0x0000_0800 +#define S5P_SDO_SCALE_CH2 S5P_SDAOUT_BASE(0x0024) // Scale Control Register for DAC Channel2 0x0000_0800 +#define S5P_SDO_YCDELAY S5P_SDAOUT_BASE(0x0034) // Video Delay Control Register 0x0000_FA00 +#define S5P_SDO_SCHLOCK S5P_SDAOUT_BASE(0x0038) // SCH Phase Control Register 0x0000_0000 +#define S5P_SDO_DAC S5P_SDAOUT_BASE(0x003C) // DAC Configuration Register 0x0000_0000 +#define S5P_SDO_FINFO S5P_SDAOUT_BASE(0x0040) // Status Register 0x0000_0002 +#define S5P_SDO_Y0 S5P_SDAOUT_BASE(0x0044) // Y- AAF 1¡¯st and 23¡¯th Coefficient (AAF : Anti-Aliasing Filter) 0x0000_0000 +#define S5P_SDO_Y1 S5P_SDAOUT_BASE(0x0048) // Y- AAF 2¡¯nd and 22¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y2 S5P_SDAOUT_BASE(0x004C) // Y- AAF 3¡¯rd and 21¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y3 S5P_SDAOUT_BASE(0x0050) // Y- AAF 4¡¯th and 20¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y4 S5P_SDAOUT_BASE(0x0054) // Y- AAF 5¡¯th and 19¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y5 S5P_SDAOUT_BASE(0x0058) // Y- AAF 6¡¯th and 18¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y6 S5P_SDAOUT_BASE(0x005C) // Y- AAF 7¡¯th and 17¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y7 S5P_SDAOUT_BASE(0x0060) // Y- AAF 8¡¯th and 16¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y8 S5P_SDAOUT_BASE(0x0064) // Y - AAF 9¡¯th and 15¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y9 S5P_SDAOUT_BASE(0x0068) // Y- AAF 10¡¯th and 14¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y10 S5P_SDAOUT_BASE(0x006C) // Y- AAF 11¡¯th and 13¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_Y11 S5P_SDAOUT_BASE(0x0070) // Y- AAF 12¡¯th Coefficient 0x0000_025D +#define S5P_SDO_CB0 S5P_SDAOUT_BASE(0x0080) // CB- AAF 1¡¯st and 23¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CB1 S5P_SDAOUT_BASE(0x0084) // CB- AAF 2¡¯nd and 22¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CB2 S5P_SDAOUT_BASE(0x0088) // CB- AAF 3¡¯rd and 21¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CB3 S5P_SDAOUT_BASE(0x008C) // CB-AAF 4¡¯th and 20¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CB4 S5P_SDAOUT_BASE(0x0090) // CB- AAF 5¡¯th and 19¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CB5 S5P_SDAOUT_BASE(0x0094) // CB- AAF 6¡¯th and 18¡¯th Coefficient 0x0000_0001 +#define S5P_SDO_CB6 S5P_SDAOUT_BASE(0x0098) // CB- AAF 7¡¯th and 17¡¯th Coefficient 0x0000_0007 +#define S5P_SDO_CB7 S5P_SDAOUT_BASE(0x009C) // CB- AAF 8¡¯th and 16¡¯th Coefficient 0x0000_0014 +#define S5P_SDO_CB8 S5P_SDAOUT_BASE(0x00A0) // CB- AAF 9¡¯th and 15¡¯th Coefficient 0x0000_0028 +#define S5P_SDO_CB9 S5P_SDAOUT_BASE(0x00A4) // CB- AAF 10¡¯th and 14¡¯th Coefficient 0x0000_003F +#define S5P_SDO_CB10 S5P_SDAOUT_BASE(0x00A8) // CB- AAF 11¡¯th and 13¡¯th Coefficient 0x0000_0052 +#define S5P_SDO_CB11 S5P_SDAOUT_BASE(0x00AC) // CB- AAF 12¡¯th Coefficient 0x0000_005A +#define S5P_SDO_CR0 S5P_SDAOUT_BASE(0x00C0) // CR- AAF 1¡¯st and 23¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CR1 S5P_SDAOUT_BASE(0x00C4) // CR- AAF 2¡¯nd and 22¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CR2 S5P_SDAOUT_BASE(0x00C8) // CR- AAF 3¡¯rd and 21¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CR3 S5P_SDAOUT_BASE(0x00CC) // CR-AAF 4¡¯th and 20¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CR4 S5P_SDAOUT_BASE(0x00D0) // CR- AAF 5¡¯th and 19¡¯th Coefficient 0x0000_0000 +#define S5P_SDO_CR5 S5P_SDAOUT_BASE(0x00D4) // CR- AAF 6¡¯th and 18¡¯th Coefficient 0x0000_0001 +#define S5P_SDO_CR6 S5P_SDAOUT_BASE(0x00D8) // CR- AAF 7¡¯th and 17¡¯th Coefficient 0x0000_0009 +#define S5P_SDO_CR7 S5P_SDAOUT_BASE(0x00DC) // CR- AAF 8¡¯th and 16¡¯th Coefficient 0x0000_001C +#define S5P_SDO_CR8 S5P_SDAOUT_BASE(0x00E0) // CR- AAF 9¡¯th and 15¡¯th Coefficient 0x0000_0039 +#define S5P_SDO_CR9 S5P_SDAOUT_BASE(0x00E4) // CR- AAF 10¡¯th and 14¡¯th Coefficient 0x0000_005A +#define S5P_SDO_CR10 S5P_SDAOUT_BASE(0x00E8) // CR- AAF 11¡¯th and 13¡¯th Coefficient 0x0000_0074 +#define S5P_SDO_CR11 S5P_SDAOUT_BASE(0x00EC) // CR- AAF 12¡¯th Coefficient 0x0000_007E +#define S5P_SDO_MV_ON S5P_SDAOUT_BASE(0x0100) +#define S5P_SDO_MV_SLINE_FIRST_EVEN S5P_SDAOUT_BASE(0x0104) +#define S5P_SDO_MV_SLINE_FIRST_SPACE_EVEN S5P_SDAOUT_BASE(0x0108) +#define S5P_SDO_MV_SLINE_FIRST_ODD S5P_SDAOUT_BASE(0x010C) +#define S5P_SDO_MV_SLINE_FIRST_SPACE_ODD S5P_SDAOUT_BASE(0x0110) +#define S5P_SDO_MV_SLINE_SPACING S5P_SDAOUT_BASE(0x0114) +#define S5P_SDO_MV_STRIPES_NUMBER S5P_SDAOUT_BASE(0x0118) +#define S5P_SDO_MV_STRIPES_THICKNESS S5P_SDAOUT_BASE(0x011C) +#define S5P_SDO_MV_PSP_DURATION S5P_SDAOUT_BASE(0x0120) +#define S5P_SDO_MV_PSP_FIRST S5P_SDAOUT_BASE(0x0124) +#define S5P_SDO_MV_PSP_SPACING S5P_SDAOUT_BASE(0x0128) +#define S5P_SDO_MV_SEL_LINE_PSP_AGC S5P_SDAOUT_BASE(0x012C) +#define S5P_SDO_MV_SEL_FORMAT_PSP_AGC S5P_SDAOUT_BASE(0x0130) +#define S5P_SDO_MV_PSP_AGC_A_ON S5P_SDAOUT_BASE(0x0134) +#define S5P_SDO_MV_PSP_AGC_B_ON S5P_SDAOUT_BASE(0x0138) +#define S5P_SDO_MV_BACK_PORCH S5P_SDAOUT_BASE(0x013C) +#define S5P_SDO_MV_BURST_ADVANCED_ON S5P_SDAOUT_BASE(0x0140) +#define S5P_SDO_MV_BURST_DURATION_ZONE1 S5P_SDAOUT_BASE(0x0144) +#define S5P_SDO_MV_BURST_DURATION_ZONE2 S5P_SDAOUT_BASE(0x0148) +#define S5P_SDO_MV_BURST_DURATION_ZONE3 S5P_SDAOUT_BASE(0x014C) +#define S5P_SDO_MV_BURST_PHASE_ZONE S5P_SDAOUT_BASE(0x0150) +#define S5P_SDO_MV_SLICE_PHASE_LINE S5P_SDAOUT_BASE(0x0154) +#define S5P_SDO_MV_RGB_PROTECTION_ON S5P_SDAOUT_BASE(0x0158) +#define S5P_SDO_MV_480P_PROTECTION_ON S5P_SDAOUT_BASE(0x015C) +#define S5P_SDO_CCCON S5P_SDAOUT_BASE(0x0180) // Color Compensation On/ Off Control 0x0000_0000 +#define S5P_SDO_YSCALE S5P_SDAOUT_BASE(0x0184) // Brightness Control for Y 0x0080_0000 +#define S5P_SDO_CBSCALE S5P_SDAOUT_BASE(0x0188) // Hue/ Saturation Control for CB 0x0080_0000 +#define S5P_SDO_CRSCALE S5P_SDAOUT_BASE(0x018C) // Hue/ Saturation Control for CR 0x0000_0080 +#define S5P_SDO_CB_CR_OFFSET S5P_SDAOUT_BASE(0x0190) // Hue/ Sat Offset Control for CB/CR 0x0000_0000 +#define S5P_SDO_RGB_CC S5P_SDAOUT_BASE(0x0194) // Color Compensation of RGB Output 0x0000_EB10 +#define S5P_SDO_CVBS_CC_Y1 S5P_SDAOUT_BASE(0x0198) // Color Compensation of CVBS Output 0x0200_0000 +#define S5P_SDO_CVBS_CC_Y2 S5P_SDAOUT_BASE(0x019C) // Color Compensation of CVBS Output 0x03FF_0200 +#define S5P_SDO_CVBS_CC_C S5P_SDAOUT_BASE(0x01A0) // Color Compensation of CVBS Output 0x0000_01FF +#define S5P_SDO_YC_CC_Y S5P_SDAOUT_BASE(0x01A4) // Color Compensation of S-video Output 0x03FF_0000 +#define S5P_SDO_YC_CC_C S5P_SDAOUT_BASE(0x01A8) // Color Compensation of S-video Output 0x0000_01FF +#define S5P_SDO_CSC_525_PORCH S5P_SDAOUT_BASE(0x01B0) // Porch Position Control of CSC in 525 Line 0x008A_0359 +#define S5P_SDO_CSC_625_PORCH S5P_SDAOUT_BASE(0x01B4) // Porch Position Control of CSC in 625 Line 0x0096_035C +#define S5P_SDO_RGBSYNC S5P_SDAOUT_BASE(0x01C0) // VESA RGB Sync Control Register 0x0000_0000 +#define S5P_SDO_OSFC00_0 S5P_SDAOUT_BASE(0x0200) // OverSampling Filter (OSF) Coefficient 1 & 0. of channel #0 0x00FD_00FE +#define S5P_SDO_OSFC01_0 S5P_SDAOUT_BASE(0x0204) // OSF Coefficient 3 & 2 of Channel #0 0x0000_0000 +#define S5P_SDO_OSFC02_0 S5P_SDAOUT_BASE(0x0208) // OSF Coefficient 5 & 4 of Channel #0 0x0005_0004 +#define S5P_SDO_OSFC03_0 S5P_SDAOUT_BASE(0x020C) // OSF Coefficient 7 & 6 of Channel #0 0x0000_00FF +#define S5P_SDO_OSFC04_0 S5P_SDAOUT_BASE(0x0210) // OSF Coefficient 9 & 8 of Channel #0 0x00F7_00FA +#define S5P_SDO_OSFC05_0 S5P_SDAOUT_BASE(0x0214) // OSF Coefficient 11 & 10 of Channel #0 0x0000_0001 +#define S5P_SDO_OSFC06_0 S5P_SDAOUT_BASE(0x0218) // OSF Coefficient 13 & 12 of Channel #0 0x000E_000A +#define S5P_SDO_OSFC07_0 S5P_SDAOUT_BASE(0x021C) // OSF Coefficient 15 & 14 of Channel #0 0x0000_01FF +#define S5P_SDO_OSFC08_0 S5P_SDAOUT_BASE(0x0220) // OSF Coefficient 17 & 16 of Channel #0 0x01EC_01F2 +#define S5P_SDO_OSFC09_0 S5P_SDAOUT_BASE(0x0224) // OSF Coefficient 19 & 18 of Channel #0 0x0000_0001 +#define S5P_SDO_OSFC10_0 S5P_SDAOUT_BASE(0x0228) // OSF Coefficient 21 & 20 of Channel #0 0x001D_0014 +#define S5P_SDO_OSFC11_0 S5P_SDAOUT_BASE(0x022C) // OSF Coefficient 23 & 22 of Channel #0 0x0000_01FE +#define S5P_SDO_OSFC12_0 S5P_SDAOUT_BASE(0x0230) // OSF Coefficient 25 & 24 of Channel #0 0x03D8_03E4 +#define S5P_SDO_OSFC13_0 S5P_SDAOUT_BASE(0x0234) // OSF Coefficient 27 & 26 of Channel #0 0x0000_0002 +#define S5P_SDO_OSFC14_0 S5P_SDAOUT_BASE(0x0238) // OSF Coefficient 29 & 28 of Channel #0 0x0038_0028 +#define S5P_SDO_OSFC15_0 S5P_SDAOUT_BASE(0x023C) // OSF Coefficient 31 & 30 of Channel #0 0x0000_03FD +#define S5P_SDO_OSFC16_0 S5P_SDAOUT_BASE(0x0240) // OSF Coefficient 33 & 32 of Channel #0 0x03B0_03C7 +#define S5P_SDO_OSFC17_0 S5P_SDAOUT_BASE(0x0244) // OSF Coefficient 35 & 34 of Channel #0 0x0000_0005 +#define S5P_SDO_OSFC18_0 S5P_SDAOUT_BASE(0x0248) // OSF Coefficient 37 & 36 of Channel #0 0x0079_0056 +#define S5P_SDO_OSFC19_0 S5P_SDAOUT_BASE(0x024C) // OSF Coefficient 39 & 38 of Channel #0 0x0000_03F6 +#define S5P_SDO_OSFC20_0 S5P_SDAOUT_BASE(0x0250) // OSF Coefficient 41 & 40 of Channel #0 0x072C_0766 +#define S5P_SDO_OSFC21_0 S5P_SDAOUT_BASE(0x0254) // OSF Coefficient 43 & 42 of Channel #0 0x0000_001B +#define S5P_SDO_OSFC22_0 S5P_SDAOUT_BASE(0x0258) // OSF Coefficient 45 & 44 of Channel #0 0x028B_0265 +#define S5P_SDO_OSFC23_0 S5P_SDAOUT_BASE(0x025C) // OSF Coefficient 47 & 46 of Channel #0 0x0400_0ECC +#define S5P_SDO_XTALK0 S5P_SDAOUT_BASE(0x0260) // Crosstalk Cancel Coefficient for Ch.0 0x0000_0000 +#define S5P_SDO_XTALK1 S5P_SDAOUT_BASE(0x0264) // Crosstalk Cancel Coefficient for Ch.1 0x0000_0000 +#define S5P_SDO_XTALK2 S5P_SDAOUT_BASE(0x0268) // Crosstalk Cancel Coefficient for Ch.2 0x0000_0000 +#define S5P_SDO_BB_CTRL S5P_SDAOUT_BASE(0x026C) // Blackburst Test Control 0x0001_1A00 +#define S5P_SDO_IRQ S5P_SDAOUT_BASE(0x0280) // Interrupt Request Register 0x0000_0000 +#define S5P_SDO_IRQMASK S5P_SDAOUT_BASE(0x0284) // Interrupt Request Enable Register 0x0000_0000 +#define S5P_SDO_OSFC00_1 S5P_SDAOUT_BASE(0x02C0) // OverSampling Filter (OSF) Coefficient 1 & 0. of Channel #1 0x00FD_00FE +#define S5P_SDO_OSFC01_1 S5P_SDAOUT_BASE(0x02C4) // OSF Coefficient 3 & 2 of Channel #1 0x0000_0000 +#define S5P_SDO_OSFC02_1 S5P_SDAOUT_BASE(0x02C8) // OSF Coefficient 5 & 4 of Channel #1 0x0005_0004 +#define S5P_SDO_OSFC03_1 S5P_SDAOUT_BASE(0x02CC) // OSF Coefficient 7 & 6 of Channel #1 0x0000_00FF +#define S5P_SDO_OSFC04_1 S5P_SDAOUT_BASE(0x02D0) // OSF Coefficient 9 & 8 of Channel #1 0x00F7_00FA +#define S5P_SDO_OSFC05_1 S5P_SDAOUT_BASE(0x02D4) // OSF Coefficient 11 & 10 of Channel #1 0x0000_0001 +#define S5P_SDO_OSFC06_1 S5P_SDAOUT_BASE(0x02D8) // OSF Coefficient 13 & 12 of Channel #1 0x000E_000A +#define S5P_SDO_OSFC07_1 S5P_SDAOUT_BASE(0x02DC) // OSF Coefficient 15 & 14 of Channel #1 0x0000_01FF +#define S5P_SDO_OSFC08_1 S5P_SDAOUT_BASE(0x02E0) // OSF Coefficient 17 & 16 of Channel #1 0x01EC_01F2 +#define S5P_SDO_OSFC09_1 S5P_SDAOUT_BASE(0x02E4) // OSF Coefficient 19 & 18 of Channel #1 0x0000_0001 +#define S5P_SDO_OSFC10_1 S5P_SDAOUT_BASE(0x02E8) // OSF Coefficient 21 & 20 of Channel #1 0x001D_0014 +#define S5P_SDO_OSFC11_1 S5P_SDAOUT_BASE(0x02EC) // OSF Coefficient 23 & 22 of Channel #1 0x0000_01FE +#define S5P_SDO_OSFC12_1 S5P_SDAOUT_BASE(0x02E0) // OSF Coefficient 25 & 24 of Channel #1 0x03D8_03E4 +#define S5P_SDO_OSFC13_1 S5P_SDAOUT_BASE(0x02F4) // OSF Coefficient 27 & 26 of Channel #1 0x0000_0002 +#define S5P_SDO_OSFC14_1 S5P_SDAOUT_BASE(0x02F8) // OSF Coefficient 29 & 28 of Channel #1 0x0038_0028 +#define S5P_SDO_OSFC15_1 S5P_SDAOUT_BASE(0x02FC) // OSF Coefficient 31 & 30 of Channel #1 0x0000_03FD +#define S5P_SDO_OSFC16_1 S5P_SDAOUT_BASE(0x0300) // OSF Coefficient 33 & 32 of Channel #1 0x03B0_03C7 +#define S5P_SDO_OSFC17_1 S5P_SDAOUT_BASE(0x0304) // OSF Coefficient 35 & 34 of Channel #1 0x0000_0005 +#define S5P_SDO_OSFC18_1 S5P_SDAOUT_BASE(0x0308) // OSF Coefficient 37 & 36 of Channel #1 0x0079_0056 +#define S5P_SDO_OSFC19_1 S5P_SDAOUT_BASE(0x030C) // OSF Coefficient 39 & 38 of Channel #1 0x0000_03F6 +#define S5P_SDO_OSFC20_1 S5P_SDAOUT_BASE(0x0310) // OSF Coefficient 41 & 40 of Channel #1 0x072C_0766 +#define S5P_SDO_OSFC21_1 S5P_SDAOUT_BASE(0x0314) // OSF Coefficient 43 & 42 of Channel #1 0x0000_001B +#define S5P_SDO_OSFC22_1 S5P_SDAOUT_BASE(0x0318) // OSF Coefficient 45 & 44 of Channel #1 0x028B_0265 +#define S5P_SDO_OSFC23_1 S5P_SDAOUT_BASE(0x031C) // OSF Coefficient 47 & 46 of Channel #1 0x0400_0ECC +#define S5P_SDO_OSFC00_2 S5P_SDAOUT_BASE(0x0320) // OverSampling Filter (OSF) Coefficient 1 & 0. of Channel #2 0x00FD_00FE +#define S5P_SDO_OSFC01_2 S5P_SDAOUT_BASE(0x0324) // OSF Coefficient 3 & 2 of Channel #2 0x0000_0000 +#define S5P_SDO_OSFC02_2 S5P_SDAOUT_BASE(0x0328) // OSF Coefficient 5 & 4 of Channel #2 0x0005_0004 +#define S5P_SDO_OSFC03_2 S5P_SDAOUT_BASE(0x032C) // OSF Coefficient 7 & 6 of Channel #2 0x0000_00FF +#define S5P_SDO_OSFC04_2 S5P_SDAOUT_BASE(0x0330) // OSF Coefficient 9 & 8 of Channel #2 0x00F7_00FA +#define S5P_SDO_OSFC05_2 S5P_SDAOUT_BASE(0x0334) // OSF Coefficient 11 & 10 of Channel #2 0x0000_0001 +#define S5P_SDO_OSFC06_2 S5P_SDAOUT_BASE(0x0338) // OSF Coefficient 13 & 12 of Channel #2 0x000E_000A +#define S5P_SDO_OSFC07_2 S5P_SDAOUT_BASE(0x033C) // OSF Coefficient 15 & 14 of Channel #2 0x0000_01FF +#define S5P_SDO_OSFC08_2 S5P_SDAOUT_BASE(0x0340) // OSF Coefficient 17 & 16 of Channel #2 0x01EC_01F2 +#define S5P_SDO_OSFC09_2 S5P_SDAOUT_BASE(0x0344) // OSF Coefficient 19 & 18 of Channel #2 0x0000_0001 +#define S5P_SDO_OSFC10_2 S5P_SDAOUT_BASE(0x0348) // OSF Coefficient 21 & 20 of Channel #2 0x001D_0014 +#define S5P_SDO_OSFC11_2 S5P_SDAOUT_BASE(0x034C) // OSF Coefficient 23 & 22 of Channel #2 0x0000_01FE +#define S5P_SDO_OSFC12_2 S5P_SDAOUT_BASE(0x0350) // OSF Coefficient 25 & 24 of Channel #2 0x03D8_03E4 +#define S5P_SDO_OSFC13_2 S5P_SDAOUT_BASE(0x0354) // OSF Coefficient 27 & 26 of Channel #2 0x0000_0002 +#define S5P_SDO_OSFC14_2 S5P_SDAOUT_BASE(0x0358) // OSF Coefficient 29 & 28 of Channel #2 0x0038_0028 +#define S5P_SDO_OSFC15_2 S5P_SDAOUT_BASE(0x035C) // OSF Coefficient 31 & 30 of Channel #2 0x0000_03FD +#define S5P_SDO_OSFC16_2 S5P_SDAOUT_BASE(0x0360) // OSF Coefficient 33 & 32 of Channel #2 0x03B0_03C7 +#define S5P_SDO_OSFC17_2 S5P_SDAOUT_BASE(0x0364) // OSF Coefficient 35 & 34 of Channel #2 0x0000_0005 +#define S5P_SDO_OSFC18_2 S5P_SDAOUT_BASE(0x0368) // OSF Coefficient 37 & 36 of Channel #2 0x0079_0056 +#define S5P_SDO_OSFC19_2 S5P_SDAOUT_BASE(0x036C) // OSF Coefficient 39 & 38 of Channel #2 0x0000_03F6 +#define S5P_SDO_OSFC20_2 S5P_SDAOUT_BASE(0x0370) // OSF Coefficient 41 & 40 of Channel #2 0x072C_0766 +#define S5P_SDO_OSFC21_2 S5P_SDAOUT_BASE(0x0374) // OSF Coefficient 43 & 42 of Channel #2 0x0000_001B +#define S5P_SDO_OSFC22_2 S5P_SDAOUT_BASE(0x0378) // OSF Coefficient 45 & 44 of Channel #2 0x028B_0265 +#define S5P_SDO_OSFC23_2 S5P_SDAOUT_BASE(0x037C) // OSF Coefficient 47 & 46 of Channel #2 0x0400_0ECC +#define S5P_SDO_ARMCC S5P_SDAOUT_BASE(0x03C0) // Closed Caption Data Register 0x0000_0000 +#define S5P_SDO_ARMWSS525 S5P_SDAOUT_BASE(0x03C4) // WSS 525 Data Register 0x0000_0000 +#define S5P_SDO_ARMWSS625 S5P_SDAOUT_BASE(0x03C8) // WSS 625 Data Register 0x0000_0000 +#define S5P_SDO_ARMCGMS525 S5P_SDAOUT_BASE(0x03CC) // CGMS-A 525 Data Register 0x0000_0000 +#define S5P_SDO_ARMCGMS625 S5P_SDAOUT_BASE(0x03D4) // CGMS-A 625 Data Register 0x0000_0000 +#define S5P_SDO_VERSION S5P_SDAOUT_BASE(0x03D8) // TVOUT Version Number Read Register 0x0000_000C +#define S5P_SDO_CC S5P_SDAOUT_BASE(0x0380) // Closed Caption Data Shadow register 0x0000_0000 +#define S5P_SDO_WSS525 S5P_SDAOUT_BASE(0x0384) // WSS 525 Data Shadow Register 0x0000_0000 +#define S5P_SDO_WSS625 S5P_SDAOUT_BASE(0x0388) // WSS 625 Data Shadow Register 0x0000_0000 +#define S5P_SDO_CGMS525 S5P_SDAOUT_BASE(0x038C) // CGMS-A 525 Data Shadow Register 0x0000_0000 +#define S5P_SDO_CGMS625 S5P_SDAOUT_BASE(0x0394) // CGMS-A 625 Data Shadow Register 0x0000_0000 + +/* + Shadow Registers +*/ + +/* + Registers Bit Description +*/ +/* + Macros +*/ +/* SDO_CLKCON */ +#define SDO_TVOUT_SW_RESET (1<<4) +#define SDO_TVOUT_CLK_DOWN_RDY (1<<1) +#define SDO_TVOUT_CLOCK_ON (1) +#define SDO_TVOUT_CLOCK_OFF (0) + +/* SDO_CONFIG */ +#define SDO_DAC2_Y_G (0<<20) +#define SDO_DAC2_PB_B (1<<20) +#define SDO_DAC2_PR_R (2<<20) +#define SDO_DAC1_Y_G (0<<18) +#define SDO_DAC1_PB_B (1<<18) +#define SDO_DAC1_PR_R (2<<18) +#define SDO_DAC0_Y_G (0<<16) +#define SDO_DAC0_PB_B (1<<16) +#define SDO_DAC0_PR_R (2<<16) +#define SDO_DAC2_CVBS (0<<12) +#define SDO_DAC2_Y (1<<12) +#define SDO_DAC2_C (2<<12) +#define SDO_DAC1_CVBS (0<<10) +#define SDO_DAC1_Y (1<<10) +#define SDO_DAC1_C (2<<10) +#define SDO_DAC0_CVBS (0<<8) +#define SDO_DAC0_Y (1<<8) +#define SDO_DAC0_C (2<<8) +#define SDO_COMPOSITE (0<<6) +#define SDO_COMPONENT (1<<6) +#define SDO_RGB (0<<5) +#define SDO_YPBPR (1<<5) +#define SDO_INTERLACED (0<<4) +#define SDO_PROGRESSIVE (1<<4) +#define SDO_NTSC_M (0) +#define SDO_PAL_M (1) +#define SDO_PAL_BGHID (2) +#define SDO_PAL_N (3) +#define SDO_PAL_NC (4) +#define SDO_NTSC_443 (8) +#define SDO_PAL_60 (9) + +/* SDO_SCALE */ +#define SDO_COMPONENT_LEVEL_SEL_0IRE (0<<3) +#define SDO_COMPONENT_LEVEL_SEL_75IRE (1<<3) +#define SDO_COMPONENT_VTOS_RATIO_10_4 (0<<2) +#define SDO_COMPONENT_VTOS_RATIO_7_3 (1<<2) +#define SDO_COMPOSITE_LEVEL_SEL_0IRE (0<<1) +#define SDO_COMPOSITE_LEVEL_SEL_75IRE (1<<1) +#define SDO_COMPOSITE_VTOS_RATIO_10_4 (0<<0) +#define SDO_COMPOSITE_VTOS_RATIO_7_3 (1<<0) + +/* SDO_SYNC */ +#define SDO_COMPONENT_SYNC_ABSENT (0) +#define SDO_COMPONENT_SYNC_YG (1) +#define SDO_COMPONENT_SYNC_ALL (3) + +/* SDO_VBI */ +#define SDO_CVBS_NO_WSS (0<<14) +#define SDO_CVBS_WSS_INS (1<<14) +#define SDO_CVBS_NO_CLOSED_CAPTION (0<<12) +#define SDO_CVBS_21H_CLOSED_CAPTION (1<<12) +#define SDO_CVBS_21H_284H_CLOSED_CAPTION (2<<12) +#define SDO_CVBS_USE_OTHERS (3<<12) +#define SDO_SVIDEO_NO_WSS (0<<10) +#define SDO_SVIDEO_WSS_INS (1<<10) +#define SDO_SVIDEO_NO_CLOSED_CAPTION (0<<8) +#define SDO_SVIDEO_21H_CLOSED_CAPTION (1<<8) +#define SDO_SVIDEO_21H_284H_CLOSED_CAPTION (2<<8) +#define SDO_SVIDEO_USE_OTHERS (3<<8) +#define SDO_RGB_NO_CGMSA (0<<7) +#define SDO_RGB_CGMSA_INS (1<<7) +#define SDO_RGB_NO_WSS (0<<6) +#define SDO_RGB_WSS_INS (1<<6) +#define SDO_RGB_NO_CLOSED_CAPTION (0<<4) +#define SDO_RGB_21H_CLOSED_CAPTION (1<<4) +#define SDO_RGB_21H_284H_CLOSED_CAPTION (2<<4) +#define SDO_RGB_USE_OTHERS (3<<4) +#define SDO_YPBPR_NO_CGMSA (0<<3) +#define SDO_YPBPR_CGMSA_INS (1<<3) +#define SDO_YPBPR_NO_WSS (0<<2) +#define SDO_YPBPR_WSS_INS (1<<2) +#define SDO_YPBPR_NO_CLOSED_CAPTION (0) +#define SDO_YPBPR_21H_CLOSED_CAPTION (1) +#define SDO_YPBPR_21H_284H_CLOSED_CAPTION (2) +#define SDO_YPBPR_USE_OTHERS (3) + +/* SDO_SCALE_CHx */ +#define SDO_SCALE_CONV_OFFSET(a) ((0x3ff&a)<<16) +#define SDO_SCALE_CONV_GAIN(a) (0xfff&a) + +/* SDO_YCDELAY */ +#define SDO_DELAY_YTOC(a) ((0xf&a)<<16) +#define SDO_ACTIVE_START_OFFSET(a) ((0xff&a)<<8) +#define SDO_ACTIVE_END_OFFSET(a) (0xff&a) + +/* SDO_SCHLOCK */ +#define SDO_COLOR_SC_PHASE_ADJ (1) +#define SDO_COLOR_SC_PHASE_NOADJ (0) + +/* SDO_DAC */ +#define SDO_POWER_ON_DAC2 (1<<2) +#define SDO_POWER_DOWN_DAC2 (0<<2) +#define SDO_POWER_ON_DAC1 (1<<1) +#define SDO_POWER_DOWN_DAC1 (0<<1) +#define SDO_POWER_ON_DAC0 (1<<0) +#define SDO_POWER_DOWN_DAC0 (0<<0) + +/* SDO_FINFO */ +#define SDO_FIELD_MOD_1001(a) (((0x3ff<<16)&a)>>16) +#define SDO_FIELD_ID_BOTTOM(a) ((1<<1)&a) +#define SDO_FIELD_ID_BOTTOM_PI_INCATION(a) (1) +/* SDO_Y0 */ +/* +#define SDO_AA_75_73_CB (0x251) +#define SDO_AA_75_104_CB (0x25d) +#define SDO_AA_75_73_CB (0x281) +#define SDO_AA_0_73_CB (0x28f) +#define SDO_AA_75_73_CR (0x1f3) +#define SDO_AA_75_104_CR (0x200) +#define SDO_AA_75_73_CR (0x21e) +#define SDO_AA_0_73_CR (0x228) +#define SDO_AA_75_73 (0x2c0) +#define SDO_AA_75_104 (0x2d1) +#define SDO_AA_75_73 (0x2c0) +#define SDO_AA_0_73 (0x30d) +*/ +/* SDO_MV_480P_PROTECTION_ON */ +#define SDO_MV_AGC_103_ON (1) + +/* SDO_CCCON */ +#define SDO_COMPONENT_BHS_ADJ_ON (0<<4) +#define SDO_COMPONENT_BHS_ADJ_OFF (1<<4) +#define SDO_COMPONENT_YPBPR_COMP_ON (0<<3) +#define SDO_COMPONENT_YPBPR_COMP_OFF (1<<3) +#define SDO_COMPONENT_RGB_COMP_ON (0<<2) +#define SDO_COMPONENT_RGB_COMP_OFF (1<<2) +#define SDO_COMPONENT_YC_COMP_ON (0<<1) +#define SDO_COMPONENT_YC_COMP_OFF (1<<1) +#define SDO_COMPONENT_CVBS_COMP_ON (0) +#define SDO_COMPONENT_CVBS_COMP_OFF (1) + +/* SDO_YSCALE */ +#define SDO_BRIGHTNESS_GAIN(a) ((0xff&a)<<16) +#define SDO_BRIGHTNESS_OFFSET(a) (0xff&a) + +/* SDO_CBSCALE */ +#define SDO_HS_CB_GAIN0(a) ((0x1ff&a)<<16) +#define SDO_HS_CB_GAIN1(a) (0x1ff&a) + +/* SDO_CRSCALE */ +#define SDO_HS_CR_GAIN0(a) ((0x1ff&a)<<16) +#define SDO_HS_CR_GAIN1(a) (0x1ff&a) + +/* SDO_CB_CR_OFFSET */ +#define SDO_HS_CR_OFFSET(a) ((0x3ff&a)<<16) +#define SDO_HS_CB_OFFSET(a) (0x3ff&a) + +/* SDO_RGB_CC */ +#define SDO_MAX_RGB_CUBE(a) ((0xff&a)<<8) +#define SDO_MIN_RGB_CUBE(a) (0xff&a) + +/* SDO_CVBS_CC_Y1 */ +#define SDO_Y_LOWER_MID_CVBS_CORN(a) ((0x3ff&a)<<16) +#define SDO_Y_BOTTOM_CVBS_CORN(a) (0x3ff&a) + +/* SDO_CVBS_CC_Y2 */ +#define SDO_Y_TOP_CVBS_CORN(a) ((0x3ff&a)<<16) +#define SDO_Y_UPPER_MID_CVBS_CORN(a) (0x3ff&a) + +/* SDO_CVBS_CC_C */ +#define SDO_RADIUS_CVBS_CORN(a) (0x1ff&a) + +/* SDO_YC_CC_Y */ +#define SDO_Y_TOP_YC_CYLINDER(a) ((0x3ff&a)<<16) +#define SDO_Y_BOTOM_YC_CYLINDER(a) (0x3ff&a) + +/* SDO_CVBS_CC_C */ +#define SDO_RADIUS_YC_CYLINDER(a) (0x1ff&a) + +/* SDO_CSC_525_PORCH */ +#define SDO_COMPONENT_525_BP(a) ((0x3ff&a)<<16) +#define SDO_COMPONENT_525_FP(a) (0x3ff&a) + +/* SDO_CSC_525_PORCH */ +#define SDO_COMPONENT_625_BP(a) ((0x3ff&a)<<16) +#define SDO_COMPONENT_625_FP(a) (0x3ff&a) + +/* SDO_RGBSYNC */ +#define SDO_RGB_SYNC_COMPOSITE (0<<8) +#define SDO_RGB_SYNC_SEPERATE (1<<8) +#define SDO_RGB_VSYNC_LOW_ACT (0<<4) +#define SDO_RGB_VSYNC_HIGH_ACT (1<<4) +#define SDO_RGB_HSYNC_LOW_ACT 0 +#define SDO_RGB_HSYNC_HIGH_ACT 1 + +/* SDO_OSFCxx_x */ +#define SDO_OSF_COEF_ODD(a) ((0xfff&a)<<16) +#define SDO_OSF_COEF_EVEN(a) (0xfff&a) + +/* SDO_XTALKx */ +#define SDO_XTALK_COEF02(a) ((0xff&a)<<16) +#define SDO_XTALK_COEF01(a) (0xff&a) + +/* SDO_BB_CTRL */ +#define SDO_REF_BB_LEVEL_NTSC (0x11a<<8) +#define SDO_REF_BB_LEVEL_PAL (0xfb<<8) +#define SDO_SEL_BB_CJAN_CVBS0_BB1_BB2 (0<<4) +#define SDO_SEL_BB_CJAN_BB0_CVBS1_BB2 (1<<4) +#define SDO_SEL_BB_CJAN_BB0_BB1_CVBS2 (2<<4) +#define SDO_BB_MODE_ENABLE (1) +#define SDO_BB_MODE_DISABLE (0) + +/* SDO_IRQ */ +#define SDO_VSYNC_IRQ_PEND (1) +#define SDO_VSYNC_NO_IRQ (0) + +/* SDO_IRQMASK */ +#define SDO_VSYNC_IRQ_ENABLE (0) +#define SDO_VSYNC_IRQ_DISABLE (1) + +/* SDO_ARMCC */ +#define SDO_DISPLAY_CC_CAPTION(a) ((0xff&a)<<16) +#define SDO_NON_DISPLAY_CC_CAPTION(a) (0xff&a) + +/* SDO_WSS525 */ +#define SDO_CRC_WSS525(a) ((0x3f&a)<<14) +#define SDO_WORD2_WSS525_COPY_PERMIT (0<<6) +#define SDO_WORD2_WSS525_ONECOPY_PERMIT (1<<6) +#define SDO_WORD2_WSS525_NOCOPY_PERMIT (3<<6) +#define SDO_WORD2_WSS525_MV_PSP_OFF (0<<8) +#define SDO_WORD2_WSS525_MV_PSP_ON_2LINE_BURST (1<<8) +#define SDO_WORD2_WSS525_MV_PSP_ON_BURST_OFF (2<<8) +#define SDO_WORD2_WSS525_MV_PSP_ON_4LINE_BURST (3<<8) +#define SDO_WORD2_WSS525_ANALOG_OFF (0<<10) +#define SDO_WORD2_WSS525_ANALOG_ON (1<<10) +#define SDO_WORD1_WSS525_COPY_INFO (0<<2) +#define SDO_WORD1_WSS525_DEFAULT (0xf<<2) +#define SDO_WORD0_WSS525_4_3_NORMAL (0) +#define SDO_WORD0_WSS525_16_9_ANAMORPIC (1) +#define SDO_WORD0_WSS525_4_3_LETTERBOX (2) + +/* SDO_WSS625 */ +#define SDO_WSS625_SURROUND_SOUND_DISABLE (0<<11) +#define SDO_WSS625_SURROUND_SOUND_ENABLE (1<<11) +#define SDO_WSS625_NO_COPYRIGHT (0<<12) +#define SDO_WSS625_COPYRIGHT (1<<12) +#define SDO_WSS625_COPY_NOT_RESTRICTED (0<<13) +#define SDO_WSS625_COPY_RESTRICTED (1<<13) +#define SDO_WSS625_TELETEXT_NO_SUBTITLES (0<<8) +#define SDO_WSS625_TELETEXT_SUBTITLES (1<<8) +#define SDO_WSS625_NO_OPEN_SUBTITLES (0<<9) +#define SDO_WSS625_INACT_OPEN_SUBTITLES (1<<9) +#define SDO_WSS625_OUTACT_OPEN_SUBTITLES (2<<9) +#define SDO_WSS625_CAMERA (0<<4) +#define SDO_WSS625_FILM (1<<4) +#define SDO_WSS625_NORMAL_PAL (0<<5) +#define SDO_WSS625_MOTION_ADAPTIVE_COLORPLUS (1<<5) +#define SDO_WSS625_HELPER_NO_SIG (0<<6) +#define SDO_WSS625_HELPER_SIG (1<<6) +#define SDO_WSS625_4_3_FULL_576 (0x8) +#define SDO_WSS625_14_9_LETTERBOX_CENTER_504 (0x1) +#define SDO_WSS625_14_9_LETTERBOX_TOP_504 (0x2) +#define SDO_WSS625_16_9_LETTERBOX_CENTER_430 (0xb) +#define SDO_WSS625_16_9_LETTERBOX_TOP_430 (0x4) +#define SDO_WSS625_16_9_LETTERBOX_CENTER (0xd) +#define SDO_WSS625_14_9_FULL_CENTER_576 (0xe) +#define SDO_WSS625_16_9_ANAMORPIC_576 (0x7) + +/* SDO_CGMS525 */ +#define SDO_CRC_CGMS525(a) ((0x3f&a)<<14) +#define SDO_WORD2_CGMS525_COPY_PERMIT (0<<6) +#define SDO_WORD2_CGMS525_ONECOPY_PERMIT (1<<6) +#define SDO_WORD2_CGMS525_NOCOPY_PERMIT (3<<6) +#define SDO_WORD2_CGMS525_MV_PSP_OFF (0<<8) +#define SDO_WORD2_CGMS525_MV_PSP_ON_2LINE_BURST (1<<8) +#define SDO_WORD2_CGMS525_MV_PSP_ON_BURST_OFF (2<<8) +#define SDO_WORD2_CGMS525_MV_PSP_ON_4LINE_BURST (3<<8) +#define SDO_WORD2_CGMS525_ANALOG_OFF (0<<10) +#define SDO_WORD2_CGMS525_ANALOG_ON (1<<10) +#define SDO_WORD1_CGMS525_COPY_INFO (0<<2) +#define SDO_WORD1_CGMS525_DEFAULT (0xf<<2) +#define SDO_WORD0_CGMS525_4_3_NORMAL (0) +#define SDO_WORD0_CGMS525_16_9_ANAMORPIC (1) +#define SDO_WORD0_CGMS525_4_3_LETTERBOX (2) + +/* SDO_CGMS625 */ +#define SDO_CGMS625_SURROUND_SOUND_DISABLE (0<<11) +#define SDO_CGMS625_SURROUND_SOUND_ENABLE (1<<11) +#define SDO_CGMS625_NO_COPYRIGHT (0<<12) +#define SDO_CGMS625_COPYRIGHT (1<<12) +#define SDO_CGMS625_COPY_NOT_RESTRICTED (0<<13) +#define SDO_CGMS625_COPY_RESTRICTED (1<<13) +#define SDO_CGMS625_TELETEXT_NO_SUBTITLES (0<<8) +#define SDO_CGMS625_TELETEXT_SUBTITLES (1<<8) +#define SDO_CGMS625_NO_OPEN_SUBTITLES (0<<9) +#define SDO_CGMS625_INACT_OPEN_SUBTITLES (1<<9) +#define SDO_CGMS625_OUTACT_OPEN_SUBTITLES (2<<9) +#define SDO_CGMS625_CAMERA (0<<4) +#define SDO_CGMS625_FILM (1<<4) +#define SDO_CGMS625_NORMAL_PAL (0<<5) +#define SDO_CGMS625_MOTION_ADAPTIVE_COLORPLUS (1<<5) +#define SDO_CGMS625_HELPER_NO_SIG (0<<6) +#define SDO_CGMS625_HELPER_SIG (1<<6) +#define SDO_CGMS625_4_3_FULL_576 (0x8) +#define SDO_CGMS625_14_9_LETTERBOX_CENTER_504 (0x1) +#define SDO_CGMS625_14_9_LETTERBOX_TOP_504 (0x2) +#define SDO_CGMS625_16_9_LETTERBOX_CENTER_430 (0xb) +#define SDO_CGMS625_16_9_LETTERBOX_TOP_430 (0x4) +#define SDO_CGMS625_16_9_LETTERBOX_CENTER (0xd) +#define SDO_CGMS625_14_9_FULL_CENTER_576 (0xe) +#define SDO_CGMS625_16_9_ANAMORPIC_576 (0x7) + +#endif /*__ASM_ARCH_REGS_SDAOUT_H */ diff --git a/drivers/media/video/samsung/tv20/s5pv210/regs/regs-vmx.h b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-vmx.h new file mode 100644 index 0000000..24126cb --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-vmx.h @@ -0,0 +1,254 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vmx.h + * + * Mixer register header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <mach/map.h> + +#define S5P_MIXER_BASE(x) (x) +/* + Registers +*/ +#define S5P_MXR_STATUS S5P_MIXER_BASE(0x0000) //Status of MIXER Operation +#define S5P_MXR_CFG S5P_MIXER_BASE(0x0004) //MIXER Mode Setting +#define S5P_MXR_INT_EN S5P_MIXER_BASE(0x0008) //Interrupt Enable +#define S5P_MXR_INT_STATUS S5P_MIXER_BASE(0x000C) //Interrupt Status +#define S5P_MXR_LAYER_CFG S5P_MIXER_BASE(0x0010) //Video & Graphic Layer Priority and On// Off +#define S5P_MXR_VIDEO_CFG S5P_MIXER_BASE(0x0014) //Video Layer Configuration +#define S5P_MXR_GRAPHIC0_CFG S5P_MIXER_BASE(0x0020) //Graphic Layer0 Configuration +#define S5P_MXR_GRAPHIC0_BASE S5P_MIXER_BASE(0x0024) //Base Address for Graphic Layer0 +#define S5P_MXR_GRAPHIC0_SPAN S5P_MIXER_BASE(0x0028) //Span for Graphic Layer0 +#define S5P_MXR_GRAPHIC0_SXY S5P_MIXER_BASE(0x002C) //Source X//Y Positions for Graphic Layer0 +#define S5P_MXR_GRAPHIC0_WH S5P_MIXER_BASE(0x0030) //Width// Height for Graphic Layer0 +#define S5P_MXR_GRAPHIC0_DXY S5P_MIXER_BASE(0x0034) //Destination X//Y Positions for Graphic Layer0 +#define S5P_MXR_GRAPHIC0_BLANK S5P_MIXER_BASE(0x0038) //Blank Pixel Value for Graphic Layer0 +#define S5P_MXR_GRAPHIC1_CFG S5P_MIXER_BASE(0x0040) //Graphic Layer1 Configuration +#define S5P_MXR_GRAPHIC1_BASE S5P_MIXER_BASE(0x0044) //Base Address for Graphic Layer1 +#define S5P_MXR_GRAPHIC1_SPAN S5P_MIXER_BASE(0x0048) //Span for Graphic Layer1 +#define S5P_MXR_GRAPHIC1_SXY S5P_MIXER_BASE(0x004C) //Source X//Y Positions for Graphic Layer1 +#define S5P_MXR_GRAPHIC1_WH S5P_MIXER_BASE(0x0050) //Width// Height for Graphic Layer1 +#define S5P_MXR_GRAPHIC1_DXY S5P_MIXER_BASE(0x0054) //Destination X//Y Positions for Graphic Layer1 +#define S5P_MXR_GRAPHIC1_BLANK S5P_MIXER_BASE(0x0058) //Blank Pixel Value for Graphic Layer1 +#define S5P_MXR_BG_CFG S5P_MIXER_BASE(0x0060) +#define S5P_MXR_BG_COLOR0 S5P_MIXER_BASE(0x0064) //Background Color of First Point +#define S5P_MXR_BG_COLOR1 S5P_MIXER_BASE(0x0068) //Background Color of Second Point +#define S5P_MXR_BG_COLOR2 S5P_MIXER_BASE(0x006C) //Background Color of Last Point +#define S5P_MXR_CM_COEFF_Y S5P_MIXER_BASE(0x0080) //Scaled Color Space Conversion (RGB to Y) Coefficient for Graphic Layer +#define S5P_MXR_CM_COEFF_CB S5P_MIXER_BASE(0x0084) //Scaled Color Space Conversion (RGB to CB) Coefficient for Graphic Layer +#define S5P_MXR_CM_COEFF_CR S5P_MIXER_BASE(0x0088) //Scaled Color Space Conversion (RGB to Cr) Coefficient for Graphic Layer +#define S5P_MXR_VER S5P_MIXER_BASE(0x0100) //Mixer Version + +/* + Shadow Registers +*/ +#define S5P_MXR_STATUS_S S5P_MIXER_BASE(0x2000) //Status of MIXER Operation (Shadow) +#define S5P_MXR_CFG_S S5P_MIXER_BASE(0x2004) //MIXER Mode Setting (Shadow) +#define S5P_MXR_LAYER_CFG_S S5P_MIXER_BASE(0x2010) //Video & Graphic Layer Priority and On// Off (Shadow) +#define S5P_MXR_VIDEO_CFG_S S5P_MIXER_BASE(0x2014) //Video Layer Configuration (Shadow) +#define S5P_MXR_GRAPHIC0_CFG_S S5P_MIXER_BASE(0x2020) //Graphic Layer0 Configuration (Shadow) +#define S5P_MXR_GRAPHIC0_BASE_S S5P_MIXER_BASE(0x2024) //Graphic0 Base Address (Shadow) +#define S5P_MXR_GRAPHIC0_SPAN_S S5P_MIXER_BASE(0x2028) //Graphic0 Span (Shadow) +#define S5P_MXR_GRAPHIC0_SXY_S S5P_MIXER_BASE(0x202C) //Graphic0 Source X//Y Coordinates (Shadow) +#define S5P_MXR_GRAPHIC0_WH_S S5P_MIXER_BASE(0x2030) //Graphic0 Width// Height (Shadow) +#define S5P_MXR_GRAPHIC0_DXY_S S5P_MIXER_BASE(0x2034) //Graphic0 Destination X//Y Coordinates (Shadow) +#define S5P_MXR_GRAPHIC0_BLANK_PIXEL_S S5P_MIXER_BASE(0x2038) //Graphic0 Blank Pixel (Shadow) +#define S5P_MXR_GRAPHIC1_CFG_S S5P_MIXER_BASE(0x2040) //Graphic Layer1 Configuration (Shadow) +#define S5P_MXR_GRAPHIC1_BASE_S S5P_MIXER_BASE(0x2044) //Graphic1 Base Address (Shadow) +#define S5P_MXR_GRAPHIC1_SPAN_S S5P_MIXER_BASE(0x2048) //Graphic1 Span (Shadow) +#define S5P_MXR_GRAPHIC1_SXY_S S5P_MIXER_BASE(0x204C) //Graphic1 Source X//Y Coordinates (Shadow) +#define S5P_MXR_GRAPHIC1_WH_S S5P_MIXER_BASE(0x2050) //Graphic1 Width// Height (Shadow) +#define S5P_MXR_GRAPHIC1_DXY_S S5P_MIXER_BASE(0x2054) //Graphic1 Destination X//YCoordinates (Shadow) +#define S5P_MXR_GRAPHIC1_BLANK_PIXEL_S S5P_MIXER_BASE(0x2058) //Graphic1 Blank Pixel (Shadow) +#define S5P_MXR_BG_COLOR0_S S5P_MIXER_BASE(0x2064) //Background First Color (Shadow) +#define S5P_MXR_BG_COLOR1_S S5P_MIXER_BASE(0x2068) //Background Second Color (Shadow) +#define S5P_MXR_BG_COLOR2_S S5P_MIXER_BASE(0x206C) //Background Last Color (Shadow) + +/* + Registers Bit Description +*/ +/* S5P_MXR_STATUS */ +#define S5P_MXR_STATUS_RUN (1<<0) +#define S5P_MXR_STATUS_STOP (0<<0) +#define S5P_MXR_STATUS_SYNC_DISABLE (0<<2) +#define S5P_MXR_STATUS_SYNC_ENABLE (1<<2) +#define S5P_MXR_STATUS_LITTLE (0<<3) +#define S5P_MXR_STATUS_BIT (1<<3) +#define S5P_MXR_STATUS_8_BURST (0<<7) +#define S5P_MXR_STATUS_16_BURST (1<<7) + +/* S5P_MXR_CFG */ +#define S5P_MXR_CFG_SD (0<<0) +#define S5P_MXR_CFG_HD (1<<0) +#define S5P_MXR_CFG_NTSC (0<<1) +#define S5P_MXR_CFG_PAL (1<<1) +#define S5P_MXR_CFG_INTERLACE (0<<2) +#define S5P_MXR_CFG_PROGRASSIVE (1<<2) +#define S5P_MXR_CFG_VIDEO_DISABLE (0<<3) +#define S5P_MXR_CFG_VIDEO_ENABLE (1<<4) +#define S5P_MXR_CFG_GRAPHIC0_DISABLE (0<<4) +#define S5P_MXR_CFG_GRAPHIC0_ENABLE (1<<4) +#define S5P_MXR_CFG_GRAPHIC1_DISABLE (0<<5) +#define S5P_MXR_CFG_GRAPHIC1_ENABLE (1<<5) +#define S5P_MXR_CFG_HD_720P (0<<6) +#define S5P_MXR_CFG_HD_1080I (1<<6) +#define S5P_MXR_CFG_TV_OUT (0<<7) +#define S5P_MXR_CFG_HDMI_OUT (1<<7) + +/* S5P_MXR_INT_EN */ +#define S5P_MXR_INT_EN_GRP0_DISABLE (0<<8) +#define S5P_MXR_INT_EN_GRP0_ENABLE (1<<8) +#define S5P_MXR_INT_EN_GRP1_DISABLE (0<<9) +#define S5P_MXR_INT_EN_GRP1_ENABLE (1<<9) +#define S5P_MXR_INT_EN_VP_DISABLE (0<<10) +#define S5P_MXR_INT_EN_VP_ENABLE (1<<10) + +/* S5P_MXR_INT_STATUS */ +#define S5P_MXR_STATUS_EN_GRP0_N_FIRED (0<<8) +#define S5P_MXR_STATUS_EN_GRP0_FIRED (1<<8) +#define S5P_MXR_STATUS_EN_GRP1_N_FIRED (0<<9) +#define S5P_MXR_STATUS_EN_GRP1_FIRED (1<<9) +#define S5P_MXR_STATUS_EN_VP_N_FIRED (0<<10) +#define S5P_MXR_STATUS_EN_VP_FIRED (1<<10) + +/* S5P_MXR_LAYER_CFG */ +#define S5P_MXR_LAYER_CFG_VP_HIDE (0<<0) +#define S5P_MXR_LAYER_CFG_GRP0_HIDE (0<<4) +#define S5P_MXR_LAYER_CFG_GRP1_HIDE (0<<8) + +/* S5P_MXR_VIDEO_CFG */ +#define S5P_MXR_VIDEO_CFG_BLEND_EN (1<<16) + +/* Macros */ +/* MIXER_STATUS */ +#define S5P_MXR_BURST16_MODE (1<<7) +#define S5P_MXR_BURST8_MODE (0<<7) +#define S5P_MXR_BIG_ENDIAN_SOURCE_FORMAT (1<<3) +#define S5P_MXR_LITTLE_ENDIAN_SOURCE_FORMAT (0<<3) +#define S5P_MXR_MIXER_RESERVED (1<<2) +#define S5P_MXR_CMU_STOP_CLOCK (1<<1) +#define S5P_MXR_CMU_CANNOT_STOP_CLOCK (0<<1) +#define S5P_MXR_MIXER_START (1<<0) +#define S5P_MXR_MIXER_STOP (0<<0) + +/* MIXER_CFG */ +#define S5P_MXR_DST_SEL_HDMI (1<<7) +#define S5P_MXR_DST_SEL_ANALOG ~(1<<7) +#define S5P_MXR_HD_1080I_MODE (1<<6) +/* C110 */ +#define S5P_MXR_HD_1080P_MODE S5P_MXR_HD_1080I_MODE + +#define S5P_MXR_HD_720P_MODE (0<<6) +#define S5P_MXR_GRAPHIC1_LAYER_SHOW (1<<5) +#define S5P_MXR_GRAPHIC1_LAYER_HIDE (0<<5) +#define S5P_MXR_GRAPHIC0_LAYER_SHOW (1<<4) +#define S5P_MXR_GRAPHIC0_LAYER_HIDE (0<<4) +#define S5P_MXR_VIDEO_LAYER_SHOW (1<<3) +#define S5P_MXR_VIDEO_LAYER_HIDE (0<<3) +#define S5P_MXR_PROGRESSVE_MODE (1<<2) +#define S5P_MXR_INTERLACE_MODE ~(1<<2) +#define S5P_MXR_PAL (1<<1) +#define S5P_MXR_NTSC (0<<1) +#define S5P_MXR_HD (1<<0) +#define S5P_MXR_SD (0<<0) + +/* MIXER_INT_EN */ +#define S5P_MXR_VP_INT_ENABLE (1<<10) +#define S5P_MXR_VP_INT_DISABLE (0<<10) +#define S5P_MXR_GRP1_INT_ENABLE (1<<9) +#define S5P_MXR_GRP1_INT_DISABLE (0<<9) +#define S5P_MXR_GRP0_INT_ENABLE (1<<8) +#define S5P_MXR_GRP0_INT_DISABLE (0<<8) + +/* MIXER_INT_STATUS */ +#define S5P_MXR_VP_INT_FIRED (1<<10) +#define S5P_MXR_GRP1_INT_FIRED (1<<9) +#define S5P_MXR_GRP0_INT_FIRED (1<<8) +#define S5P_MXR_INT_FIRED (1<<0) + +#define S5P_MXR_ALPHA (0xff) + +/* MIXER_LAYER_CFG */ +#define S5P_MXR_GRP1_LAYER_PRIORITY(a) ((0xf&a)<<8) +#define S5P_MXR_GRP0_LAYER_PRIORITY(a) ((0xf&a)<<4) +#define S5P_MXR_VP_LAYER_PRIORITY(a) ((0xf&a)<<0) +#define S5P_MXR_GRP1_LAYER_PRIORITY_CLEAR(a) ((~(0xf<<8))&a) +#define S5P_MXR_GRP0_LAYER_PRIORITY_CLEAR(a) ((~(0xf<<4))&a) +#define S5P_MXR_VP_LAYER_PRIORITY_CLEAR(a) ((~(0xf<<0))&a) +#define S5P_MXR_GRP1_LAYER_PRIORITY_INFO(a) ((0xf<<8)&a) +#define S5P_MXR_GRP0_LAYER_PRIORITY_INFO(a) ((0xf<<4)&a) +#define S5P_MXR_VP_LAYER_PRIORITY_INFO(a) ((0xf<<0)&a) + +/* MIXER_VIDEO_CFG */ +#define S5P_MXR_VP_BLEND_ENABLE (1<<16) +#define S5P_MXR_VP_BLEND_DISABLE (0<<16) +#define S5P_MXR_VP_ALPHA_VALUE(a) ((0xff&a)<<0) +#define S5P_MXR_VP_ALPHA_VALUE_CLEAR(a) ((~(0xff<<0))&a) + +/* MIXER_GRAPHx_CFG */ +#define S5P_MXR_BLANK_CHANGE_NEW_PIXEL (1<<21) +#define S5P_MXR_BLANK_NOT_CHANGE_NEW_PIXEL (0<<21) +#define S5P_MXR_PRE_MUL_MODE (1<<20) +#define S5P_MXR_NORMAL_MODE (0<<20) +#define S5P_MXR_WIN_BLEND_ENABLE (1<<17) +#define S5P_MXR_WIN_BLEND_DISABLE (0<<17) +#define S5P_MXR_PIXEL_BLEND_ENABLE (1<<16) +#define S5P_MXR_PIXEL_BLEND_DISABLE (0<<16) +#define S5P_MXR_EG_COLOR_FORMAT(a) ((0xf&a)<<8) +#define S5P_MXR_EG_COLOR_FORMAT_CLEAR(a) ((~(0xf<<8))&a) +#define S5P_MXR_GRP_ALPHA_VALUE(a) ((0xff&a)<<0) +#define S5P_MXR_GRP_ALPHA_VALUE_CLEAR(a) ((~(0xff<<0))&a) +/* +enum s5p_tv_vmx_color_fmt +{ + S5P_MXR_DIRECT_RGB565 = 4, + S5P_MXR_DIRECT_RGB1555 = 5, + S5P_MXR_DIRECT_RGB4444 = 6, + S5P_MXR_DIRECT_RGB8888 = 7 +} +*/ + +/* MIXER_GRAPHx_BASE */ +#define S5P_MXR_GPR_BASE(a) (0xffffffff&a) +#define S5P_MXR_GRP_ADDR_ILLEGAL(a) (0x3&a) + +/* MIXER_GRAPH1_SPAN */ +#define S5P_MXR_GRP_SPAN(a) (0x7fff&a) + +/* MIXER_GRAPH1_WH */ +#define S5P_MXR_GRP_WIDTH(a) ((0x7ff&a)<<16) +#define S5P_MXR_GRP_HEIGHT(a) ((0x7ff&a)<<0) + +/* MIXER_GRAPH1_SXY */ +#define S5P_MXR_GRP_STARTX(a) ((0x7ff&a)<<16) +#define S5P_MXR_GRP_STARTY(a) ((0x7ff&a)<<0) + +/* MIXER_GRAPH1_DXY */ +#define S5P_MXR_GRP_DESTX(a) ((0x7ff&a)<<16) +#define S5P_MXR_GRP_DESTY(a) ((0x7ff&a)<<0) + +/* MIXER_GRAPH1_BLANK */ +#define S5P_MXR_GPR_BLANK_COLOR(a) (0xffffffff&a) + +/* MIXER_BG_CFG */ +#define S5P_MXR_BG_CR_DIHER_EN (1<<19) +#define S5P_MXR_BG_CB_DIHER_EN (1<<18) +#define S5P_MXR_BG_Y_DIHER_EN (1<<17) + +/* MIXER_BG_COLORx */ +#define S5P_MXR_BG_COLOR_Y(a) ((0xff&a)<<16) +#define S5P_MXR_BG_COLOR_CB(a) ((0xff&a)<<8) +#define S5P_MXR_BG_COLOR_CR(a) ((0xff&a)<<0) + +/* MIXER_CM_COEFF_x */ +#define S5P_MXR_BG_COLOR_WIDE (1<<30) +#define S5P_MXR_BG_COLOR_NARROW (0<<30) +#define S5P_MXR_BG_COEFF_0(a) ((0x3f&a)<<20) +#define S5P_MXR_BG_COEFF_1(a) ((0x3f&a)<<10) +#define S5P_MXR_BG_COEFF_2(a) ((0x3f&a)<<0) + diff --git a/drivers/media/video/samsung/tv20/s5pv210/regs/regs-vprocessor.h b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-vprocessor.h new file mode 100644 index 0000000..a450018 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/regs/regs-vprocessor.h @@ -0,0 +1,447 @@ +/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-vprocessor.h + * + * Video Processor register header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARCH_REGS_VPROCESSOR_H + +#include <mach/map.h> + +#define S5P_VPROCESSOR_BASE(x) (x) +/* + Registers +*/ +#define S5P_VP_ENABLE S5P_VPROCESSOR_BASE(0x0000) // Power-Down Ready & Enable +#define S5P_VP_SRESET S5P_VPROCESSOR_BASE(0x0004) // Software Reset +#define S5P_VP_SHADOW_UPDATE S5P_VPROCESSOR_BASE(0x0008) // Shadow Register Update Enable +#define S5P_VP_FIELD_ID S5P_VPROCESSOR_BASE(0x000C) // Field ID of the "Source" Image +#define S5P_VP_MODE S5P_VPROCESSOR_BASE(0x0010) // VP Operation Mode +#define S5P_VP_IMG_SIZE_Y S5P_VPROCESSOR_BASE(0x0014) // Luminance Date Size +#define S5P_VP_IMG_SIZE_C S5P_VPROCESSOR_BASE(0x0018) // Chrominance Date Size +#define S5P_VP_PER_RATE_CTRL S5P_VPROCESSOR_BASE(0x001C) +#define S5P_VP_TOP_Y_PTR S5P_VPROCESSOR_BASE(0x0028) // Base Address for Y of Top Field (Frame) +#define S5P_VP_BOT_Y_PTR S5P_VPROCESSOR_BASE(0x002C) // Base Address for Y of Bottom Field +#define S5P_VP_TOP_C_PTR S5P_VPROCESSOR_BASE(0x0030) // Base Address for C of Top +#define S5P_VP_BOT_C_PTR S5P_VPROCESSOR_BASE(0x0034) // Base Address for C of Bottom Field +#define S5P_VP_ENDIAN_MODE S5P_VPROCESSOR_BASE(0x03CC) // Big/Little Endian Mode Selection +#define S5P_VP_SRC_H_POSITION S5P_VPROCESSOR_BASE(0x0044) // Horizontal Offset in the Source Image +#define S5P_VP_SRC_V_POSITION S5P_VPROCESSOR_BASE(0x0048) // Vertical Offset in the Source Image +#define S5P_VP_SRC_WIDTH S5P_VPROCESSOR_BASE(0x004C) // Width of the Source Image +#define S5P_VP_SRC_HEIGHT S5P_VPROCESSOR_BASE(0x0050) // Height of the Source Image +#define S5P_VP_DST_H_POSITION S5P_VPROCESSOR_BASE(0x0054) // Horizontal Offset in the Display +#define S5P_VP_DST_V_POSITION S5P_VPROCESSOR_BASE(0x0058) // Vertical Offset in the Display +#define S5P_VP_DST_WIDTH S5P_VPROCESSOR_BASE(0x005C) // Width of the Display +#define S5P_VP_DST_HEIGHT S5P_VPROCESSOR_BASE(0x0060) // Height of the Display +#define S5P_VP_H_RATIO S5P_VPROCESSOR_BASE(0x0064) // Horizontal Zoom Ratio of SRC:DST +#define S5P_VP_V_RATIO S5P_VPROCESSOR_BASE(0x0068) // Vertical Zoom Ratio of SRC:DST +#define S5P_VP_POLY8_Y0_LL S5P_VPROCESSOR_BASE(0x006C) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y0_LH S5P_VPROCESSOR_BASE(0x0070) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y0_HL S5P_VPROCESSOR_BASE(0x0074) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y0_HH S5P_VPROCESSOR_BASE(0x0078) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y1_LL S5P_VPROCESSOR_BASE(0x007C) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y1_LH S5P_VPROCESSOR_BASE(0x0080) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y1_HL S5P_VPROCESSOR_BASE(0x0084) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y1_HH S5P_VPROCESSOR_BASE(0x0088) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y2_LL S5P_VPROCESSOR_BASE(0x008C) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y2_LH S5P_VPROCESSOR_BASE(0x0090) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y2_HL S5P_VPROCESSOR_BASE(0x0094) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y2_HH S5P_VPROCESSOR_BASE(0x0098) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y3_LL S5P_VPROCESSOR_BASE(0x009C) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y3_LH S5P_VPROCESSOR_BASE(0x00A0) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y3_HL S5P_VPROCESSOR_BASE(0x00A4) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY8_Y3_HH S5P_VPROCESSOR_BASE(0x00A8) // 8-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY4_Y0_LL S5P_VPROCESSOR_BASE(0x00EC) // 4-Tap Poly-phase Filter Coefficients for Luminance Horizontal Scaling +#define S5P_VP_POLY4_Y0_LH S5P_VPROCESSOR_BASE(0x00F0) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y0_HL S5P_VPROCESSOR_BASE(0x00F4) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y0_HH S5P_VPROCESSOR_BASE(0x00F8) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y1_LL S5P_VPROCESSOR_BASE(0x00FC) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y1_LH S5P_VPROCESSOR_BASE(0x0100) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y1_HL S5P_VPROCESSOR_BASE(0x0104) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y1_HH S5P_VPROCESSOR_BASE(0x0108) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y2_LL S5P_VPROCESSOR_BASE(0x010C) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y2_LH S5P_VPROCESSOR_BASE(0x0110) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y2_HL S5P_VPROCESSOR_BASE(0x0114) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y2_HH S5P_VPROCESSOR_BASE(0x0118) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y3_LL S5P_VPROCESSOR_BASE(0x011C) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y3_LH S5P_VPROCESSOR_BASE(0x0120) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y3_HL S5P_VPROCESSOR_BASE(0x0124) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_Y3_HH S5P_VPROCESSOR_BASE(0x0128) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_C0_LL S5P_VPROCESSOR_BASE(0x012C) // 4-Tap Poly-phase Filter Coefficients for Luminance Vertical Scaling +#define S5P_VP_POLY4_C0_LH S5P_VPROCESSOR_BASE(0x0130) // 4-Tap Poly-phase Filter Coefficients for Chrominance Horizontal Scaling +#define S5P_VP_POLY4_C0_HL S5P_VPROCESSOR_BASE(0x0134) // 4-Tap Poly-phase Filter Coefficients for Chrominance Horizontal Scaling +#define S5P_VP_POLY4_C0_HH S5P_VPROCESSOR_BASE(0x0138) // 4-Tap Poly-phase Filter Coefficients for Chrominance Horizontal Scaling +#define S5P_VP_POLY4_C1_LL S5P_VPROCESSOR_BASE(0x013C) // 4-Tap Poly-phase Filter Coefficients for Chrominance Horizontal Scaling +#define S5P_VP_POLY4_C1_LH S5P_VPROCESSOR_BASE(0x0140) // 4-Tap Poly-phase Filter Coefficients for Chrominance Horizontal Scaling +#define S5P_VP_POLY4_C1_HL S5P_VPROCESSOR_BASE(0x0144) // 4-Tap Poly-phase Filter Coefficients for Chrominance Horizontal Scaling +#define S5P_VP_POLY4_C1_HH S5P_VPROCESSOR_BASE(0x0148) // 4-Tap Poly-phase Filter Coefficients for Chrominance Horizontal Scaling +#define S5P_PP_CSC_Y2Y_COEF S5P_VPROCESSOR_BASE(0x01D4) // Y to Y CSC Coefficient Setting +#define S5P_PP_CSC_CB2Y_COEF S5P_VPROCESSOR_BASE(0x01D8) // CB to Y CSC Coefficient Setting +#define S5P_PP_CSC_CR2Y_COEF S5P_VPROCESSOR_BASE(0x01DC) // CR to Y CSC Coefficient Setting +#define S5P_PP_CSC_Y2CB_COEF S5P_VPROCESSOR_BASE(0x01E0) // Y to Y CSC Coefficient Setting +#define S5P_PP_CSC_CB2CB_COEF S5P_VPROCESSOR_BASE(0x01E4) // CB to Y CSC Coefficient Setting +#define S5P_PP_CSC_CR2CB_COEF S5P_VPROCESSOR_BASE(0x01E8) // CR to Y CSC Coefficient Setting +#define S5P_PP_CSC_Y2CR_COEF S5P_VPROCESSOR_BASE(0x01EC) // Y to Y CSC Coefficient Setting +#define S5P_PP_CSC_CB2CR_COEF S5P_VPROCESSOR_BASE(0x01F0) // CB to Y CSC Coefficient Setting +#define S5P_PP_CSC_CR2CR_COEF S5P_VPROCESSOR_BASE(0x01F4) // CR to Y CSC Coefficient Setting +#define S5P_PP_BYPASS S5P_VPROCESSOR_BASE(0x0200) // Disable the Post Image Processor +#define S5P_PP_SATURATION S5P_VPROCESSOR_BASE(0x020C) // Color Saturation Factor +#define S5P_PP_SHARPNESS S5P_VPROCESSOR_BASE(0x0210) // Control for the Edge Enhancement +#define S5P_PP_LINE_EQ0 S5P_VPROCESSOR_BASE(0x0218) // Line Equation for Contrast Duration "0" +#define S5P_PP_LINE_EQ1 S5P_VPROCESSOR_BASE(0x021C) // Line Equation for Contrast Duration "1" +#define S5P_PP_LINE_EQ2 S5P_VPROCESSOR_BASE(0x0220) // Line Equation for Contrast Duration "2" +#define S5P_PP_LINE_EQ3 S5P_VPROCESSOR_BASE(0x0224) // Line Equation for Contrast Duration "3" +#define S5P_PP_LINE_EQ4 S5P_VPROCESSOR_BASE(0x0228) // Line Equation for Contrast Duration "4" +#define S5P_PP_LINE_EQ5 S5P_VPROCESSOR_BASE(0x022C) // Line Equation for Contrast Duration "5" +#define S5P_PP_LINE_EQ6 S5P_VPROCESSOR_BASE(0x0230) // Line Equation for Contrast Duration "6" +#define S5P_PP_LINE_EQ7 S5P_VPROCESSOR_BASE(0x0234) // Line Equation for Contrast Duration "7" +#define S5P_PP_BRIGHT_OFFSET S5P_VPROCESSOR_BASE(0x0238) // Brightness Offset Control for Y +#define S5P_PP_CSC_EN S5P_VPROCESSOR_BASE(0x023C) // Color Space Conversion Control +#define S5P_VP_VERSION_INFO S5P_VPROCESSOR_BASE(0x03FC) // VP Version Information + +/* + Shadow Registers +*/ +#define S5P_VP_FIELD_ID_S S5P_VPROCESSOR_BASE(0x016C) // Field ID of the "Source" Image +#define S5P_VP_MODE_S S5P_VPROCESSOR_BASE(0x0170) // VP Operation Mode +#define S5P_VP_IMG_SIZE_Y_S S5P_VPROCESSOR_BASE(0x0174) // Luminance Date Tiled Size +#define S5P_VP_IMG_SIZE_C_S S5P_VPROCESSOR_BASE(0x0178) // Chrominance Date Tiled Size +#define S5P_VP_TOP_Y_PTR_S S5P_VPROCESSOR_BASE(0x0190) // Base Address for Y of Top Field +#define S5P_VP_BOT_Y_PTR_S S5P_VPROCESSOR_BASE(0x0194) // Base Address for Y of Bottom Field +#define S5P_VP_TOP_C_PTR_S S5P_VPROCESSOR_BASE(0x0198) // Base Address for C of Top Frame +#define S5P_VP_BOT_C_PTR_S S5P_VPROCESSOR_BASE(0x019C) // Base Address for C of Bottom field +#define S5P_VP_ENDIAN_MODE_S S5P_VPROCESSOR_BASE(0x03EC) // Big/ Little Endian Mode Selection +#define S5P_VP_SRC_H_POSITION_S S5P_VPROCESSOR_BASE(0x01AC) // Horizontal Offset in the Source Image +#define S5P_VP_SRC_V_POSITION_S S5P_VPROCESSOR_BASE(0x01B0) // Vertical Offset in the Source Image +#define S5P_VP_SRC_WIDTH_S S5P_VPROCESSOR_BASE(0x01B4) // Width of the Source Image +#define S5P_VP_SRC_HEIGHT_S S5P_VPROCESSOR_BASE(0x01B8) // Height of the Source Image +#define S5P_VP_DST_H_POSITION_S S5P_VPROCESSOR_BASE(0x01BC) // Horizontal Offset in the Display +#define S5P_VP_DST_V_POSITION_S S5P_VPROCESSOR_BASE(0x01C0) // Vertical Offset in the Display +#define S5P_VP_DST_WIDTH_S S5P_VPROCESSOR_BASE(0x01C4) // Width of the Display +#define S5P_VP_DST_HEIGHT_S S5P_VPROCESSOR_BASE(0x01C8) // Height of the Display +#define S5P_VP_H_RATIO_S S5P_VPROCESSOR_BASE(0x01CC) // Horizontal Zoom Ratio of SRC:DST +#define S5P_VP_V_RATIO_S S5P_VPROCESSOR_BASE(0x01D0) // Vertical Zoom Ratio of SRC:DST +#define S5P_PP_BYPASS_S S5P_VPROCESSOR_BASE(0x0258) // Disable the Post Image Processor +#define S5P_PP_SATURATION_S S5P_VPROCESSOR_BASE(0x025C) // Color Saturation Factor +#define S5P_PP_SHARPNESS_S S5P_VPROCESSOR_BASE(0x0260) // Control for the Edge Enhancement +#define S5P_PP_LINE_EQ0_S S5P_VPROCESSOR_BASE(0x0268) // Line Equation for Contrast Duration "0" +#define S5P_PP_LINE_EQ1_S S5P_VPROCESSOR_BASE(0x026C) // Line Equation for Contrast Duration "1" +#define S5P_PP_LINE_EQ2_S S5P_VPROCESSOR_BASE(0x0270) // Line Equation for Contrast Duration "2" +#define S5P_PP_LINE_EQ3_S S5P_VPROCESSOR_BASE(0x0274) // Line Equation for Contrast Duration "3" +#define S5P_PP_LINE_EQ4_S S5P_VPROCESSOR_BASE(0x0278) // Line Equation for Contrast Duration "4" +#define S5P_PP_LINE_EQ5_S S5P_VPROCESSOR_BASE(0x027C) // Line Equation for Contrast Duration "5" +#define S5P_PP_LINE_EQ6_S S5P_VPROCESSOR_BASE(0x0280) // Line Equation for Contrast Duration "6" +#define S5P_PP_LINE_EQ7_S S5P_VPROCESSOR_BASE(0x0284) // Line Equation for Contrast Duration "7" +#define S5P_PP_BRIGHT_OFFSET_S S5P_VPROCESSOR_BASE(0x0288) // Brightness Offset Control for Y +#define S5P_PP_CSC_EN_S S5P_VPROCESSOR_BASE(0x028C) // Color Space Conversion Control +#define S5P_PP_CSC_Y2Y_COEF_S S5P_VPROCESSOR_BASE(0x0290) // Y to Y CSC Coefficient Setting +#define S5P_PP_CSC_CB2Y_COEF_S S5P_VPROCESSOR_BASE(0x0294) // CB to Y CSC Coefficient Setting +#define S5P_PP_CSC_CR2Y_COEF_S S5P_VPROCESSOR_BASE(0x0298) // CR to Y CSC Coefficient Setting +#define S5P_PP_CSC_Y2CB_COEF_S S5P_VPROCESSOR_BASE(0x029C) // Y to Y CSC Coefficient Setting +#define S5P_PP_CSC_CB2CB_COEF_S S5P_VPROCESSOR_BASE(0x02A0) // CB to Y CSC Coefficient Setting +#define S5P_PP_CSC_CR2CB_COEF_S S5P_VPROCESSOR_BASE(0x02A4) // CR to Y CSC Coefficient Setting +#define S5P_PP_CSC_Y2CR_COEF_S S5P_VPROCESSOR_BASE(0x02A8) // Y to Y CSC Coefficient Setting +#define S5P_PP_CSC_CB2CR_COEF_S S5P_VPROCESSOR_BASE(0x02AC) // CB to Y CSC Coefficient Setting +#define S5P_PP_CSC_CR2CR_COEF_S S5P_VPROCESSOR_BASE(0x02B0) // CR to Y CSC Coefficient Setting + +/* + Registers Bit Description +*/ +/* S5P_VP_ENABLE */ +#define S5P_VP_ENABLE_ON (1<<0) +#define S5P_VP_ENABLE_ON_S (1<<2) /* R_ONLY, Shadow bit of the bit [0]*/ + +/* S5P_VP_SRESET */ +#define S5P_VP_SRESET_LAST_COMPLETE (0<<0) +#define S5P_VP_SRESET_PROCESSING (1<<0) + +/* S5P_VP_SHADOW_UPDATE */ +#define S5P_VP_SHADOW_UPDATE_DISABLE (0<<0) +#define S5P_VP_SHADOW_UPDATE_ENABLE (1<<0) + +/* S5P_VP_FIELD_ID */ +#define S5P_VP_FIELD_ID_TOP (0<<0) +#define S5P_VP_FIELD_ID_BOTTOM (1<<0) + +/* S5P_VP_MODE */ +#define S5P_VP_MODE_2D_IPC_ENABLE (1<<1) +#define S5P_VP_MODE_2D_IPC_DISABLE (0<<1) +#define S5P_VP_MODE_FIELD_ID_MAN_TOGGLING (0<<2) +#define S5P_VP_MODE_FIELD_ID_AUTO_TOGGLING (1<<2) +#define S5P_VP_MODE_CROMA_EXPANSION_C_TOP_PTR (0<<3) +#define S5P_VP_MODE_CROMA_EXPANSION_C_TOPBOTTOM_PTR (1<<3) +#define S5P_VP_MODE_MEM_MODE_LINEAR (0<<4) +#define S5P_VP_MODE_MEM_MODE_2D_TILE (1<<4) +#define S5P_VP_MODE_LINE_SKIP_OFF (0<<5) +#define S5P_VP_MODE_LINE_SKIP_ON (1<<5) + +/* S5P_VP_ENDIAN_MODE */ +#define S5P_VP_ENDIAN_MODE_BIG (0<<0) +#define S5P_VP_ENDIAN_MODE_LITTLE (1<<0) + +/* Macros */ +/* S5P_VP_ENABLE */ +#define VP_ON_SW_RESET (1<<2) +#define VP_POWER_DOWN_RDY (1<<1) +#define VP_ON_ENABLE (1<<0) +#define VP_ON_DISABLE (0<<0) + +/* S5P_VP_SRESET */ +#define VP_SOFT_RESET (1<<0) + +/* S5P_VP_SHADOW_UPDATA */ +#define VP_SHADOW_UPDATE_ENABLE (1<<0) +#define VP_SHADOW_UPDATE_DISABLE (0<<0) + +/* S5P_VP_FIELD_ID */ +#define VP_FIELD_ID_BOTTOM (1<<0) +#define VP_FIELD_ID_TOP (0<<0) + +/* S5P_VP_MODE */ +#define VP_LINE_SKIP_ON (1<<5) +#define VP_LINE_SKIP_OFF (0<<5) +#define VP_MEM_2D_MODE (1<<4) +#define VP_MEM_LINEAR_MODE (0<<4) +#define VP_CHROMA_USE_TOP_BOTTOM (1<<3) +#define VP_CHROMA_USE_TOP (0<<3) +#define VP_FIELD_ID_TOGGLE_VSYNC (1<<2) +#define VP_FIELD_ID_TOGGLE_USER (0<<2) +#define VP_2D_IPC_ON (1<<1) +#define VP_2D_IPC_OFF (0<<1) + +/* S5P_VP_TILE_SIZE_x */ +#define VP_IMG_HSIZE(a) ((0x3fff&a)<<16) +#define VP_IMG_VSIZE(a) ((0x3fff&a)<<0) +#define VP_IMG_SIZE_ILLEGAL(a) (0x7&a) + +/* S5P_VP_PER_RATE_CTRL */ +#define VP_PEL_RATE_CTRL(a) ((0x3&a)<<0) +/* +enum VP_PIXEL_RATE +{ + VP_PIXEL_PER_RATE_1_1 = 0, + VP_PIXEL_PER_RATE_1_2 = 1, + VP_PIXEL_PER_RATE_1_3 = 2, + VP_PIXEL_PER_RATE_1_4 = 3 +} +*/ + +/* S5P_VP_TOP_x_PTR , VP_BOT_x_PTR */ +#define VP_PTR_ILLEGAL(a) (0x7&a) + +/* S5P_ VP_ENDIAN_MODE */ +#define VP_LITTLE_ENDIAN_MODE (1<<0) +#define VP_BIG_ENDIAN_MODE (0<<0) + +/* S5P_VP_SRC_H_POSITION */ +#define VP_SRC_H_POSITION(a) ((0x7ff&a)<<4) +#define VP_SRC_X_FRACT_STEP(a) (0xf&a) + +/* S5P_VP_SRC_V_POSITION */ +#define VP_SRC_V_POSITION(a) (0x7ff&a) + +/* S5P_VP_SRC_WIDTH */ +#define VP_SRC_WIDTH(a) (0x7ff&a) + +/* S5P_VP_SRC_WIDTH */ +#define VP_SRC_HEIGHT(a) (0x7ff&a) + +/* S5P_VP_DST_H_POSITION */ +#define VP_DST_H_POSITION(a) (0x7ff&a) + +/* S5P_VP_DST_V_POSITION */ +#define VP_DST_V_POSITION(a) (0x7ff&a) + +/* S5P_VP_DST_WIDTH */ +#define VP_DST_WIDTH(a) (0x7ff&a) + +/* S5P_VP_DST_WIDTH +#define VP_DST_HEIGHT(a) (0x3ff&a) +C110:*/ +#define VP_DST_HEIGHT(a) (0x7ff&a) + +/* S5P_VP_H_RATIO */ +#define VP_H_RATIO(a) (0x7ffff&a) + +/* S5P_VP_V_RATIO */ +#define VP_V_RATIO(a) (0x7ffff&a) + +/* S5P_VP_POLY8_Y0_xx */ +#define VP_POLY8_Y0_x0(a) ((0x7&a)<<24) +#define VP_POLY8_Y0_x1(a) ((0x7&a)<<16) +#define VP_POLY8_Y0_x2(a) ((0x7&a)<<8) +#define VP_POLY8_Y0_x3(a) ((0x7&a)<<0) + +/* S5P_VP_POLY8_Y1_xx */ +#define VP_POLY8_Y1_x0(a) ((0x1f&a)<<24) +#define VP_POLY8_Y1_x1(a) ((0x1f&a)<<16) +#define VP_POLY8_Y1_x2(a) ((0x1f&a)<<8) +#define VP_POLY8_Y1_x3(a) ((0x1f&a)<<0) + +/* VP_POLY8_Y2_xx */ +#define VP_POLY8_Y2_x0(a) ((0x7f&a)<<24) +#define VP_POLY8_Y2_x1(a) ((0x7f&a)<<16) +#define VP_POLY8_Y2_x2(a) ((0x7f&a)<<8) +#define VP_POLY8_Y2_x3(a) ((0x7f&a)<<0) + +/* VP_POLY8_Y3_xx */ +#define VP_POLY8_Y3_x0(a) ((0x7f&a)<<24) +#define VP_POLY8_Y3_x1(a) ((0x7f&a)<<16) +#define VP_POLY8_Y3_x2(a) ((0x7f&a)<<8) +#define VP_POLY8_Y3_x3(a) ((0x7f&a)<<0) + +/* VP_POLY4_Y0_xx */ +#define VP_POLY4_Y0_x0(a) ((0x3f&a)<<24) +#define VP_POLY4_Y0_x1(a) ((0x3f&a)<<16) +#define VP_POLY4_Y0_x2(a) ((0x3f&a)<<8) +#define VP_POLY4_Y0_x3(a) ((0x3f&a)<<0) + +/* VP_POLY4_Y1_xx */ +#define VP_POLY4_Y1_x0(a) ((0x7f&a)<<24) +#define VP_POLY4_Y1_x1(a) ((0x7f&a)<<16) +#define VP_POLY4_Y1_x2(a) ((0x7f&a)<<8) +#define VP_POLY4_Y1_x3(a) ((0x7f&a)<<0) + +/* VP_POLY4_Y2_xx */ +#define VP_POLY4_Y2_x0(a) ((0x7f&a)<<24) +#define VP_POLY4_Y2_x1(a) ((0x7f&a)<<16) +#define VP_POLY4_Y2_x2(a) ((0x7f&a)<<8) +#define VP_POLY4_Y2_x3(a) ((0x7f&a)<<0) + +/* VP_POLY4_Y3_xx */ +#define VP_POLY4_Y3_x0(a) ((0x3f&a)<<24) +#define VP_POLY4_Y3_x1(a) ((0x3f&a)<<16) +#define VP_POLY4_Y3_x2(a) ((0x3f&a)<<8) +#define VP_POLY4_Y3_x3(a) ((0x3f&a)<<0) + +/* VP_POLY4_C0_LL */ +#define VP_POLY4_C0_PH0(a) ((0x7f&a)<<24) +#define VP_POLY4_C0_PH1(a) ((0x7f&a)<<16) +#define VP_POLY4_C0_PH2(a) ((0x7f&a)<<8) +#define VP_POLY4_C0_PH3(a) ((0x7f&a)<<0) + +/* VP_POLY4_C0_LH */ +#define VP_POLY4_C0_PH4(a) ((0x3f&a)<<24) +#define VP_POLY4_C0_PH5(a) ((0x3f&a)<<16) +#define VP_POLY4_C0_PH6(a) ((0x3f&a)<<8) +#define VP_POLY4_C0_PH7(a) ((0x3f&a)<<0) + +/* VP_POLY4_C0_HL */ +#define VP_POLY4_C0_PH8(a) ((0x3f&a)<<24) +#define VP_POLY4_C0_PH9(a) ((0x3f&a)<<16) +#define VP_POLY4_C0_PH10(a) ((0x3f&a)<<8) +#define VP_POLY4_C0_PH11(a) ((0x3f&a)<<0) + +/* VP_POLY4_C0_HH */ +#define VP_POLY4_C0_PH12(a) ((0x1f&a)<<24) +#define VP_POLY4_C0_PH13(a) ((0x1f&a)<<16) +#define VP_POLY4_C0_PH14(a) ((0x1f&a)<<8) +#define VP_POLY4_C0_PH15(a) ((0x1f&a)<<0) + +/* VP_POLY4_C1_LL */ +#define VP_POLY4_C1_PH0(a) ((0xff&a)<<24) +#define VP_POLY4_C1_PH1(a) ((0xff&a)<<16) +#define VP_POLY4_C1_PH2(a) ((0xff&a)<<8) +#define VP_POLY4_C1_PH3(a) ((0xff&a)<<0) + +/* VP_POLY4_C1_LH */ +#define VP_POLY4_C1_PH4(a) ((0xff&a)<<24) +#define VP_POLY4_C1_PH5(a) ((0xff&a)<<16) +#define VP_POLY4_C1_PH6(a) ((0xff&a)<<8) +#define VP_POLY4_C1_PH7(a) ((0xff&a)<<0) + +/* VP_POLY4_C1_HL */ +#define VP_POLY4_C1_PH8(a) ((0xff&a)<<24) +#define VP_POLY4_C1_PH9(a) ((0xff&a)<<16) +#define VP_POLY4_C1_PH10(a) ((0xff&a)<<8) +#define VP_POLY4_C1_PH11(a) ((0xff&a)<<0) + +/* VP_POLY4_C1_HH */ +#define VP_POLY4_C1_PH12(a) ((0x7f&a)<<24) +#define VP_POLY4_C1_PH13(a) ((0x7f&a)<<16) +#define VP_POLY4_C1_PH14(a) ((0x7f&a)<<8) +#define VP_POLY4_C1_PH15(a) ((0x7f&a)<<0) + +/* PP_CSC_COEF */ +#define VP_CSC_COEF(a) (0xfff&a) + +/* PP_BYPASS */ +#define VP_BY_PASS_ENABLE (0) +#define VP_BY_PASS_DISABLE (1) + +/* PP_SATURATION */ +#define VP_SATURATION(a) (0xff&a) + +/* PP_SHARPNESS */ +#define VP_TH_HNOISE(a) ((0xf&a)<<8) +#define VP_SHARPNESS(a) (0x3&a) +/* +enum VP_SHARPNESS_CONTROL +{ + VP_SHARPNESS_NO = 0, + VP_SHARPNESS_MIN = 1, + VP_SHARPNESS_MOD = 2, + VP_SHARPNESS_MAX = 3 +} +*/ + +/* PP_LINE_EQx */ +#define VP_LINE_INTC(a) ((0xffff&a)<<8) +#define VP_LINE_SLOPE(a) (0xff&a) +#define VP_LINE_INTC_CLEAR(a) (~(0xffff<<8)&a) +#define VP_LINE_SLOPE_CLEAR(a) (~0xff&a) + +/* PP_BRIGHT_OFFSET */ +#define VP_BRIGHT_OFFSET(a) (0x1ff&a) + +/* PP_CSC_EN */ +#define VP_SUB_Y_OFFSET_ENABLE (1<<1) +#define VP_SUB_Y_OFFSET_DISABLE (0<<1) +#define VP_CSC_ENABLE (1) +#define VP_CSC_DISABLE (0) + +/* global variables */ +static unsigned int g_vp_contrast_brightness = 0; + +/*#define VP_UPDATE_RETRY_MAXIMUM 30 +#define VP_WAIT_UPDATE_SLEEP 3 */ + +/* Ref. to VP manual p37-39 + [11] : sign bit, [10] : integer bit, [9:0] : fraction bit + CSC from BT.601(SD) to BT.709(HD) */ +#define Y2Y_COEF_601_TO_709 0x400 // 1.0 +#define CB2Y_COEF_601_TO_709 0x879 // about -0.118188 ex) 0.118188*1024 = 121.024512 --> about 121 convert to hex(0x79) +#define CR2Y_COEF_601_TO_709 0x8d9 // about -0.212685 + +#define Y2CB_COEF_601_TO_709 0x0 // 0 +#define CB2CB_COEF_601_TO_709 0x413 // about 1.018640 +#define CR2CB_COEF_601_TO_709 0x875 // about -0.114618 + +#define Y2CR_COEF_601_TO_709 0x0 +#define CB2CR_COEF_601_TO_709 0x04d // about 0.075049 +#define CR2CR_COEF_601_TO_709 0x41a // about 1.025327 + +/* CSC from BT.709(HD) to BT.601(SD) */ +#define Y2Y_COEF_709_TO_601 0x400 +#define CB2Y_COEF_709_TO_601 0x068 // about 0.101579 +#define CR2Y_COEF_709_TO_601 0x0c9 // about 0.196076 + +#define Y2CB_COEF_709_TO_601 0x0 +#define CB2CB_COEF_709_TO_601 0x3f6 // about 0.989854 +#define CR2CB_COEF_709_TO_601 0x871 // about -0.110653 + +#define Y2CR_COEF_709_TO_601 0x0 +#define CB2CR_COEF_709_TO_601 0x84a // about -0.072453 +#define CR2CR_COEF_709_TO_601 0xbef // about -0.983398 + +#define TILE_WIDTH 0x40 +#define MAX_NUM_OF_FRM 34 // according to MFC + +#endif /* __ASM_ARCH_REGS_VPROCESSOR_H */ + diff --git a/drivers/media/video/samsung/tv20/s5pv210/sdout_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/sdout_s5pv210.c new file mode 100644 index 0000000..4a4ea66 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/sdout_s5pv210.c @@ -0,0 +1,2038 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/sdout_s5pv210.c + * + * tv encoder raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/memory.h> +#include <linux/mm.h> + +#include <plat/clock.h> +#include "tv_out_s5pv210.h" + +#include "regs/regs-sdaout.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_SDAOUT_DEBUG 1 +#endif + +#ifdef S5P_SDAOUT_DEBUG +#define SDPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[SDOUT] %s: " fmt, __func__ , ## args) +#else +#define SDPRINTK(fmt, args...) +#endif + +static struct resource *sdout_mem; +void __iomem *sdout_base; + +/* +* initialization - iniization functions are only called under stopping SDOUT +*/ +enum s5p_tv_sd_err __s5p_sdout_init_video_scale_cfg( + enum s5p_sd_level component_level, + enum s5p_sd_vsync_ratio component_ratio, + enum s5p_sd_level composite_level, + enum s5p_sd_vsync_ratio composite_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d\n\r", component_level, component_ratio, + composite_level, composite_ratio); + + switch (component_level) { + + case S5P_TV_SD_LEVEL_0IRE: + temp_reg = SDO_COMPONENT_LEVEL_SEL_0IRE; + break; + + case S5P_TV_SD_LEVEL_75IRE: + temp_reg = SDO_COMPONENT_LEVEL_SEL_75IRE; + break; + + default: + SDPRINTK("invalid component_level parameter(%d)\n\r", + component_level); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (composite_level) { + + case SDOUT_VTOS_RATIO_10_4: + temp_reg |= SDO_COMPONENT_VTOS_RATIO_10_4; + break; + + case SDOUT_VTOS_RATIO_7_3: + temp_reg |= SDO_COMPONENT_VTOS_RATIO_7_3; + break; + + default: + SDPRINTK(" invalid composite_level parameter(%d)\n\r", + composite_level); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (composite_level) { + + case S5P_TV_SD_LEVEL_0IRE: + temp_reg |= SDO_COMPOSITE_LEVEL_SEL_0IRE; + break; + + case S5P_TV_SD_LEVEL_75IRE: + temp_reg |= SDO_COMPOSITE_LEVEL_SEL_75IRE; + break; + + default: + SDPRINTK("invalid composite_ratio parameter(%d)\n\r", + composite_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (composite_ratio) { + + case SDOUT_VTOS_RATIO_10_4: + temp_reg |= SDO_COMPOSITE_VTOS_RATIO_10_4; + break; + + case SDOUT_VTOS_RATIO_7_3: + temp_reg |= SDO_COMPOSITE_VTOS_RATIO_7_3; + break; + + default: + SDPRINTK("invalid component_ratio parameter(%d)\n\r", + component_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_SCALE); + + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_SCALE)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_sync_signal_pin( + enum s5p_sd_sync_sig_pin pin) +{ + SDPRINTK("%d\n\r", pin); + + switch (pin) { + + case SDOUT_SYNC_SIG_NO: + writel(SDO_COMPONENT_SYNC_ABSENT, sdout_base + S5P_SDO_SYNC); + break; + + case SDOUT_SYNC_SIG_YG: + writel(SDO_COMPONENT_SYNC_YG, sdout_base + S5P_SDO_SYNC); + break; + + case SDOUT_SYNC_SIG_ALL: + writel(SDO_COMPONENT_SYNC_ALL, sdout_base + S5P_SDO_SYNC); + break; + + default: + SDPRINTK("invalid pin parameter(%d)\n\r", pin); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_SYNC)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_vbi(bool wss_cvbs, + enum s5p_sd_closed_caption_type caption_cvbs, + bool wss_y_sideo, + enum s5p_sd_closed_caption_type caption_y_sideo, + bool cgmsa_rgb, + bool wss_rgb, + enum s5p_sd_closed_caption_type caption_rgb, + bool cgmsa_y_ppr, + bool wss_y_ppr, + enum s5p_sd_closed_caption_type caption_y_ppr) +{ + u32 temp_reg = 0; + + SDPRINTK(" %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n\r", + wss_cvbs, caption_cvbs, + wss_y_sideo, caption_y_sideo, cgmsa_rgb, wss_rgb, caption_rgb, + cgmsa_y_ppr, wss_y_ppr, caption_y_ppr); + + if (wss_cvbs) + temp_reg = SDO_CVBS_WSS_INS; + else + temp_reg = SDO_CVBS_NO_WSS; + + + switch (caption_cvbs) { + + case SDOUT_NO_INS: + temp_reg |= SDO_CVBS_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_CVBS_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_CVBS_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_CVBS_USE_OTHERS; + break; + + default: + SDPRINTK(" invalid caption_cvbs parameter(%d)\n\r", + caption_cvbs); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (wss_y_sideo) + temp_reg |= SDO_SVIDEO_WSS_INS; + else + temp_reg |= SDO_SVIDEO_NO_WSS; + + + switch (caption_y_sideo) { + + case SDOUT_NO_INS: + temp_reg |= SDO_SVIDEO_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_SVIDEO_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_SVIDEO_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_SVIDEO_USE_OTHERS; + break; + + default: + SDPRINTK("invalid caption_y_sideo parameter(%d)\n\r", + caption_y_sideo); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (cgmsa_rgb) + temp_reg |= SDO_RGB_CGMSA_INS; + else + temp_reg |= SDO_RGB_NO_CGMSA; + + + if (wss_rgb) + temp_reg |= SDO_RGB_WSS_INS; + else + temp_reg |= SDO_RGB_NO_WSS; + + + switch (caption_rgb) { + + case SDOUT_NO_INS: + temp_reg |= SDO_RGB_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_RGB_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_RGB_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_RGB_USE_OTHERS; + break; + + default: + SDPRINTK(" invalid caption_rgb parameter(%d)\n\r", + caption_rgb); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (cgmsa_y_ppr) + temp_reg |= SDO_YPBPR_CGMSA_INS; + else + temp_reg |= SDO_YPBPR_NO_CGMSA; + + + if (wss_y_ppr) + temp_reg |= SDO_YPBPR_WSS_INS; + else + temp_reg |= SDO_YPBPR_NO_WSS; + + + switch (caption_y_ppr) { + + case SDOUT_NO_INS: + temp_reg |= SDO_YPBPR_NO_CLOSED_CAPTION; + break; + + case SDOUT_INS_1: + temp_reg |= SDO_YPBPR_21H_CLOSED_CAPTION; + break; + + case SDOUT_INS_2: + temp_reg |= SDO_YPBPR_21H_284H_CLOSED_CAPTION; + break; + + case SDOUT_INS_OTHERS: + temp_reg |= SDO_YPBPR_USE_OTHERS; + break; + + default: + SDPRINTK("invalid caption_y_ppr parameter(%d)\n\r", + caption_y_ppr); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_VBI); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_VBI)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_offset_gain( + enum s5p_sd_channel_sel channel, + u32 offset, u32 gain) +{ + SDPRINTK("%d, %d, %d\n\r", channel, offset, gain); + + switch (channel) { + + case SDOUT_CHANNEL_0: + writel(SDO_SCALE_CONV_OFFSET(offset) | + SDO_SCALE_CONV_GAIN(gain), + sdout_base + S5P_SDO_SCALE_CH0); + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_SCALE_CH0)); + break; + + case SDOUT_CHANNEL_1: + writel(SDO_SCALE_CONV_OFFSET(offset) | + SDO_SCALE_CONV_GAIN(gain), + sdout_base + S5P_SDO_SCALE_CH1); + SDPRINTK(" 0x%08x\n\r", readl(sdout_base + S5P_SDO_SCALE_CH1)); + break; + + case SDOUT_CHANNEL_2: + writel(SDO_SCALE_CONV_OFFSET(offset) | + SDO_SCALE_CONV_GAIN(gain), + sdout_base + S5P_SDO_SCALE_CH2); + SDPRINTK(" 0x%08x\n\r", readl(sdout_base + S5P_SDO_SCALE_CH2)); + break; + + default: + SDPRINTK(" invalid channel parameter(%d)\n\r", channel); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_delay(u32 delay_y, + u32 offset_video_start, + u32 offset_video_end) +{ + SDPRINTK("%d, %d, %d\n\r", delay_y, offset_video_start, + offset_video_end); + + writel(SDO_DELAY_YTOC(delay_y) | + SDO_ACTIVE_START_OFFSET(offset_video_start) | + SDO_ACTIVE_END_OFFSET(offset_video_end), + sdout_base + S5P_SDO_YCDELAY); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_YCDELAY)); +} + +void __s5p_sdout_init_schlock(bool color_sucarrier_pha_adj) +{ + SDPRINTK("%d\n\r", color_sucarrier_pha_adj); + + if (color_sucarrier_pha_adj) + writel(SDO_COLOR_SC_PHASE_ADJ, sdout_base + S5P_SDO_SCHLOCK); + else + writel(SDO_COLOR_SC_PHASE_NOADJ, sdout_base + S5P_SDO_SCHLOCK); + + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_SCHLOCK)); +} + +enum s5p_tv_sd_err __s5p_sdout_init_dac_power_onoff( + enum s5p_sd_channel_sel channel, bool dac_on) +{ + u32 temp_on_off; + + SDPRINTK("%d, %d)\n\r", channel, dac_on); + + switch (channel) { + + case SDOUT_CHANNEL_0: + temp_on_off = SDO_POWER_ON_DAC0; + break; + + case SDOUT_CHANNEL_1: + temp_on_off = SDO_POWER_ON_DAC1; + break; + + case SDOUT_CHANNEL_2: + temp_on_off = SDO_POWER_ON_DAC2; + break; + + default: + SDPRINTK("invalid channel parameter(%d)\n\r", channel); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (dac_on) + writel(readl(sdout_base + S5P_SDO_DAC) | temp_on_off, + sdout_base + S5P_SDO_DAC); + else + writel(readl(sdout_base + S5P_SDO_DAC) & ~temp_on_off, + sdout_base + S5P_SDO_DAC); + + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_DAC)); + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_color_compensaton_onoff(bool bright_hue_saturation_adj, + bool y_ppr_color_compensation, + bool rgcolor_compensation, + bool y_c_color_compensation, + bool y_cvbs_color_compensation) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d, %d)\n\r", bright_hue_saturation_adj, + y_ppr_color_compensation, rgcolor_compensation, + y_c_color_compensation, y_cvbs_color_compensation); + + if (bright_hue_saturation_adj) + temp_reg &= ~SDO_COMPONENT_BHS_ADJ_OFF; + else + temp_reg |= SDO_COMPONENT_BHS_ADJ_OFF; + + + if (y_ppr_color_compensation) + temp_reg &= ~SDO_COMPONENT_YPBPR_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_YPBPR_COMP_OFF; + + + if (rgcolor_compensation) + temp_reg &= ~SDO_COMPONENT_RGB_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_RGB_COMP_OFF; + + + if (y_c_color_compensation) + temp_reg &= ~SDO_COMPONENT_YC_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_YC_COMP_OFF; + + + if (y_cvbs_color_compensation) + temp_reg &= ~SDO_COMPONENT_CVBS_COMP_OFF; + else + temp_reg |= SDO_COMPONENT_CVBS_COMP_OFF; + + + writel(temp_reg, sdout_base + S5P_SDO_CCCON); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_CCCON)); +} + +void __s5p_sdout_init_brightness_hue_saturation(u32 gain_brightness, + u32 offset_brightness, + u32 gain0_cb_hue_saturation, + u32 gain1_cb_hue_saturation, + u32 gain0_cr_hue_saturation, + u32 gain1_cr_hue_saturation, + u32 offset_cb_hue_saturation, + u32 offset_cr_hue_saturation) +{ + SDPRINTK(" %d, %d, %d, %d, %d, %d, %d, %d)\n\r", gain_brightness, + offset_brightness, gain0_cb_hue_saturation, + gain1_cb_hue_saturation, gain0_cr_hue_saturation, + gain1_cr_hue_saturation, offset_cb_hue_saturation, + offset_cr_hue_saturation); + + writel(SDO_BRIGHTNESS_GAIN(gain_brightness) | + SDO_BRIGHTNESS_OFFSET(offset_brightness), + sdout_base + S5P_SDO_YSCALE); + + writel(SDO_HS_CB_GAIN0(gain0_cb_hue_saturation) | + SDO_HS_CB_GAIN1(gain1_cb_hue_saturation), + sdout_base + S5P_SDO_CBSCALE); + + writel(SDO_HS_CR_GAIN0(gain0_cr_hue_saturation) | + SDO_HS_CR_GAIN1(gain1_cr_hue_saturation), + sdout_base + S5P_SDO_CRSCALE); + + writel(SDO_HS_CR_OFFSET(offset_cr_hue_saturation) | + SDO_HS_CB_OFFSET(offset_cb_hue_saturation), + sdout_base + S5P_SDO_CB_CR_OFFSET); + + SDPRINTK("0x%08x, 0x%08x, 0x%08x, 0x%08x)\n\r", + readl(sdout_base + S5P_SDO_YSCALE), + readl(sdout_base + S5P_SDO_CBSCALE), + readl(sdout_base + S5P_SDO_CRSCALE), + readl(sdout_base + S5P_SDO_CB_CR_OFFSET)); +} + +void __s5p_sdout_init_rgb_color_compensation(u32 max_rgbcube, + u32 min_rgbcube) +{ + SDPRINTK("0x%08x, 0x%08x\n\r", max_rgbcube, min_rgbcube); + + writel(SDO_MAX_RGB_CUBE(max_rgbcube) | SDO_MIN_RGB_CUBE(min_rgbcube), + sdout_base + S5P_SDO_RGB_CC); + + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_RGB_CC)); +} + +void __s5p_sdout_init_cvbs_color_compensation(u32 y_lower_mid, + u32 y_bottom, + u32 y_top, + u32 y_upper_mid, + u32 radius) +{ + SDPRINTK("%d, %d, %d, %d, %d\n\r", y_lower_mid, y_bottom, y_top, + y_upper_mid, radius); + + writel(SDO_Y_LOWER_MID_CVBS_CORN(y_lower_mid) | + SDO_Y_BOTTOM_CVBS_CORN(y_bottom), + sdout_base + S5P_SDO_CVBS_CC_Y1); + writel(SDO_Y_TOP_CVBS_CORN(y_top) | + SDO_Y_UPPER_MID_CVBS_CORN(y_upper_mid), + sdout_base + S5P_SDO_CVBS_CC_Y2); + writel(SDO_RADIUS_CVBS_CORN(radius), sdout_base + S5P_SDO_CVBS_CC_C); + + SDPRINTK("0x%08x, 0x%08x, 0x%08x)\n\r", + readl(sdout_base + S5P_SDO_CVBS_CC_Y1), + readl(sdout_base + S5P_SDO_CVBS_CC_Y2), + readl(sdout_base + S5P_SDO_CVBS_CC_C)); +} + +void __s5p_sdout_init_svideo_color_compensation(u32 y_top, + u32 y_bottom, + u32 y_c_cylinder) +{ + SDPRINTK(" %d, %d, %d)\n\r", y_top, y_bottom, y_c_cylinder); + + writel(SDO_Y_TOP_YC_CYLINDER(y_top) | + SDO_Y_BOTOM_YC_CYLINDER(y_bottom), + sdout_base + S5P_SDO_YC_CC_Y); + writel(SDO_RADIUS_YC_CYLINDER(y_c_cylinder), + sdout_base + S5P_SDO_YC_CC_C); + + SDPRINTK("0x%08x, 0x%08x)\n\r", readl(sdout_base + S5P_SDO_YC_CC_Y), + readl(sdout_base + S5P_SDO_YC_CC_C)); +} + +void __s5p_sdout_init_component_porch(u32 back_525, + u32 front_525, + u32 back_625, + u32 front_625) +{ + SDPRINTK(" %d, %d, %d, %d)\n\r", back_525, + front_525, back_625, front_625); + + writel(SDO_COMPONENT_525_BP(back_525) | + SDO_COMPONENT_525_FP(front_525), + sdout_base + S5P_SDO_CSC_525_PORCH); + writel(SDO_COMPONENT_625_BP(back_625) | + SDO_COMPONENT_625_FP(front_625), + sdout_base + S5P_SDO_CSC_625_PORCH); + + SDPRINTK(" 0x%08x, 0x%08x)\n\r", + readl(sdout_base + S5P_SDO_CSC_525_PORCH), + readl(sdout_base + S5P_SDO_CSC_625_PORCH)); +} + +enum s5p_tv_sd_err __s5p_sdout_init_vesa_rgb_sync( + enum s5p_sd_vesa_rgb_sync_type sync_type, + enum s5p_tv_active_polarity v_sync_active, + enum s5p_tv_active_polarity h_sync_active) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d\n\r", sync_type, v_sync_active, h_sync_active); + + switch (sync_type) { + + case SDOUT_VESA_RGB_SYNC_COMPOSITE: + temp_reg |= SDO_RGB_SYNC_COMPOSITE; + break; + + case SDOUT_VESA_RGB_SYNC_SEPARATE: + temp_reg |= SDO_RGB_SYNC_SEPERATE; + break; + + default: + SDPRINTK(" invalid sync_type parameter(%d)\n\r", sync_type); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (v_sync_active) { + + case TVOUT_POL_ACTIVE_LOW: + temp_reg |= SDO_RGB_VSYNC_LOW_ACT; + break; + + case TVOUT_POL_ACTIVE_HIGH: + temp_reg |= SDO_RGB_VSYNC_HIGH_ACT; + break; + + default: + SDPRINTK(" invalid v_sync_active parameter(%d)\n\r", + v_sync_active); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (h_sync_active) { + + case TVOUT_POL_ACTIVE_LOW: + temp_reg |= SDO_RGB_HSYNC_LOW_ACT; + break; + + case TVOUT_POL_ACTIVE_HIGH: + temp_reg |= SDO_RGB_HSYNC_HIGH_ACT; + break; + + default: + SDPRINTK(" invalid h_sync_active parameter(%d)\n\r", + h_sync_active); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_RGBSYNC); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_RGBSYNC)); + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_oversampling_filter_coeff(u32 size, + u32 *coeff, + u32 *coeff1, + u32 *coeff2) +{ + u32 *temp_reg = 0; + + SDPRINTK(" %d, 0x%x, 0x%x, 0x%x\n\r", (u32)size, (u32)coeff, + (u32)coeff1, (u32)coeff2); + + if (coeff != NULL) { + temp_reg = (u32 *)readl(sdout_base + S5P_SDO_OSFC00_0); + memcpy((void *)temp_reg, (const void *)coeff, size*4); + } + + if (coeff1 != NULL) { + temp_reg = (u32 *)readl(sdout_base + S5P_SDO_OSFC00_1); + memcpy((void *)temp_reg, (const void *)coeff1, size*4); + } + + if (coeff2 != NULL) { + temp_reg = (u32 *)readl(sdout_base + S5P_SDO_OSFC00_2); + memcpy((void *)temp_reg, (const void *)coeff2, size*4); + } + + SDPRINTK(" ()\n\r"); +} + +enum s5p_tv_sd_err __s5p_sdout_init_ch_xtalk_cancel_coef( + enum s5p_sd_channel_sel channel, + u32 coeff2, u32 coeff1) +{ + SDPRINTK(" %d, %d, %d\n\r", channel, coeff2, coeff1); + + switch (channel) { + + case SDOUT_CHANNEL_0: + writel(SDO_XTALK_COEF02(coeff2) | SDO_XTALK_COEF01(coeff1), + sdout_base + S5P_SDO_XTALK0); + SDPRINTK(" 0x%08x)\n\r", readl(sdout_base + S5P_SDO_XTALK0)); + break; + + case SDOUT_CHANNEL_1: + writel(SDO_XTALK_COEF02(coeff2) | SDO_XTALK_COEF01(coeff1), + sdout_base + S5P_SDO_XTALK1); + SDPRINTK(" 0x%08x)\n\r", readl(sdout_base + S5P_SDO_XTALK1)); + break; + + case SDOUT_CHANNEL_2: + writel(SDO_XTALK_COEF02(coeff2) | SDO_XTALK_COEF01(coeff1), + sdout_base + S5P_SDO_XTALK2); + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_XTALK2)); + break; + + default: + SDPRINTK(" invalid channel parameter(%d)\n\r", channel); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + return SDOUT_NO_ERROR; +} + +void __s5p_sdout_init_closed_caption(u32 display_cc, u32 non_display_cc) +{ + SDPRINTK("%d, %d\n\r", display_cc, non_display_cc); + + writel(SDO_DISPLAY_CC_CAPTION(display_cc) | + SDO_NON_DISPLAY_CC_CAPTION(non_display_cc), + sdout_base + S5P_SDO_ARMCC); + + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_ARMCC)); +} + + +/* static functions */ +static u32 __s5p_sdout_init_wss_cgms_crc(u32 value) +{ + u8 i; + u8 CGMS[14], CRC[6], OLD_CRC; + u32 temp_in; + + temp_in = value; + + for (i = 0; i < 14; i++) + CGMS[i] = (u8)(temp_in >> i) & 0x1 ; + + /* initialize state */ + for (i = 0; i < 6; i++) + CRC[i] = 0x1; + + /* round 20 */ + for (i = 0; i < 14; i++) { + OLD_CRC = CRC[0]; + CRC[0] = CRC[1]; + CRC[1] = CRC[2]; + CRC[2] = CRC[3]; + CRC[3] = CRC[4]; + CRC[4] = OLD_CRC ^ CGMS[i] ^ CRC[5]; + CRC[5] = OLD_CRC ^ CGMS[i]; + } + + /* recompose to return crc */ + temp_in &= 0x3fff; + + for (i = 0; i < 6; i++) + temp_in |= ((u32)(CRC[i] & 0x1) << i); + + + return temp_in; +} + + +enum s5p_tv_sd_err __s5p_sdout_init_wss525_data( + enum s5p_sd_525_copy_permit copy_permit, + enum s5p_sd_525_mv_psp mv_psp, + enum s5p_sd_525_copy_info copy_info, + bool analog_on, + enum s5p_sd_525_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d\n\r", copy_permit, mv_psp, copy_info, + display_ratio); + + switch (copy_permit) { + + case SDO_525_COPY_PERMIT: + temp_reg = SDO_WORD2_WSS525_COPY_PERMIT; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg = SDO_WORD2_WSS525_ONECOPY_PERMIT; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg = SDO_WORD2_WSS525_NOCOPY_PERMIT; + break; + + default: + SDPRINTK(" invalid copy_permit parameter(%d)\n\r", copy_permit); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (mv_psp) { + + case SDO_525_MV_PSP_OFF: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_OFF; + break; + + case SDO_525_MV_PSP_ON_2LINE_BURST: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_ON_2LINE_BURST; + break; + + case SDO_525_MV_PSP_ON_BURST_OFF: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_ON_BURST_OFF; + break; + + case SDO_525_MV_PSP_ON_4LINE_BURST: + temp_reg |= SDO_WORD2_WSS525_MV_PSP_ON_4LINE_BURST; + break; + + default: + SDPRINTK(" invalid mv_psp parameter(%d)\n\r", mv_psp); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (copy_info) { + + case SDO_525_COPY_INFO: + temp_reg |= SDO_WORD1_WSS525_COPY_INFO; + break; + + case SDO_525_DEFAULT: + temp_reg |= SDO_WORD1_WSS525_DEFAULT; + break; + + default: + SDPRINTK(" invalid copy_info parameter(%d)\n\r", copy_info); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (analog_on) + temp_reg |= SDO_WORD2_WSS525_ANALOG_ON; + else + temp_reg |= SDO_WORD2_WSS525_ANALOG_OFF; + + + switch (display_ratio) { + + case SDO_525_COPY_PERMIT: + temp_reg |= SDO_WORD0_WSS525_4_3_NORMAL; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg |= SDO_WORD0_WSS525_16_9_ANAMORPIC; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg |= SDO_WORD0_WSS525_4_3_LETTERBOX; + break; + + default: + SDPRINTK(" invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg | + SDO_CRC_WSS525(__s5p_sdout_init_wss_cgms_crc(temp_reg)), + sdout_base + S5P_SDO_WSS525); + + SDPRINTK("0x%08x)\n\r", readl(sdout_base + S5P_SDO_WSS525)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_wss625_data(bool surround_sound, + bool copyright, + bool copy_protection, + bool text_subtitles, + enum s5p_sd_625_subtitles open_subtitles, + enum s5p_sd_625_camera_film camera_film, + enum s5p_sd_625_color_encoding color_encoding, + bool helper_signal, + enum s5p_sd_625_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d, %d, %d, %d, %d, %d\n\r", + surround_sound, copyright, copy_protection, + text_subtitles, open_subtitles, camera_film, + color_encoding, helper_signal, display_ratio); + + if (surround_sound) + temp_reg = SDO_WSS625_SURROUND_SOUND_ENABLE; + else + temp_reg = SDO_WSS625_SURROUND_SOUND_DISABLE; + + + if (copyright) + temp_reg |= SDO_WSS625_COPYRIGHT; + else + temp_reg |= SDO_WSS625_NO_COPYRIGHT; + + + if (copy_protection) + temp_reg |= SDO_WSS625_COPY_RESTRICTED; + else + temp_reg |= SDO_WSS625_COPY_NOT_RESTRICTED; + + + if (text_subtitles) + temp_reg |= SDO_WSS625_TELETEXT_SUBTITLES; + else + temp_reg |= SDO_WSS625_TELETEXT_NO_SUBTITLES; + + + switch (open_subtitles) { + + case SDO_625_NO_OPEN_SUBTITLES: + temp_reg |= SDO_WSS625_NO_OPEN_SUBTITLES; + break; + + case SDO_625_INACT_OPEN_SUBTITLES: + temp_reg |= SDO_WSS625_INACT_OPEN_SUBTITLES; + break; + + case SDO_625_OUTACT_OPEN_SUBTITLES: + temp_reg |= SDO_WSS625_OUTACT_OPEN_SUBTITLES; + break; + + default: + SDPRINTK(" invalid open_subtitles parameter(%d)\n\r", + open_subtitles); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (camera_film) { + + case SDO_625_CAMERA: + temp_reg |= SDO_WSS625_CAMERA; + break; + + case SDO_625_FILM: + temp_reg |= SDO_WSS625_FILM; + break; + + default: + SDPRINTK("invalid camera_film parameter(%d)\n\r", + camera_film); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (color_encoding) { + + case SDO_625_NORMAL_PAL: + temp_reg |= SDO_WSS625_NORMAL_PAL; + break; + + case SDO_625_MOTION_ADAPTIVE_COLORPLUS: + temp_reg |= SDO_WSS625_MOTION_ADAPTIVE_COLORPLUS; + break; + + default: + SDPRINTK("invalid color_encoding parameter(%d)\n\r", + color_encoding); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (helper_signal) + temp_reg |= SDO_WSS625_HELPER_SIG; + else + temp_reg |= SDO_WSS625_HELPER_NO_SIG; + + + switch (display_ratio) { + + case SDO_625_4_3_FULL_576: + temp_reg |= SDO_WSS625_4_3_FULL_576; + break; + + case SDO_625_14_9_LETTERBOX_CENTER_504: + temp_reg |= SDO_WSS625_14_9_LETTERBOX_CENTER_504; + break; + + case SDO_625_14_9_LETTERBOX_TOP_504: + temp_reg |= SDO_WSS625_14_9_LETTERBOX_TOP_504; + break; + + case SDO_625_16_9_LETTERBOX_CENTER_430: + temp_reg |= SDO_WSS625_16_9_LETTERBOX_CENTER_430; + break; + + case SDO_625_16_9_LETTERBOX_TOP_430: + temp_reg |= SDO_WSS625_16_9_LETTERBOX_TOP_430; + break; + + case SDO_625_16_9_LETTERBOX_CENTER: + temp_reg |= SDO_WSS625_16_9_LETTERBOX_CENTER; + break; + + case SDO_625_14_9_FULL_CENTER_576: + temp_reg |= SDO_WSS625_14_9_FULL_CENTER_576; + break; + + case SDO_625_16_9_ANAMORPIC_576: + temp_reg |= SDO_WSS625_16_9_ANAMORPIC_576; + break; + + default: + SDPRINTK("invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_WSS625); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_WSS625)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_cgmsa525_data( + enum s5p_sd_525_copy_permit copy_permit, + enum s5p_sd_525_mv_psp mv_psp, + enum s5p_sd_525_copy_info copy_info, + bool analog_on, + enum s5p_sd_525_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d)\n\r", copy_permit, mv_psp, copy_info, + display_ratio); + + switch (copy_permit) { + + case SDO_525_COPY_PERMIT: + temp_reg = SDO_WORD2_CGMS525_COPY_PERMIT; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg = SDO_WORD2_CGMS525_ONECOPY_PERMIT; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg = SDO_WORD2_CGMS525_NOCOPY_PERMIT; + break; + + default: + SDPRINTK("invalid copy_permit parameter(%d)\n\r", copy_permit); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (mv_psp) { + + case SDO_525_MV_PSP_OFF: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_OFF; + break; + + case SDO_525_MV_PSP_ON_2LINE_BURST: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_ON_2LINE_BURST; + break; + + case SDO_525_MV_PSP_ON_BURST_OFF: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_ON_BURST_OFF; + break; + + case SDO_525_MV_PSP_ON_4LINE_BURST: + temp_reg |= SDO_WORD2_CGMS525_MV_PSP_ON_4LINE_BURST; + break; + + default: + SDPRINTK(" invalid mv_psp parameter(%d)\n\r", mv_psp); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (copy_info) { + + case SDO_525_COPY_INFO: + temp_reg |= SDO_WORD1_CGMS525_COPY_INFO; + break; + + case SDO_525_DEFAULT: + temp_reg |= SDO_WORD1_CGMS525_DEFAULT; + break; + + default: + SDPRINTK("invalid copy_info parameter(%d)\n\r", copy_info); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (analog_on) + temp_reg |= SDO_WORD2_CGMS525_ANALOG_ON; + else + temp_reg |= SDO_WORD2_CGMS525_ANALOG_OFF; + + + switch (display_ratio) { + + case SDO_525_COPY_PERMIT: + temp_reg |= SDO_WORD0_CGMS525_4_3_NORMAL; + break; + + case SDO_525_ONECOPY_PERMIT: + temp_reg |= SDO_WORD0_CGMS525_16_9_ANAMORPIC; + break; + + case SDO_525_NOCOPY_PERMIT: + temp_reg |= SDO_WORD0_CGMS525_4_3_LETTERBOX; + break; + + default: + SDPRINTK(" invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg | SDO_CRC_CGMS525( + __s5p_sdout_init_wss_cgms_crc(temp_reg)), + sdout_base + S5P_SDO_CGMS525); + + SDPRINTK(" 0x%08x)\n\r", readl(sdout_base + S5P_SDO_CGMS525)); + + return SDOUT_NO_ERROR; +} + +enum s5p_tv_sd_err __s5p_sdout_init_cgmsa625_data(bool surround_sound, + bool copyright, + bool copy_protection, + bool text_subtitles, + enum s5p_sd_625_subtitles open_subtitles, + enum s5p_sd_625_camera_film camera_film, + enum s5p_sd_625_color_encoding color_encoding, + bool helper_signal, + enum s5p_sd_625_aspect_ratio display_ratio) +{ + u32 temp_reg = 0; + + SDPRINTK("%d, %d, %d, %d, %d, %d, %d, %d, %d)\n\r", surround_sound, + copyright, copy_protection, + text_subtitles, open_subtitles, + camera_film, color_encoding, helper_signal, + display_ratio); + + if (surround_sound) + temp_reg = SDO_CGMS625_SURROUND_SOUND_ENABLE; + else + temp_reg = SDO_CGMS625_SURROUND_SOUND_DISABLE; + + + if (copyright) + temp_reg |= SDO_CGMS625_COPYRIGHT; + else + temp_reg |= SDO_CGMS625_NO_COPYRIGHT; + + + if (copy_protection) + temp_reg |= SDO_CGMS625_COPY_RESTRICTED; + else + temp_reg |= SDO_CGMS625_COPY_NOT_RESTRICTED; + + + if (text_subtitles) + temp_reg |= SDO_CGMS625_TELETEXT_SUBTITLES; + else + temp_reg |= SDO_CGMS625_TELETEXT_NO_SUBTITLES; + + + switch (open_subtitles) { + + case SDO_625_NO_OPEN_SUBTITLES: + temp_reg |= SDO_CGMS625_NO_OPEN_SUBTITLES; + break; + + case SDO_625_INACT_OPEN_SUBTITLES: + temp_reg |= SDO_CGMS625_INACT_OPEN_SUBTITLES; + break; + + case SDO_625_OUTACT_OPEN_SUBTITLES: + temp_reg |= SDO_CGMS625_OUTACT_OPEN_SUBTITLES; + break; + + default: + SDPRINTK("invalid open_subtitles parameter(%d)\n\r", + open_subtitles); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (camera_film) { + + case SDO_625_CAMERA: + temp_reg |= SDO_CGMS625_CAMERA; + break; + + case SDO_625_FILM: + temp_reg |= SDO_CGMS625_FILM; + break; + + default: + SDPRINTK(" invalid camera_film parameter(%d)\n\r", + camera_film); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (color_encoding) { + + case SDO_625_NORMAL_PAL: + temp_reg |= SDO_CGMS625_NORMAL_PAL; + break; + + case SDO_625_MOTION_ADAPTIVE_COLORPLUS: + temp_reg |= SDO_CGMS625_MOTION_ADAPTIVE_COLORPLUS; + break; + + default: + SDPRINTK(" invalid color_encoding parameter(%d)\n\r", + color_encoding); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + if (helper_signal) + temp_reg |= SDO_CGMS625_HELPER_SIG; + else + temp_reg |= SDO_CGMS625_HELPER_NO_SIG; + + + switch (display_ratio) { + + case SDO_625_4_3_FULL_576: + temp_reg |= SDO_CGMS625_4_3_FULL_576; + break; + + case SDO_625_14_9_LETTERBOX_CENTER_504: + temp_reg |= SDO_CGMS625_14_9_LETTERBOX_CENTER_504; + break; + + case SDO_625_14_9_LETTERBOX_TOP_504: + temp_reg |= SDO_CGMS625_14_9_LETTERBOX_TOP_504; + break; + + case SDO_625_16_9_LETTERBOX_CENTER_430: + temp_reg |= SDO_CGMS625_16_9_LETTERBOX_CENTER_430; + break; + + case SDO_625_16_9_LETTERBOX_TOP_430: + temp_reg |= SDO_CGMS625_16_9_LETTERBOX_TOP_430; + break; + + case SDO_625_16_9_LETTERBOX_CENTER: + temp_reg |= SDO_CGMS625_16_9_LETTERBOX_CENTER; + break; + + case SDO_625_14_9_FULL_CENTER_576: + temp_reg |= SDO_CGMS625_14_9_FULL_CENTER_576; + break; + + case SDO_625_16_9_ANAMORPIC_576: + temp_reg |= SDO_CGMS625_16_9_ANAMORPIC_576; + break; + + default: + SDPRINTK("invalid display_ratio parameter(%d)\n\r", + display_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, sdout_base + S5P_SDO_CGMS625); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_CGMS625)); + + return SDOUT_NO_ERROR; +} + + +static enum s5p_tv_sd_err __s5p_sdout_init_antialias_filter_coeff_default( + enum s5p_sd_level composite_level, + enum s5p_sd_vsync_ratio composite_ratio, + enum s5p_tv_o_mode out_mode) +{ + SDPRINTK("%d, %d, %d\n\r", composite_level, composite_ratio, out_mode); + + switch (composite_level) { + + case S5P_TV_SD_LEVEL_0IRE: + + switch (composite_ratio) { + + case SDOUT_VTOS_RATIO_10_4: + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + writel(0x00000000 , sdout_base + S5P_SDO_Y3); + writel(0x00000000 , sdout_base + S5P_SDO_Y4); + writel(0x00000000 , sdout_base + S5P_SDO_Y5); + writel(0x00000000 , sdout_base + S5P_SDO_Y6); + writel(0x00000000 , sdout_base + S5P_SDO_Y7); + writel(0x00000000 , sdout_base + S5P_SDO_Y8); + writel(0x00000000 , sdout_base + S5P_SDO_Y9); + writel(0x00000000 , sdout_base + S5P_SDO_Y10); + writel(0x0000029a , sdout_base + S5P_SDO_Y11); + writel(0x00000000 , sdout_base + S5P_SDO_CB0); + writel(0x00000000 , sdout_base + S5P_SDO_CB1); + writel(0x00000000 , sdout_base + S5P_SDO_CB2); + writel(0x00000000 , sdout_base + S5P_SDO_CB3); + writel(0x00000000 , sdout_base + S5P_SDO_CB4); + writel(0x00000001 , sdout_base + S5P_SDO_CB5); + writel(0x00000007 , sdout_base + S5P_SDO_CB6); + writel(0x00000015 , sdout_base + S5P_SDO_CB7); + writel(0x0000002b , sdout_base + S5P_SDO_CB8); + writel(0x00000045 , sdout_base + S5P_SDO_CB9); + writel(0x00000059 , sdout_base + S5P_SDO_CB10); + writel(0x00000061 , sdout_base + S5P_SDO_CB11); + writel(0x00000000 , sdout_base + S5P_SDO_CR1); + writel(0x00000000 , sdout_base + S5P_SDO_CR2); + writel(0x00000000 , sdout_base + S5P_SDO_CR3); + writel(0x00000000 , sdout_base + S5P_SDO_CR4); + writel(0x00000002 , sdout_base + S5P_SDO_CR5); + writel(0x0000000a , sdout_base + S5P_SDO_CR6); + writel(0x0000001e , sdout_base + S5P_SDO_CR7); + writel(0x0000003d , sdout_base + S5P_SDO_CR8); + writel(0x00000061 , sdout_base + S5P_SDO_CR9); + writel(0x0000007a , sdout_base + S5P_SDO_CR10); + writel(0x0000008f , sdout_base + S5P_SDO_CR11); + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x0000029a, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000007, sdout_base + S5P_SDO_CB6); + writel(0x00000015, sdout_base + S5P_SDO_CB7); + writel(0x0000002b, sdout_base + S5P_SDO_CB8); + writel(0x00000045, sdout_base + S5P_SDO_CB9); + writel(0x00000059, sdout_base + S5P_SDO_CB10); + writel(0x00000061, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000002, sdout_base + S5P_SDO_CR5); + writel(0x0000000a, sdout_base + S5P_SDO_CR6); + writel(0x0000001e, sdout_base + S5P_SDO_CR7); + writel(0x0000003d, sdout_base + S5P_SDO_CR8); + writel(0x00000061, sdout_base + S5P_SDO_CR9); + writel(0x0000007a, sdout_base + S5P_SDO_CR10); + writel(0x0000008f, sdout_base + S5P_SDO_CR11); + break; + + default: + SDPRINTK("invalid out_mode parameter(%d)\n\r", + out_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case SDOUT_VTOS_RATIO_7_3: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x00000281, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000007, sdout_base + S5P_SDO_CB6); + writel(0x00000015, sdout_base + S5P_SDO_CB7); + writel(0x0000002a, sdout_base + S5P_SDO_CB8); + writel(0x00000044, sdout_base + S5P_SDO_CB9); + writel(0x00000057, sdout_base + S5P_SDO_CB10); + writel(0x0000005f, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000002, sdout_base + S5P_SDO_CR5); + writel(0x0000000a, sdout_base + S5P_SDO_CR6); + writel(0x0000001d, sdout_base + S5P_SDO_CR7); + writel(0x0000003c, sdout_base + S5P_SDO_CR8); + writel(0x0000005f, sdout_base + S5P_SDO_CR9); + writel(0x0000007b, sdout_base + S5P_SDO_CR10); + writel(0x00000086, sdout_base + S5P_SDO_CR11); + break; + + default: + SDPRINTK("invalid composite_ratio parameter(%d)\n\r", + composite_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case S5P_TV_SD_LEVEL_75IRE: + + switch (composite_ratio) { + + case SDOUT_VTOS_RATIO_10_4: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x0000025d, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000007, sdout_base + S5P_SDO_CB6); + writel(0x00000014, sdout_base + S5P_SDO_CB7); + writel(0x00000028, sdout_base + S5P_SDO_CB8); + writel(0x0000003f, sdout_base + S5P_SDO_CB9); + writel(0x00000052, sdout_base + S5P_SDO_CB10); + writel(0x0000005a, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000001, sdout_base + S5P_SDO_CR5); + writel(0x00000009, sdout_base + S5P_SDO_CR6); + writel(0x0000001c, sdout_base + S5P_SDO_CR7); + writel(0x00000039, sdout_base + S5P_SDO_CR8); + writel(0x0000005a, sdout_base + S5P_SDO_CR9); + writel(0x00000074, sdout_base + S5P_SDO_CR10); + writel(0x0000007e, sdout_base + S5P_SDO_CR11); + break; + + case SDOUT_VTOS_RATIO_7_3: + writel(0x00000000, sdout_base + S5P_SDO_Y0); + writel(0x00000000, sdout_base + S5P_SDO_Y1); + writel(0x00000000, sdout_base + S5P_SDO_Y2); + writel(0x00000000, sdout_base + S5P_SDO_Y3); + writel(0x00000000, sdout_base + S5P_SDO_Y4); + writel(0x00000000, sdout_base + S5P_SDO_Y5); + writel(0x00000000, sdout_base + S5P_SDO_Y6); + writel(0x00000000, sdout_base + S5P_SDO_Y7); + writel(0x00000000, sdout_base + S5P_SDO_Y8); + writel(0x00000000, sdout_base + S5P_SDO_Y9); + writel(0x00000000, sdout_base + S5P_SDO_Y10); + writel(0x00000251, sdout_base + S5P_SDO_Y11); + writel(0x00000000, sdout_base + S5P_SDO_CB0); + writel(0x00000000, sdout_base + S5P_SDO_CB1); + writel(0x00000000, sdout_base + S5P_SDO_CB2); + writel(0x00000000, sdout_base + S5P_SDO_CB3); + writel(0x00000000, sdout_base + S5P_SDO_CB4); + writel(0x00000001, sdout_base + S5P_SDO_CB5); + writel(0x00000006, sdout_base + S5P_SDO_CB6); + writel(0x00000013, sdout_base + S5P_SDO_CB7); + writel(0x00000028, sdout_base + S5P_SDO_CB8); + writel(0x0000003f, sdout_base + S5P_SDO_CB9); + writel(0x00000051, sdout_base + S5P_SDO_CB10); + writel(0x00000056, sdout_base + S5P_SDO_CB11); + writel(0x00000000, sdout_base + S5P_SDO_CR1); + writel(0x00000000, sdout_base + S5P_SDO_CR2); + writel(0x00000000, sdout_base + S5P_SDO_CR3); + writel(0x00000000, sdout_base + S5P_SDO_CR4); + writel(0x00000002, sdout_base + S5P_SDO_CR5); + writel(0x00000005, sdout_base + S5P_SDO_CR6); + writel(0x00000018, sdout_base + S5P_SDO_CR7); + writel(0x00000037, sdout_base + S5P_SDO_CR8); + writel(0x0000005A, sdout_base + S5P_SDO_CR9); + writel(0x00000076, sdout_base + S5P_SDO_CR10); + writel(0x0000007e, sdout_base + S5P_SDO_CR11); + break; + + default: + SDPRINTK(" invalid composite_ratio parameter(%d)\n\r", + composite_ratio); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + default: + SDPRINTK(" invalid composite_level parameter(%d)\n\r", + composite_level); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + SDPRINTK("()\n\r"); + + return SDOUT_NO_ERROR; + +} + + +static enum s5p_tv_sd_err __s5p_sdout_init_oversampling_filter_coeff_default( + enum s5p_tv_o_mode out_mode) +{ + + SDPRINTK("%d\n\r", out_mode); + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + /* + temp_reg = (u32)(sdout_base + S5P_SDO_OSFC00_0); + + for (i = 0; i < 3; i++) { + + temp_reg = (u32)((i == 0) ? + sdout_base + S5P_SDO_OSFC00_0 : + (i == 1) ? sdout_base + S5P_SDO_OSFC00_1 : + sdout_base + S5P_SDO_OSFC00_2); + + writel(((-2&0xfff) << 0) | ((-3&0xfff) << 0), + temp_reg + 0); + writel(0, + temp_reg + 1); + writel((4 << 0) | (5 << 16), + temp_reg + 2); + writel(((-1&0xfff) << 0) | (0 << 16), + temp_reg + 3); + writel(((-6&0xfff) << 0) | ((-9&0xfff) << 16), + temp_reg + 4); + writel((1 << 0) | (0 << 16), + temp_reg + 5); + writel((10 << 0) | (14 << 16), + temp_reg + 6); + writel(((-1&0xfff) << 0) | (0 << 16), + temp_reg + 7); + writel(((-14&0xfff) << 0) | ((-20&0xfff) << 16), + temp_reg + 8); + writel((1 << 0) | (0 << 16), + temp_reg + 9); + writel((20 << 0) | (29 << 16), + temp_reg + 10); + writel(((-2&0xfff) << 0) | (0 << 16), + temp_reg + 11); + writel(((-28&0xfff) << 0) | ((-40&0xfff) << 16), + temp_reg + 12); + writel((2 << 0) | (0 << 16), + temp_reg + 13); + writel((40 << 0) | (56 << 16), + temp_reg + 14); + writel(((-3&0xfff) << 0) | (0 << 16), + temp_reg + 15); + writel(((-57&0xfff) << 0) | ((-80&0xfff) << 16), + temp_reg + 16); + writel((5 << 0) | (0 << 16), + temp_reg + 17); + writel((86 << 0) | (121 << 16), + temp_reg + 18); + writel(((-10&0xfff) << 0) | (0 << 16), + temp_reg + 19); + writel(((-154&0xfff) << 0) | ((-212&0xfff) << 16), + temp_reg + 20); + writel((27 << 0) | (0 << 16), + temp_reg + 21); + writel((613 << 0) | (651 << 16), + temp_reg + 22); + writel(((-308&0xfff) << 0) | (1024 << 16), + temp_reg + 23); + } +*/ + break; + + default: + SDPRINTK("invalid out_mode parameter(%d)\n\r", out_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + return SDOUT_NO_ERROR; +} + +/* +* initialization +* - iniization functions are only called under stopping sdout +*/ +enum s5p_tv_sd_err __s5p_sdout_init_display_mode( + enum s5p_tv_disp_mode disp_mode, + enum s5p_tv_o_mode out_mode, + enum s5p_sd_order order) +{ + u32 temp_reg = 0; + + SDPRINTK(" %d, %d, %d\n\r", disp_mode, out_mode, order); + + switch (disp_mode) { + + case TVOUT_NTSC_M: + temp_reg |= SDO_NTSC_M; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4, + out_mode); + break; + + case TVOUT_PAL_BDGHI: + temp_reg |= SDO_PAL_BGHID; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, out_mode); + break; + + case TVOUT_PAL_M: + temp_reg |= SDO_PAL_M; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, + out_mode); + break; + + case TVOUT_PAL_N: + temp_reg |= SDO_PAL_N; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4, + out_mode); + break; + + case TVOUT_PAL_NC: + temp_reg |= SDO_PAL_NC; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, + out_mode); + break; + + case TVOUT_PAL_60: + temp_reg |= SDO_PAL_60; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3); + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, + out_mode); + break; + + case TVOUT_NTSC_443: + temp_reg |= SDO_NTSC_443; + __s5p_sdout_init_video_scale_cfg(S5P_TV_SD_LEVEL_0IRE, + SDOUT_VTOS_RATIO_7_3, S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4); + __s5p_sdout_init_antialias_filter_coeff_default( + S5P_TV_SD_LEVEL_75IRE, + SDOUT_VTOS_RATIO_10_4, + out_mode); + break; + + default: + SDPRINTK("invalid disp_mode parameter(%d)\n\r", disp_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + switch (out_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + + case TVOUT_OUTPUT_SVIDEO: + temp_reg |= SDO_COMPOSITE | SDO_INTERLACED; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_Y_C: + temp_reg |= SDO_DAC2_CVBS | SDO_DAC1_Y | SDO_DAC0_C; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_C_Y: + temp_reg |= SDO_DAC2_CVBS | SDO_DAC1_C | SDO_DAC0_Y; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_Y_C_CVBS: + temp_reg |= SDO_DAC2_Y | SDO_DAC1_C | SDO_DAC0_CVBS; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_Y_CVBS_C: + temp_reg |= SDO_DAC2_Y | SDO_DAC1_CVBS | SDO_DAC0_C; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_C_CVBS_Y: + temp_reg |= SDO_DAC2_C | SDO_DAC1_CVBS | SDO_DAC0_Y; + break; + + case S5P_TV_SD_O_ORDER_COMPOSITE_C_Y_CVBS: + temp_reg |= SDO_DAC2_C | SDO_DAC1_Y | SDO_DAC0_CVBS; + break; + + default: + SDPRINTK(" invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + temp_reg |= SDO_COMPONENT | SDO_YPBPR | SDO_INTERLACED; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_Y_G | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_PB_B | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_Y_G | + SDO_DAC0_PR_R; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_PR_R | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PR_R | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PB_B | + SDO_DAC0_PR_R; + break; + + default: + SDPRINTK(" invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + temp_reg |= SDO_COMPONENT | SDO_YPBPR | SDO_PROGRESSIVE; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_Y_G | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_PB_B | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_Y_G | + SDO_DAC0_PR_R; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_PR_R | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PR_R | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PB_B | + SDO_DAC0_PR_R; + break; + + default: + SDPRINTK(" invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + temp_reg |= SDO_COMPONENT | SDO_RGB | SDO_PROGRESSIVE; + + switch (order) { + + case S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_Y_G | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY: + temp_reg |= SDO_DAC2_PR_R | SDO_DAC1_PB_B | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_Y_G | + SDO_DAC0_PR_R; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY: + temp_reg |= SDO_DAC2_PB_B | SDO_DAC1_PR_R | + SDO_DAC0_Y_G; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PR_R | + SDO_DAC0_PB_B; + break; + + case S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR: + temp_reg |= SDO_DAC2_Y_G | SDO_DAC1_PB_B | + SDO_DAC0_PR_R; + break; + + default: + SDPRINTK("invalid order parameter(%d)\n\r", order); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + break; + + default: + SDPRINTK(" invalid out_mode parameter(%d)\n\r", out_mode); + return S5P_TV_SD_ERR_INVALID_PARAM; + break; + } + + __s5p_sdout_init_oversampling_filter_coeff_default(out_mode); + + writel(temp_reg, sdout_base + S5P_SDO_CONFIG); + + SDPRINTK("0x%08x\n\r", readl(sdout_base + S5P_SDO_CONFIG)); + + return SDOUT_NO_ERROR; +} + +/* +* start - start functions are only called under stopping SDOUT +*/ +void __s5p_sdout_start(void) +{ + SDPRINTK("()\n\r"); + + writel(SDO_TVOUT_CLOCK_ON, sdout_base + S5P_SDO_CLKCON); + + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_CLKCON)); +} + +/* +/ stop - stop functions are only called under running SDOUT +*/ +void __s5p_sdout_stop(void) +{ + SDPRINTK("()\n\r"); + + mdelay(100); + + writel(SDO_TVOUT_CLOCK_OFF, sdout_base + S5P_SDO_CLKCON); + + SDPRINTK(" 0x%x)\n\r", readl(sdout_base + S5P_SDO_CLKCON)); +} + +/* +* reset +* - reset function +*/ +void __s5p_sdout_sw_reset(bool active) +{ + SDPRINTK("%d\n\r", active); + + if (active) + writel(readl(sdout_base + S5P_SDO_CLKCON) | SDO_TVOUT_SW_RESET, + sdout_base + S5P_SDO_CLKCON); + else + writel(readl(sdout_base + S5P_SDO_CLKCON) & + ~SDO_TVOUT_SW_RESET, + sdout_base + S5P_SDO_CLKCON); + + SDPRINTK(" 0x%x\n\r", readl(sdout_base + S5P_SDO_CLKCON)); +} + + +void __s5p_sdout_set_interrupt_enable(bool vsync_intr_en) +{ + SDPRINTK("%d)\n\r", vsync_intr_en); + + if (vsync_intr_en) + writel(readl(sdout_base + S5P_SDO_IRQMASK) & + ~SDO_VSYNC_IRQ_DISABLE, + sdout_base + S5P_SDO_IRQMASK); + else + writel(readl(sdout_base + S5P_SDO_IRQMASK) | + SDO_VSYNC_IRQ_DISABLE, + sdout_base + S5P_SDO_IRQMASK); + + SDPRINTK("0x%x)\n\r", readl(sdout_base + S5P_SDO_IRQMASK)); +} + +void __s5p_sdout_clear_interrupt_pending(void) +{ + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_IRQ)); + + writel(readl(sdout_base + S5P_SDO_IRQ) | SDO_VSYNC_IRQ_PEND, + sdout_base + S5P_SDO_IRQ); + + SDPRINTK("0x%x\n\r", readl(sdout_base + S5P_SDO_IRQ)); +} + +bool __s5p_sdout_get_interrupt_pending(void) +{ + SDPRINTK(" 0x%x\n\r", readl(sdout_base + S5P_SDO_IRQ)); + + return (readl(sdout_base + S5P_SDO_IRQ) | SDO_VSYNC_IRQ_PEND) ? 1 : 0; +} + +int __init __s5p_sdout_probe(struct platform_device *pdev, u32 res_num) +{ + struct resource *res; + size_t size; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + goto error; + } + + size = (res->end - res->start) + 1; + + sdout_mem = request_mem_region(res->start, size, pdev->name); + + if (sdout_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + goto error; + } + + sdout_base = ioremap(res->start, size); + + if (sdout_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + goto error; + + } + + return 0; +error: + return -ENOENT; + +} + +int __init __s5p_sdout_release(struct platform_device *pdev) +{ + iounmap(sdout_base); + + /* remove memory region */ + if (sdout_mem != NULL) { + if (release_resource(sdout_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(sdout_mem); + + sdout_mem = NULL; + } + + return 0; +} diff --git a/drivers/media/video/samsung/tv20/s5pv210/tv_clock_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/tv_clock_s5pv210.c new file mode 100644 index 0000000..c0de6b3 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/tv_clock_s5pv210.c @@ -0,0 +1,286 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/tv_clock_s5pc110.c + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ + * + * clock raw ftn file for Samsung TVOut driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/uaccess.h> +#include <linux/io.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> + +#include "tv_out_s5pv210.h" +#include "regs/regs-clock_extra.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_TVOUT_CLK_DEBUG 1 +#endif + +#ifdef S5P_TVOUT_CLK_DEBUG +#define TVCLKPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[TVCLK] %s: " fmt, __func__ , ## args) +#else +#define TVCLKPRINTK(fmt, args...) +#endif + +void __s5p_tv_clk_init_hpll(unsigned int lock_time, + bool vsel, + unsigned int mdiv, + unsigned int pdiv, + unsigned int sdiv) +{ + u32 temp; + + TVCLKPRINTK("%d,%d,%d,%d\n\r", lock_time, mdiv, pdiv, sdiv); + + temp = readl(S5P_VPLL_CON); + + temp &= ~VPLL_ENABLE; + + writel(temp, S5P_VPLL_CON); + + temp = 0; + + if (vsel) + temp |= VCO_FREQ_SEL; + + temp |= VPLL_ENABLE; + temp |= MDIV(mdiv) | PDIV(pdiv) | SDIV(sdiv); + + writel(VPLL_LOCKTIME(lock_time), S5P_VPLL_LOCK); + writel(temp, S5P_VPLL_CON); + + while (!VPLL_LOCKED(readl(S5P_VPLL_CON))); + + TVCLKPRINTK("0x%08x,0x%08x\n\r", readl(S5P_VPLL_LOCK), \ + readl(S5P_VPLL_CON)); +} + +void __s5p_tv_clk_hpll_onoff(bool en) +{ +} + +s5p_tv_clk_err __s5p_tv_clk_init_href(s5p_tv_clk_hpll_ref hpll_ref) +{ + return S5P_TV_CLK_ERR_NO_ERROR; +} + +/* prevent hdmi hang-up when reboot */ +int __s5p_tv_clk_change_internal(void) +{ + u32 reg = readl(S5P_CLK_SRC1); + /* set to SCLK_DAC */ + reg &= HDMI_SEL_MASK; + /* set to SCLK_PIXEL */ + reg &= VMIXER_SEL_MASK; + + writel(reg, S5P_CLK_SRC1); + + return 0; +} + +s5p_tv_clk_err __s5p_tv_clk_init_mout_hpll(s5p_tv_clk_mout_hpll mout_hpll) +{ + TVCLKPRINTK("(%d)\n\r", mout_hpll); + + writel(readl(S5P_CLK_SRC1) | HDMI_SEL_HDMIPHY, S5P_CLK_SRC1); + + TVCLKPRINTK("S5P_CLK_SRC1 :0x%08x\n", readl(S5P_CLK_SRC1)); + return S5P_TV_CLK_ERR_NO_ERROR; +} + +s5p_tv_clk_err __s5p_tv_clk_init_video_mixer(s5p_tv_clk_vmiexr_srcclk src_clk) +{ + switch (src_clk) { + + /* for analog tv out 0:SCLK_DAC */ + case TVOUT_CLK_VMIXER_SRCCLK_VCLK_54: + writel(readl(S5P_CLK_SRC1) & VMIXER_SEL_MASK, S5P_CLK_SRC1); + break; + + /* for digital hdmi_phy 1: SCLK_HDMI */ + case TVOUT_CLK_VMIXER_SRCCLK_MOUT_HPLL: + writel(readl(S5P_CLK_SRC1) | VMIXER_SEL_MOUT_VPLL, \ + S5P_CLK_SRC1); + break; + + default: + TVCLKPRINTK("[ERR] invalid src_clk parameter = %d\n", src_clk); + return S5P_TV_CLK_ERR_INVALID_PARAM; + break; + } + + TVCLKPRINTK("S5P_CLK_SRC1 :0x%08x\n", readl(S5P_CLK_SRC1)); + + return S5P_TV_CLK_ERR_NO_ERROR; +} + +void __s5p_tv_clk_init_hdmi_ratio(unsigned int clk_div) +{ + TVCLKPRINTK("(%d)\n\r", clk_div); + + writel((readl(S5P_CLK_DIV1) & HDMI_DIV_RATIO_MASK) | \ + HDMI_DIV_RATIO(clk_div), S5P_CLK_DIV1); + + TVCLKPRINTK("(0x%08x)\n\r", readl(S5P_CLK_DIV3)); +} + +/* + * hclk gating + */ + +/* VP */ +void __s5p_tv_clk_set_vp_clk_onoff(bool clk_on) +{ + /* + TVCLKPRINTK("VP hclk : %s\n\r", clk_on ? "on":"off"); + + if (clk_on) + bit_add_l(S5P_CLKGATE_IP1_VP, S5P_CLKGATE_IP1); + else + bit_del_l(S5P_CLKGATE_IP1_VP, S5P_CLKGATE_IP1); + + TVCLKPRINTK("S5P_CLKGATE_MAIN1 :0x%08x\n\r", readl(S5P_CLKGATE_MAIN1)); + */ +} + +/* MIXER */ +void __s5p_tv_clk_set_vmixer_hclk_onoff(bool clk_on) +{ + /* + TVCLKPRINTK("MIXER hclk : %s\n\r", clk_on ? "on":"off"); + + if (clk_on) + bit_add_l(S5P_CLKGATE_IP1_MIXER, S5P_CLKGATE_IP1); + else + bit_del_l(S5P_CLKGATE_IP1_MIXER, S5P_CLKGATE_IP1); + + TVCLKPRINTK("S5P_CLKGATE_MAIN1 :0x%08x\n\r", readl(S5P_CLKGATE_MAIN1)); + */ +} + +/* TVENC */ +void __s5p_tv_clk_set_sdout_hclk_onoff(bool clk_on) +{ + /* + TVCLKPRINTK("TVENC hclk : %s\n\r", clk_on ? "on":"off"); + + if (clk_on) + bit_add_l(S5P_CLKGATE_IP1_TVENC, S5P_CLKGATE_IP1); + else + bit_del_l(S5P_CLKGATE_IP1_TVENC, S5P_CLKGATE_IP1); + */ +} + +/* HDMI */ +void __s5p_tv_clk_set_hdmi_hclk_onoff(bool clk_on) +{ + /* + TVCLKPRINTK("HDMI hclk : %s\n\r", clk_on ? "on":"off"); + + if (clk_on) { + bit_add_l(S5P_CLKGATE_IP1_HDMI, S5P_CLKGATE_IP1); + bit_add_l(VMIXER_OUT_SEL_HDMI, S5P_MIXER_OUT_SEL); + } else + bit_del_l(S5P_CLKGATE_IP1_HDMI, S5P_CLKGATE_IP1); + + TVCLKPRINTK("S5P_CLKGATE_PERI1 :0x%08x\n\r", readl(S5P_CLKGATE_PERI1)); + TVCLKPRINTK("clk output is %s\n\r", readl(S5P_MIXER_OUT_SEL) ? "HDMI":"SDOUT"); + */ +} + +/* + * sclk gating + */ + +/* MIXER */ +void __s5p_tv_clk_set_vmixer_sclk_onoff(bool clk_on) +{ +#if 0 + TVCLKPRINTK("MIXER sclk : %s\n\r", clk_on ? "on":"off"); + + if (clk_on) + bit_add_l(CLK_SCLK_VMIXER_PASS, S5P_SCLKGATE0); + else + bit_del_l(CLK_SCLK_VMIXER_PASS, S5P_SCLKGATE0); + + TVCLKPRINTK("S5P_SCLKGATE0 :0x%08x\n\r", readl(S5P_SCLKGATE0)); +#endif +} + +/* TVENC */ +void __s5p_tv_clk_set_sdout_sclk_onoff(bool clk_on) +{ +#if 0 + TVCLKPRINTK("TVENC sclk : %s\n\r", clk_on ? "on":"off"); + + if (clk_on) + bit_add_l(CLK_SCLK_TV54_PASS | CLK_SCLK_VDAC54_PASS, S5P_SCLKGATE0); + else + bit_del_l(CLK_SCLK_TV54_PASS | CLK_SCLK_VDAC54_PASS, S5P_SCLKGATE0); + + TVCLKPRINTK("S5P_SCLKGATE0 :0x%08x\n\r", readl(S5P_SCLKGATE0)); +#endif +} + +/* HDMI */ +void __s5p_tv_clk_set_hdmi_sclk_onoff(bool clk_on) +{ +#if 0 + TVCLKPRINTK("HDMI sclk : %s\n\r", clk_on ? "on":"off"); + + if (clk_on) + bit_add_l(CLK_SCLK_HDMI_PASS, S5P_SCLKGATE0); + else + bit_del_l(CLK_SCLK_HDMI_PASS, S5P_SCLKGATE0); + + TVCLKPRINTK("S5P_SCLKGATE0 :0x%08x\n\r", readl(S5P_SCLKGATE0)); +#endif +} + +void __s5p_tv_clk_start(bool vp, bool sdout, bool hdmi) +{ + __s5p_tv_clk_set_vp_clk_onoff(vp); + __s5p_tv_clk_set_sdout_hclk_onoff(sdout); + __s5p_tv_clk_set_sdout_sclk_onoff(sdout); + __s5p_tv_clk_set_hdmi_hclk_onoff(hdmi); + __s5p_tv_clk_set_vmixer_hclk_onoff(true); + __s5p_tv_clk_set_vmixer_sclk_onoff(true); + + if (hdmi) + __s5p_tv_clk_hpll_onoff(true); +} + +void __s5p_tv_clk_stop(void) +{ + __s5p_tv_clk_set_sdout_sclk_onoff(false); + __s5p_tv_clk_set_sdout_hclk_onoff(false); + __s5p_tv_clk_set_hdmi_sclk_onoff(false); + __s5p_tv_clk_set_hdmi_hclk_onoff(false); + __s5p_tv_clk_set_vp_clk_onoff(false); + __s5p_tv_clk_set_vmixer_sclk_onoff(false); + __s5p_tv_clk_set_vmixer_hclk_onoff(false); + __s5p_tv_clk_hpll_onoff(false); +} + +int __init __s5p_tvclk_probe(struct platform_device *pdev, u32 res_num) +{ + return 0; +} + +int __init __s5p_tvclk_release(struct platform_device *pdev) +{ + return 0; +} diff --git a/drivers/media/video/samsung/tv20/s5pv210/tv_out_s5pv210.h b/drivers/media/video/samsung/tv20/s5pv210/tv_out_s5pv210.h new file mode 100644 index 0000000..fd326dd --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/tv_out_s5pv210.h @@ -0,0 +1,597 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/tv_out_s5pv210.h + * + * tv out header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/mm.h> +/* #define COFIG_TVOUT_RAW_DBG */ + + +#define HDMI_START_NUM 0x1000 + +#define bit_add_l(val, addr) writel(readl(addr) | val, addr) +#define bit_add_s(val, addr) writes(reads(addr) | val, addr) +#define bit_add_b(val, addr) writeb(readb(addr) | val, addr) +#define bit_del_l(val, addr) writel(readl(addr) & ~val, addr) +#define bit_del_s(val, addr) writes(reads(addr) & ~val, addr) +#define bit_del_b(val, addr) writeb(readb(addr) & ~val, addr) + + +enum s5p_tv_audio_codec_type { + PCM = 1, AC3, MP3, WMA +}; + +enum s5p_endian_type { + TVOUT_LITTLE_ENDIAN_MODE = 0, + TVOUT_BIG_ENDIAN_MODE = 1 +}; + +enum s5p_tv_disp_mode { + TVOUT_NTSC_M = 0, + TVOUT_PAL_BDGHI, + TVOUT_PAL_M, + TVOUT_PAL_N, + TVOUT_PAL_NC, + TVOUT_PAL_60, + TVOUT_NTSC_443, + + TVOUT_480P_60_16_9 = HDMI_START_NUM, + TVOUT_480P_60_4_3, + TVOUT_480P_59, + + TVOUT_576P_50_16_9, + TVOUT_576P_50_4_3, + + TVOUT_720P_60, + TVOUT_720P_50, + TVOUT_720P_59, + + TVOUT_1080P_60, + TVOUT_1080P_50, + TVOUT_1080P_59, + TVOUT_1080P_30, + + TVOUT_1080I_60, + TVOUT_1080I_50, + TVOUT_1080I_59, +}; + +enum s5p_tv_o_mode { + TVOUT_OUTPUT_COMPOSITE, + TVOUT_OUTPUT_SVIDEO, + TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED, + TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE, + TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE, + TVOUT_OUTPUT_HDMI, + TVOUT_OUTPUT_HDMI_RGB, + TVOUT_OUTPUT_DVI +}; + +enum s5p_tv_pwr_err { + S5P_TV_PWR_ERR_NO_ERROR = 0, + S5P_TV_PWR_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x5000, + S5P_TV_PWR_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_PWR_ERR_INVALID_PARAM +}; + +enum s5p_tv_clk_err { + S5P_TV_CLK_ERR_NO_ERROR = 0, + S5P_TV_CLK_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x4000, + S5P_TV_CLK_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_CLK_ERR_INVALID_PARAM +}; + +enum s5p_tv_vp_err { + VPROC_NO_ERROR = 0, + S5P_TV_VP_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x2000, + S5P_TV_VP_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN, + S5P_TV_VP_ERR_NOT_UPDATE_FOR_ANOTHER_UPDATE, + S5P_TV_VP_ERR_INVALID_PARAM +}; + +enum s5p_tv_vmx_err { + VMIXER_NO_ERROR = 0, + S5P_TV_VMX_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x1000, + S5P_TV_VMX_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_VMX_ERR_BASE_ADDRESS_MUST_WORD_ALIGN, + S5P_TV_VMX_ERR_INVALID_PARAM +}; + +enum s5p_tv_vmx_color_fmt { + VM_DIRECT_RGB565 = 4, + VM_DIRECT_RGB1555 = 5, + VM_DIRECT_RGB4444 = 6, + VM_DIRECT_RGB8888 = 7 +}; + +enum s5p_tv_sd_err { + SDOUT_NO_ERROR = 0, + S5P_TV_SD_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x3000, + S5P_TV_SD_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_SD_ERR_INVALID_PARAM +}; + +enum s5p_sd_order { + S5P_TV_SD_O_ORDER_COMPONENT_RGB_PRYPB, + S5P_TV_SD_O_ORDER_COMPONENT_RBG_PRPBY, + S5P_TV_SD_O_ORDER_COMPONENT_BGR_PBYPR, + S5P_TV_SD_O_ORDER_COMPONENT_BRG_PBPRY, + S5P_TV_SD_O_ORDER_COMPONENT_GRB_YPRPB, + S5P_TV_SD_O_ORDER_COMPONENT_GBR_YPBPR, + S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_Y_C, + S5P_TV_SD_O_ORDER_COMPOSITE_CVBS_C_Y, + S5P_TV_SD_O_ORDER_COMPOSITE_Y_C_CVBS, + S5P_TV_SD_O_ORDER_COMPOSITE_Y_CVBS_C, + S5P_TV_SD_O_ORDER_COMPOSITE_C_CVBS_Y, + S5P_TV_SD_O_ORDER_COMPOSITE_C_Y_CVBS +}; + +enum s5p_tv_hdmi_err { + HDMI_NO_ERROR = 0, + S5P_TV_HDMI_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x6000, + S5P_TV_HDMI_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_HDMI_ERR_INVALID_PARAM +}; + +enum s5p_hdmi_transmit { + HDMI_DO_NOT_TANS = 0, + HDMI_TRANS_ONCE, + HDMI_TRANS_EVERY_SYNC +}; + +enum s5p_hdmi_audio_type { + HDMI_AUDIO_NO, + HDMI_AUDIO_PCM +}; + + +enum s5p_tv_stda_err { + STDA_NO_ERROR = 0, + S5P_TV_STDA_ERR_NOT_INIT_PARAMETERS_UNDER_RUNNING = 0x7000, + S5P_TV_STDA_ERR_NOT_SET_PARAMETERS_UNDER_STOP, + S5P_TV_STDA_ERR_INVALID_PARAM +}; + + +/* +* enum +*/ + +enum s5p_tv_active_polarity { + TVOUT_POL_ACTIVE_LOW, + TVOUT_POL_ACTIVE_HIGH +}; + +enum s5p_yuv_fmt_component { + TVOUT_YUV_Y, + TVOUT_YUV_CB, + TVOUT_YUV_CR +}; + +enum s5p_tv_clk_hpll_ref { + S5P_TV_CLK_HPLL_REF_27M, + S5P_TV_CLK_HPLL_REF_SRCLK +}; + +enum s5p_tv_clk_mout_hpll { + S5P_TV_CLK_MOUT_HPLL_27M, + S5P_TV_CLK_MOUT_HPLL_FOUT_HPLL +}; + +enum s5p_tv_clk_vmiexr_srcclk { + TVOUT_CLK_VMIXER_SRCCLK_CLK27M, + TVOUT_CLK_VMIXER_SRCCLK_VCLK_54, + TVOUT_CLK_VMIXER_SRCCLK_MOUT_HPLL +}; + +enum s5p_vp_src_color { + VPROC_SRC_COLOR_NV12 = 0, + VPROC_SRC_COLOR_NV12IW = 1, + VPROC_SRC_COLOR_TILE_NV12 = 2, + VPROC_SRC_COLOR_TILE_NV12IW = 3 +}; + +enum s5p_vp_pxl_rate { + VPROC_PIXEL_PER_RATE_1_1 = 0, + VPROC_PIXEL_PER_RATE_1_2 = 1, + VPROC_PIXEL_PER_RATE_1_3 = 2, + VPROC_PIXEL_PER_RATE_1_4 = 3 +}; + +enum s5p_vp_sharpness_control { + VPROC_SHARPNESS_NO = 0, + VPROC_SHARPNESS_MIN = 1, + VPROC_SHARPNESS_MOD = 2, + VPROC_SHARPNESS_MAX = 3 +}; + +enum s5p_vp_line_eq { + VProc_LINE_EQ_0 = 0, + VProc_LINE_EQ_1 = 1, + VProc_LINE_EQ_2 = 2, + VProc_LINE_EQ_3 = 3, + VProc_LINE_EQ_4 = 4, + VProc_LINE_EQ_5 = 5, + VProc_LINE_EQ_6 = 6, + VProc_LINE_EQ_7 = 7 +}; + +enum s5p_vp_mem_mode { + VPROC_LINEAR_MODE, + VPROC_2D_TILE_MODE +}; + +enum s5p_vp_chroma_expansion { + VPROC_USING_C_TOP, + VPROC_USING_C_TOP_BOTTOM +}; + +enum s5p_vp_filed_id_toggle { + S5P_TV_VP_FILED_ID_TOGGLE_USER, + S5P_TV_VP_FILED_ID_TOGGLE_VSYNC +}; + +enum s5p_vp_field { + VPROC_TOP_FIELD, + VPROC_BOTTOM_FIELD +}; + +enum s5p_vp_poly_coeff { + VPROC_POLY8_Y0_LL = 0, + VPROC_POLY8_Y0_LH, + VPROC_POLY8_Y0_HL, + VPROC_POLY8_Y0_HH, + VPROC_POLY8_Y1_LL, + VPROC_POLY8_Y1_LH, + VPROC_POLY8_Y1_HL, + VPROC_POLY8_Y1_HH, + VPROC_POLY8_Y2_LL, + VPROC_POLY8_Y2_LH, + VPROC_POLY8_Y2_HL, + VPROC_POLY8_Y2_HH, + VPROC_POLY8_Y3_LL, + VPROC_POLY8_Y3_LH, + VPROC_POLY8_Y3_HL, + VPROC_POLY8_Y3_HH, + VPROC_POLY4_Y0_LL = 32, + VPROC_POLY4_Y0_LH, + VPROC_POLY4_Y0_HL, + VPROC_POLY4_Y0_HH, + VPROC_POLY4_Y1_LL, + VPROC_POLY4_Y1_LH, + VPROC_POLY4_Y1_HL, + VPROC_POLY4_Y1_HH, + VPROC_POLY4_Y2_LL, + VPROC_POLY4_Y2_LH, + VPROC_POLY4_Y2_HL, + VPROC_POLY4_Y2_HH, + VPROC_POLY4_Y3_LL, + VPROC_POLY4_Y3_LH, + VPROC_POLY4_Y3_HL, + VPROC_POLY4_Y3_HH, + VPROC_POLY4_C0_LL, + VPROC_POLY4_C0_LH, + VPROC_POLY4_C0_HL, + VPROC_POLY4_C0_HH, + VPROC_POLY4_C1_LL, + VPROC_POLY4_C1_LH, + VPROC_POLY4_C1_HL, + VPROC_POLY4_C1_HH +}; + +enum s5p_vp_csc_coeff { + VPROC_CSC_Y2Y_COEF = 0, + VPROC_CSC_CB2Y_COEF, + VPROC_CSC_CR2Y_COEF, + VPROC_CSC_Y2CB_COEF, + VPROC_CSC_CB2CB_COEF, + VPROC_CSC_CR2CB_COEF, + VPROC_CSC_Y2CR_COEF, + VPROC_CSC_CB2CR_COEF, + VPROC_CSC_CR2CR_COEF +}; + +enum s5p_vp_csc_type { + VPROC_CSC_SD_HD, + VPROC_CSC_HD_SD +}; + +enum s5p_tv_vp_filter_h_pp { + /* Don't change the order and the value */ + VPROC_PP_H_NORMAL = 0, + VPROC_PP_H_8_9, /* 720 to 640 */ + VPROC_PP_H_1_2, + VPROC_PP_H_1_3, + VPROC_PP_H_1_4 +}; + +enum s5p_tv_vp_filter_v_pp { + /* Don't change the order and the value */ + VPROC_PP_V_NORMAL = 0, + VPROC_PP_V_5_6, /* PAL to NTSC */ + VPROC_PP_V_3_4, + VPROC_PP_V_1_2, + VPROC_PP_V_1_3, + VPROC_PP_V_1_4 +}; + +enum s5p_vmx_burst_mode { + VM_BURST_8 = 0, + VM_BURST_16 = 1 +}; + +enum s5p_tv_vmx_scan_mode { + VMIXER_INTERLACED_MODE = 0, + VMIXER_PROGRESSIVE_MODE = 1 +}; + +enum s5p_tv_vmx_layer { + VM_VIDEO_LAYER = 2, + VM_GPR0_LAYER = 0, + VM_GPR1_LAYER = 1 +}; + +enum s5p_tv_vmx_bg_color_num { + VMIXER_BG_COLOR_0 = 0, + VMIXER_BG_COLOR_1 = 1, + VMIXER_BG_COLOR_2 = 2 +}; + +enum s5p_tv_coef_y_mode { + VMIXER_COEF_Y_NARROW = 0, + VMIXER_COEF_Y_WIDE = 1 +}; + +enum s5p_tv_vmx_csc_type { + VMIXER_CSC_RGB_TO_YUV601_LR, + VMIXER_CSC_RGB_TO_YUV601_FR, + VMIXER_CSC_RGB_TO_YUV709_LR, + VMIXER_CSC_RGB_TO_YUV709_FR +}; + +enum s5p_tv_vmx_rgb { + RGB601_0_255, + RGB601_16_235, + RGB709_0_255, + RGB709_16_235 +}; + +enum s5p_tv_vmx_out_type { + MX_YUV444, + MX_RGB888 +}; + +enum s5p_sd_level { + S5P_TV_SD_LEVEL_0IRE, + S5P_TV_SD_LEVEL_75IRE +}; + +enum s5p_sd_vsync_ratio { + SDOUT_VTOS_RATIO_10_4, + SDOUT_VTOS_RATIO_7_3 +}; + +enum s5p_sd_sync_sig_pin { + SDOUT_SYNC_SIG_NO, + SDOUT_SYNC_SIG_YG, + SDOUT_SYNC_SIG_ALL +}; + +enum s5p_sd_closed_caption_type { + SDOUT_NO_INS, + SDOUT_INS_1, + SDOUT_INS_2, + SDOUT_INS_OTHERS +}; + +enum s5p_sd_channel_sel { + SDOUT_CHANNEL_0 = 0, + SDOUT_CHANNEL_1 = 1, + SDOUT_CHANNEL_2 = 2 +}; + +enum s5p_sd_vesa_rgb_sync_type { + SDOUT_VESA_RGB_SYNC_COMPOSITE, + SDOUT_VESA_RGB_SYNC_SEPARATE +}; + +enum s5p_sd_525_copy_permit { + SDO_525_COPY_PERMIT, + SDO_525_ONECOPY_PERMIT, + SDO_525_NOCOPY_PERMIT +}; + +enum s5p_sd_525_mv_psp { + SDO_525_MV_PSP_OFF, + SDO_525_MV_PSP_ON_2LINE_BURST, + SDO_525_MV_PSP_ON_BURST_OFF, + SDO_525_MV_PSP_ON_4LINE_BURST, +}; + +enum s5p_sd_525_copy_info { + SDO_525_COPY_INFO, + SDO_525_DEFAULT, +}; + +enum s5p_sd_525_aspect_ratio { + SDO_525_4_3_NORMAL, + SDO_525_16_9_ANAMORPIC, + SDO_525_4_3_LETTERBOX +}; + +enum s5p_sd_625_subtitles { + SDO_625_NO_OPEN_SUBTITLES, + SDO_625_INACT_OPEN_SUBTITLES, + SDO_625_OUTACT_OPEN_SUBTITLES +}; + +enum s5p_sd_625_camera_film { + SDO_625_CAMERA, + SDO_625_FILM +}; + +enum s5p_sd_625_color_encoding { + SDO_625_NORMAL_PAL, + SDO_625_MOTION_ADAPTIVE_COLORPLUS +}; + +enum s5p_sd_625_aspect_ratio { + SDO_625_4_3_FULL_576, + SDO_625_14_9_LETTERBOX_CENTER_504, + SDO_625_14_9_LETTERBOX_TOP_504, + SDO_625_16_9_LETTERBOX_CENTER_430, + SDO_625_16_9_LETTERBOX_TOP_430, + SDO_625_16_9_LETTERBOX_CENTER, + SDO_625_14_9_FULL_CENTER_576, + SDO_625_16_9_ANAMORPIC_576 +}; + +enum s5p_tv_hdmi_csc_type { + HDMI_CSC_YUV601_TO_RGB_LR, + HDMI_CSC_YUV601_TO_RGB_FR, + HDMI_CSC_YUV709_TO_RGB_LR, + HDMI_CSC_YUV709_TO_RGB_FR, + HDMI_CSC_YUV601_TO_YUV709, + HDMI_CSC_RGB_FR_TO_RGB_LR, + HDMI_CSC_RGB_FR_TO_YUV601, + HDMI_CSC_RGB_FR_TO_YUV709, + HDMI_BYPASS +}; + +/* + * Color Depth for HDMI HW (settings and GCP packet), + * EDID and PHY HW + */ +enum s5p_hdmi_color_depth { + HDMI_CD_48, + HDMI_CD_36, + HDMI_CD_30, + HDMI_CD_24 +}; + +enum phy_freq { + ePHY_FREQ_25_200, + ePHY_FREQ_25_175, + ePHY_FREQ_27, + ePHY_FREQ_27_027, + ePHY_FREQ_54, + ePHY_FREQ_54_054, + ePHY_FREQ_74_250, + ePHY_FREQ_74_176, + ePHY_FREQ_148_500, + ePHY_FREQ_148_352, + ePHY_FREQ_108_108, + ePHY_FREQ_72, + ePHY_FREQ_25, + ePHY_FREQ_65, + ePHY_FREQ_108, + ePHY_FREQ_162 +}; + +/* video format for HDMI HW (timings and AVI) and EDID */ +enum s5p_hdmi_v_fmt { + v640x480p_60Hz = 0, + v720x480p_60Hz, + v1280x720p_60Hz, + v1920x1080i_60Hz, + v720x480i_60Hz, + v720x240p_60Hz, + v2880x480i_60Hz, + v2880x240p_60Hz, + v1440x480p_60Hz, + v1920x1080p_60Hz, + v720x576p_50Hz, + v1280x720p_50Hz, + v1920x1080i_50Hz, + v720x576i_50Hz, + v720x288p_50Hz, + v2880x576i_50Hz, + v2880x288p_50Hz, + v1440x576p_50Hz, + v1920x1080p_50Hz, + v1920x1080p_24Hz, + v1920x1080p_25Hz, + v1920x1080p_30Hz, + v2880x480p_60Hz, + v2880x576p_50Hz, + v1920x1080i_50Hz_1250, + v1920x1080i_100Hz, + v1280x720p_100Hz, + v720x576p_100Hz, + v720x576i_100Hz, + v1920x1080i_120Hz, + v1280x720p_120Hz, + v720x480p_120Hz, + v720x480i_120Hz, + v720x576p_200Hz, + v720x576i_200Hz, + v720x480p_240Hz, + v720x480i_240Hz, + v720x480p_59Hz, + v1280x720p_59Hz, + v1920x1080i_59Hz, + v1920x1080p_59Hz, + +}; + + +enum s5p_tv_hdmi_disp_mode { + S5P_TV_HDMI_DISP_MODE_480P_60 = 0, + S5P_TV_HDMI_DISP_MODE_576P_50 = 1, + S5P_TV_HDMI_DISP_MODE_720P_60 = 2, + S5P_TV_HDMI_DISP_MODE_720P_50 = 3, + S5P_TV_HDMI_DISP_MODE_1080I_60 = 4, + S5P_TV_HDMI_DISP_MODE_1080I_50 = 5, + S5P_TV_HDMI_DISP_MODE_VGA_60 = 6, + S5P_TV_HDMI_DISP_MODE_1080P_60 = 7, + S5P_TV_HDMI_DISP_MODE_1080P_50 = 8, + S5P_TV_HDMI_DISP_MODE_NUM = 9 +}; + +/* pixel aspect ratio for HDMI HW (AVI packet and EDID) */ +enum s5p_tv_hdmi_pxl_aspect { + HDMI_PIXEL_RATIO_4_3, + HDMI_PIXEL_RATIO_16_9 +}; + +enum s5p_tv_hdmi_interrrupt { + HDMI_IRQ_PIN_POLAR_CTL = 7, + HDMI_IRQ_GLOBAL = 6, + HDMI_IRQ_I2S = 5, + HDMI_IRQ_CEC = 4, + HDMI_IRQ_HPD_PLUG = 3, + HDMI_IRQ_HPD_UNPLUG = 2, + HDMI_IRQ_SPDIF = 1, + HDMI_IRQ_HDCP = 0 +}; + +typedef int (*hdmi_isr)(int irq); + + +extern int s5p_hdmi_register_isr(hdmi_isr isr, u8 irq_num); +extern void s5p_hdmi_enable_interrupts(enum s5p_tv_hdmi_interrrupt intr); +extern void s5p_hdmi_disable_interrupts(enum s5p_tv_hdmi_interrrupt intr); +extern void s5p_hdmi_hpd_gen(void); +extern u8 s5p_hdmi_get_interrupts(void); +extern u8 s5p_hdmi_get_enabled_interrupt(void); +extern int s5p_hdmi_set_dvi(bool en); +extern void s5p_hdmi_mute_en(bool en); + +extern void __iomem *hdmi_base; +extern bool __s5p_start_hdcp(void); +extern bool __s5p_stop_hdcp(void); +extern void __s5p_init_hdcp(bool hpd_status, struct i2c_client *ddc_port); + + /* 0 - hdcp stopped, 1 - hdcp started, 2 - hdcp reset */ +extern u8 hdcp_protocol_status; + +void __s5p_hdmi_video_set_bluescreen(bool en, u8 cb, u8 y_g, u8 cr_r); diff --git a/drivers/media/video/samsung/tv20/s5pv210/tv_power_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/tv_power_s5pv210.c new file mode 100644 index 0000000..4276df2 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/tv_power_s5pv210.c @@ -0,0 +1,133 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/tv_power_s5pv210.c + * + * power raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> + +#include "../s5p_tv.h" + + +#if defined USE_POWERCON_FUNCTION +#undef USE_POWERCON_FUNCTION +#endif + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_TVOUT_PM_DEBUG 1 +#endif + +#ifdef S5P_TVOUT_PM_DEBUG +#define TVPMPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[TVPM] %s: " fmt, __func__ , ## args) +#else +#define TVPMPRINTK(fmt, args...) +#endif + +/* NORMAL_CFG */ +#define TVPWR_SUBSYSTEM_ACTIVE (1<<4) +#define TVPWR_SUBSYSTEM_LP (0<<4) + +/* MTC_STABLE */ +#define TVPWR_MTC_COUNTER_CLEAR(a) (((~0xf)<<16)&a) +#define TVPWR_MTC_COUNTER_SET(a) ((0xf&a)<<16) + +/* BLK_PWR_STAT */ +#define TVPWR_TV_BLOCK_STATUS(a) ((0x1<<4)&a) + +static unsigned short g_dacPwrOn; +extern struct s5p_tv_status s5ptv_status; + +void __s5p_tv_power_init_mtc_stable_counter(unsigned int value) +{ + TVPMPRINTK("(%d)\n\r", value); + + writel(TVPWR_MTC_COUNTER_CLEAR((readl(S5P_MTC_STABLE) | + TVPWR_MTC_COUNTER_SET(value))), + S5P_MTC_STABLE); + + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_MTC_STABLE)); +} + +void __s5p_tv_powerinitialize_dac_onoff(bool on) +{ + TVPMPRINTK("(%d)\n\r", on); + + g_dacPwrOn = on; + + TVPMPRINTK("(0x%08x)\n\r", g_dacPwrOn); +} + +void __s5p_tv_powerset_dac_onoff(bool on) +{ + TVPMPRINTK("(%d)\n\r", on); + + if (on) { + regulator_enable(s5ptv_status.tv_tvout); + writel(S5P_DAC_ENABLE, S5P_DAC_CONTROL); + } else { + writel(S5P_DAC_DISABLE, S5P_DAC_CONTROL); + regulator_disable(s5ptv_status.tv_tvout); + } + + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_DAC_CONTROL)); +} + + +bool __s5p_tv_power_get_power_status(void) +{ + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_BLK_PWR_STAT)); + + + return TVPWR_TV_BLOCK_STATUS(readl(S5P_BLK_PWR_STAT)) ? 1 : 0; +} + +bool __s5p_tv_power_get_dac_power_status(void) +{ + TVPMPRINTK("()\n\r"); + + TVPMPRINTK("(0x%08x)\n\r", readl(S5P_DAC_CONTROL)); + + return (readl(S5P_DAC_CONTROL) & S5P_DAC_ENABLE) ? 1 : 0; +} + + +void __s5p_tv_poweron(void) +{ + TVPMPRINTK("0x%08x\n\r", readl(S3C_VA_SYS + 0xE804)); + + writel(readl(S3C_VA_SYS + 0xE804) | 0x1, S3C_VA_SYS + 0xE804); + + if (regulator_enable(s5ptv_status.tv_regulator)) + pr_err("%s : failed to turn tv-power-domain on\n", __func__); + + TVPMPRINTK("0x%08x, 0x%08x)\n\r", readl(S5P_NORMAL_CFG), + readl(S5P_BLK_PWR_STAT)); +} + + +void __s5p_tv_poweroff(void) +{ + TVPMPRINTK("()\n\r"); + + __s5p_tv_powerset_dac_onoff(0); + + if (regulator_disable(s5ptv_status.tv_regulator)) + pr_err("%s : failed to turn tv-power-domain off\n", __func__); + + TVPMPRINTK("0x%08x, 0x%08x)\n\r", readl(S5P_NORMAL_CFG), + readl(S5P_BLK_PWR_STAT)); +} diff --git a/drivers/media/video/samsung/tv20/s5pv210/vmixer_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/vmixer_s5pv210.c new file mode 100644 index 0000000..b38f57a --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/vmixer_s5pv210.c @@ -0,0 +1,1256 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/vmixer_s5pv210.c + * + * Mixer raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> + +/* #include <mach/regs-vmx.h> */ + +#include "tv_out_s5pv210.h" + +#include "regs/regs-vmx.h" +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_MXR_DEBUG 1 +#endif + +#ifdef S5P_MXR_DEBUG +#define VMPRINTK(fmt, args...) \ + printk(KERN_INFO "\t\t[VM] %s: " fmt, __func__ , ## args) +#else +#define VMPRINTK(fmt, args...) +#endif + +static struct resource *mixer_mem; +void __iomem *mixer_base; + +/* +*set - set functions are only called under running vmixer +*/ + +enum s5p_tv_vmx_err __s5p_vm_set_layer_show( + enum s5p_tv_vmx_layer layer, bool show) +{ + u32 mxr_config; + + VMPRINTK("%d, %d\n\r", layer, show); + + switch (layer) { + + case VM_VIDEO_LAYER: + mxr_config = (show) ? + (readl(mixer_base + S5P_MXR_CFG) | + S5P_MXR_VIDEO_LAYER_SHOW) : + (readl(mixer_base + S5P_MXR_CFG) & + ~S5P_MXR_VIDEO_LAYER_SHOW); + break; + + case VM_GPR0_LAYER: + mxr_config = (show) ? + (readl(mixer_base + S5P_MXR_CFG) | + S5P_MXR_GRAPHIC0_LAYER_SHOW) : + (readl(mixer_base + S5P_MXR_CFG) & + ~S5P_MXR_GRAPHIC0_LAYER_SHOW); + break; + + case VM_GPR1_LAYER: + mxr_config = (show) ? + (readl(mixer_base + S5P_MXR_CFG) | + S5P_MXR_GRAPHIC1_LAYER_SHOW) : + (readl(mixer_base + S5P_MXR_CFG) & + ~S5P_MXR_GRAPHIC1_LAYER_SHOW); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(mxr_config, mixer_base + S5P_MXR_CFG); + + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_CFG)); + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_layer_priority(enum s5p_tv_vmx_layer layer, + u32 priority) +{ + u32 layer_cfg; + + VMPRINTK("%d, %d\n\r", layer, priority); + + switch (layer) { + + case VM_VIDEO_LAYER: + layer_cfg = S5P_MXR_VP_LAYER_PRIORITY_CLEAR( + readl(mixer_base + S5P_MXR_LAYER_CFG)) | + S5P_MXR_VP_LAYER_PRIORITY(priority); + break; + + case VM_GPR0_LAYER: + layer_cfg = S5P_MXR_GRP0_LAYER_PRIORITY_CLEAR( + readl(mixer_base + S5P_MXR_LAYER_CFG)) | + S5P_MXR_GRP0_LAYER_PRIORITY(priority); + break; + + case VM_GPR1_LAYER: + layer_cfg = S5P_MXR_GRP1_LAYER_PRIORITY_CLEAR( + readl(mixer_base + S5P_MXR_LAYER_CFG)) | + S5P_MXR_GRP1_LAYER_PRIORITY(priority); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(layer_cfg, mixer_base + S5P_MXR_LAYER_CFG); + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_win_blend(enum s5p_tv_vmx_layer layer, + bool enable) +{ + u32 temp_reg; + VMPRINTK("%d, %d\n\r", layer, enable); + + switch (layer) { + + case VM_VIDEO_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_VIDEO_CFG) + & (~S5P_MXR_VP_BLEND_ENABLE) ; + + if (enable) + temp_reg |= S5P_MXR_VP_BLEND_ENABLE; + else + temp_reg |= S5P_MXR_VP_BLEND_DISABLE; + + writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG); + + break; + + case VM_GPR0_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG) + & (~S5P_MXR_WIN_BLEND_ENABLE) ; + + if (enable) + temp_reg |= S5P_MXR_WIN_BLEND_ENABLE; + else + temp_reg |= S5P_MXR_WIN_BLEND_DISABLE; + + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG); + + break; + + case VM_GPR1_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG) + & (~S5P_MXR_WIN_BLEND_ENABLE) ; + + if (enable) + temp_reg |= S5P_MXR_WIN_BLEND_ENABLE; + else + temp_reg |= S5P_MXR_WIN_BLEND_DISABLE; + + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG); + + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + + return S5P_TV_VMX_ERR_INVALID_PARAM; + + break; + } + + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_VIDEO_CFG)); + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)); + + return VMIXER_NO_ERROR; +} + + +enum s5p_tv_vmx_err __s5p_vm_set_layer_alpha(enum s5p_tv_vmx_layer layer, + u32 alpha) +{ + u32 temp_reg; + VMPRINTK("%d, %d\n\r", layer, alpha); + + switch (layer) { + + case VM_VIDEO_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_VIDEO_CFG) + & (~S5P_MXR_ALPHA) ; + temp_reg |= S5P_MXR_VP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG); + break; + + case VM_GPR0_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG) + & (~S5P_MXR_ALPHA) ; + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG); + break; + + case VM_GPR1_LAYER: + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_CFG) + & (~S5P_MXR_ALPHA) ; + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_VIDEO_CFG)); + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("0x08%x\n\r", readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)); + + return VMIXER_NO_ERROR; +} + + +enum s5p_tv_vmx_err __s5p_vm_set_grp_base_address(enum s5p_tv_vmx_layer layer, + u32 base_addr) +{ + VMPRINTK("%d, 0x%x\n\r", layer, base_addr); + + if (S5P_MXR_GRP_ADDR_ILLEGAL(base_addr)) { + VMPRINTK(" address is not word align = %d\n\r", base_addr); + return S5P_TV_VMX_ERR_BASE_ADDRESS_MUST_WORD_ALIGN; + } + + switch (layer) { + + case VM_GPR0_LAYER: + writel(S5P_MXR_GPR_BASE(base_addr), + mixer_base + S5P_MXR_GRAPHIC0_BASE); + VMPRINTK("0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_BASE)); + break; + + case VM_GPR1_LAYER: + writel(S5P_MXR_GPR_BASE(base_addr), + mixer_base + S5P_MXR_GRAPHIC1_BASE); + VMPRINTK("0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_BASE)); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_grp_layer_position(enum s5p_tv_vmx_layer layer, + u32 dst_offs_x, u32 dst_offs_y) +{ + VMPRINTK("%d, %d, %d)\n\r", layer, dst_offs_x, dst_offs_y); + + switch (layer) { + + case VM_GPR0_LAYER: + writel(S5P_MXR_GRP_DESTX(dst_offs_x) | + S5P_MXR_GRP_DESTY(dst_offs_y), + mixer_base + S5P_MXR_GRAPHIC0_DXY); + VMPRINTK("0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_DXY)); + break; + + case VM_GPR1_LAYER: + writel(S5P_MXR_GRP_DESTX(dst_offs_x) | + S5P_MXR_GRP_DESTY(dst_offs_y), + mixer_base + S5P_MXR_GRAPHIC1_DXY); + VMPRINTK("0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_DXY)); + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_grp_layer_size(enum s5p_tv_vmx_layer layer, + u32 span, + u32 width, + u32 height, + u32 src_offs_x, + u32 src_offs_y) +{ + VMPRINTK("%d, %d, %d, %d, %d, %d)\n\r", layer, span, width, height, + src_offs_x, src_offs_y); + + switch (layer) { + + case VM_GPR0_LAYER: + writel(S5P_MXR_GRP_SPAN(span), + mixer_base + S5P_MXR_GRAPHIC0_SPAN); + writel(S5P_MXR_GRP_WIDTH(width) | S5P_MXR_GRP_HEIGHT(height), + mixer_base + S5P_MXR_GRAPHIC0_WH); + writel(S5P_MXR_GRP_STARTX(src_offs_x) | + S5P_MXR_GRP_STARTY(src_offs_y), + mixer_base + S5P_MXR_GRAPHIC0_SXY); + VMPRINTK("0x%x, 0x%x, 0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_SPAN), + readl(mixer_base + S5P_MXR_GRAPHIC0_WH), + readl(mixer_base + S5P_MXR_GRAPHIC0_SXY)); + break; + + case VM_GPR1_LAYER: + writel(S5P_MXR_GRP_SPAN(span), + mixer_base + S5P_MXR_GRAPHIC1_SPAN); + writel(S5P_MXR_GRP_WIDTH(width) | S5P_MXR_GRP_HEIGHT(height), + mixer_base + S5P_MXR_GRAPHIC1_WH); + writel(S5P_MXR_GRP_STARTX(src_offs_x) | + S5P_MXR_GRP_STARTY(src_offs_y), + mixer_base + S5P_MXR_GRAPHIC1_SXY); + VMPRINTK("0x%x, 0x%x, 0x%x\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_SPAN), + readl(mixer_base + S5P_MXR_GRAPHIC1_WH), + readl(mixer_base + S5P_MXR_GRAPHIC1_SXY)); + break; + + default: + VMPRINTK(" invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_set_bg_color(enum s5p_tv_vmx_bg_color_num colornum, + u32 color_y, + u32 color_cb, + u32 color_cr) +{ + u32 reg_value; + VMPRINTK("%d, %d, %d, %d)\n\r", colornum, color_y, color_cb, color_cr); + + reg_value = S5P_MXR_BG_COLOR_Y(color_y) | + S5P_MXR_BG_COLOR_CB(color_cb) | + S5P_MXR_BG_COLOR_CR(color_cr); + + switch (colornum) { + + case VMIXER_BG_COLOR_0: + writel(reg_value, mixer_base + S5P_MXR_BG_COLOR0); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_BG_COLOR0)); + break; + + case VMIXER_BG_COLOR_1: + writel(reg_value, mixer_base + S5P_MXR_BG_COLOR1); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_BG_COLOR1)); + break; + + case VMIXER_BG_COLOR_2: + writel(reg_value, mixer_base + S5P_MXR_BG_COLOR2); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_BG_COLOR2)); + break; + + default: + VMPRINTK(" invalid uiColorNum parameter = %d\n\r", colornum); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + + + +/* +* initialization - iniization functions are only called under stopping vmixer +*/ +enum s5p_tv_vmx_err __s5p_vm_init_status_reg(enum s5p_vmx_burst_mode burst, + enum s5p_endian_type endian) +{ + u32 temp_reg = 0; + + VMPRINTK("++(%d, %d)\n\r", burst, endian); + + temp_reg = S5P_MXR_MIXER_RESERVED | S5P_MXR_CMU_CANNOT_STOP_CLOCK; + + switch (burst) { + + case VM_BURST_8: + temp_reg |= S5P_MXR_BURST8_MODE; + break; + + case VM_BURST_16: + temp_reg |= S5P_MXR_BURST16_MODE; + break; + + default: + VMPRINTK("[ERR] : invalid burst parameter = %d\n\r", burst); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + switch (endian) { + + case TVOUT_BIG_ENDIAN_MODE: + temp_reg |= S5P_MXR_BIG_ENDIAN_SOURCE_FORMAT; + break; + + case TVOUT_LITTLE_ENDIAN_MODE: + temp_reg |= S5P_MXR_LITTLE_ENDIAN_SOURCE_FORMAT; + break; + + default: + VMPRINTK("[ERR] : invalid endian parameter = %d\n\r", endian); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, mixer_base + S5P_MXR_STATUS); + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_STATUS)); + + return VMIXER_NO_ERROR; +} + +enum s5p_tv_vmx_err __s5p_vm_init_display_mode(enum s5p_tv_disp_mode mode, + enum s5p_tv_o_mode output_mode) +{ + u32 temp_reg = readl(mixer_base + S5P_MXR_CFG); + + VMPRINTK("%d, %d)\n\r", mode, output_mode); + + switch (mode) { + + case TVOUT_NTSC_M: + + case TVOUT_NTSC_443: + temp_reg &= ~S5P_MXR_HD; + temp_reg &= ~S5P_MXR_PAL; + temp_reg &= S5P_MXR_INTERLACE_MODE; + break; + + case TVOUT_PAL_BDGHI: + + case TVOUT_PAL_M: + + case TVOUT_PAL_N: + + case TVOUT_PAL_NC: + + case TVOUT_PAL_60: + temp_reg &= ~S5P_MXR_HD; + temp_reg |= S5P_MXR_PAL; + temp_reg &= S5P_MXR_INTERLACE_MODE; + break; + + case TVOUT_480P_60_16_9: + + case TVOUT_480P_60_4_3: + + case TVOUT_480P_59: + temp_reg &= ~S5P_MXR_HD; + temp_reg &= ~S5P_MXR_PAL; + temp_reg |= S5P_MXR_PROGRESSVE_MODE; + temp_reg |= RGB601_16_235<<9; + break; + + case TVOUT_576P_50_16_9: + + case TVOUT_576P_50_4_3: + temp_reg &= ~S5P_MXR_HD; + temp_reg |= S5P_MXR_PAL; + temp_reg |= S5P_MXR_PROGRESSVE_MODE; + temp_reg |= RGB601_16_235<<9; + break; + + case TVOUT_720P_50: + + case TVOUT_720P_59: + + case TVOUT_720P_60: + temp_reg |= S5P_MXR_HD; + temp_reg &= ~S5P_MXR_HD_1080I_MODE; + temp_reg |= S5P_MXR_PROGRESSVE_MODE; + temp_reg |= RGB709_16_235<<9; + break; + + case TVOUT_1080I_50: + + case TVOUT_1080I_59: + + case TVOUT_1080I_60: + temp_reg |= S5P_MXR_HD; + temp_reg |= S5P_MXR_HD_1080I_MODE; + temp_reg &= S5P_MXR_INTERLACE_MODE; + temp_reg |= RGB709_16_235<<9; + break; + + case TVOUT_1080P_50: + + case TVOUT_1080P_59: + + case TVOUT_1080P_60: + + case TVOUT_1080P_30: + temp_reg |= S5P_MXR_HD; + temp_reg |= S5P_MXR_HD_1080P_MODE; + temp_reg |= S5P_MXR_PROGRESSVE_MODE; + temp_reg |= RGB709_16_235<<9; + break; + + default: + VMPRINTK(" invalid mode parameter = %d\n\r", mode); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + switch (output_mode) { + + case TVOUT_OUTPUT_COMPOSITE: + case TVOUT_OUTPUT_SVIDEO: + case TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED: + case TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE: + case TVOUT_OUTPUT_COMPONENT_RGB_PROGRESSIVE: + temp_reg &= S5P_MXR_DST_SEL_ANALOG; + break; + + case TVOUT_OUTPUT_HDMI_RGB: + case TVOUT_OUTPUT_DVI: + temp_reg |= S5P_MXR_DST_SEL_HDMI; + temp_reg &= ~(0x1<<8); + temp_reg |= MX_RGB888<<8; + break; + + case TVOUT_OUTPUT_HDMI: + temp_reg |= S5P_MXR_DST_SEL_HDMI; + temp_reg &= ~(0x1<<8); + temp_reg |= MX_YUV444<<8; + break; + + default: + VMPRINTK(" invalid mode parameter = %d\n\r", mode); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + writel(temp_reg, mixer_base + S5P_MXR_CFG); + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CFG)); + + return VMIXER_NO_ERROR; +} + +u32 grp_scaling_factor(u32 src, u32 dst, u32 h_v) +{ + u32 factor; /* for scaling factor */ + + /* check scale or not */ + if (src == dst) + factor = 0; + + if (dst % src) { + factor = 0; + + VMPRINTK(" can't %s scaling src(%d) into dst(%d)\n" + , h_v ? "horizontal" : "vertical" + , src_w, dst_w); + VMPRINTK(" scaling vector must be 2/4/8x\n"); + } + + factor = dst / src; + + switch (factor) { + case 2: + factor = 1; + break; + case 4: + factor = 2; + break; + case 8: + factor = 3; + break; + default: + VMPRINTK(" scaling vector must be 2/4/8x\n"); + factor = 0; + break; + } + + return factor; +} + +void __s5p_vm_set_ctrl(enum s5p_tv_vmx_layer layer, + bool premul, + bool pixel_blending, + bool blank_change, + bool win_blending, + enum s5p_tv_vmx_color_fmt color, + u32 alpha, u32 blank_color) +{ + u32 reg = readl(mixer_base + S5P_MXR_GRAPHIC0_CFG); + + if (blank_change) + reg &= ~S5P_MXR_BLANK_CHANGE_NEW_PIXEL; + else + reg |= S5P_MXR_BLANK_CHANGE_NEW_PIXEL; + + + if (premul) + reg |= S5P_MXR_PRE_MUL_MODE; + else + reg &= ~S5P_MXR_PRE_MUL_MODE; + + if (win_blending) + reg |= S5P_MXR_WIN_BLEND_ENABLE; + else + reg &= ~S5P_MXR_WIN_BLEND_ENABLE; + + reg &= ~S5P_MXR_EG_COLOR_FORMAT(0xf); + reg |= S5P_MXR_EG_COLOR_FORMAT(color); + reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + + writel(reg, mixer_base + S5P_MXR_GRAPHIC0_CFG); + writel(S5P_MXR_GPR_BLANK_COLOR(blank_color), + mixer_base + S5P_MXR_GRAPHIC0_BLANK); + +} + +enum s5p_tv_vmx_err __s5p_vm_init_layer(enum s5p_tv_disp_mode mode, + enum s5p_tv_vmx_layer layer, + bool show, + bool win_blending, + u32 alpha, + u32 priority, + enum s5p_tv_vmx_color_fmt color, + bool blank_change, + bool pixel_blending, + bool premul, + u32 blank_color, + u32 base_addr, + u32 span, + u32 width, + u32 height, + u32 src_offs_x, + u32 src_offs_y, + u32 dst_offs_x, + u32 dst_offs_y, + u32 dst_width, + u32 dst_height) +{ + u32 temp_reg = 0; + u32 h_factor = 0, v_factor = 0; + + VMPRINTK("%d, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x,\ + 0x%x, %d, %d, %d, %d, %d, %d, %d)\n\r", + layer, show, win_blending, alpha, priority, + color, blank_change, pixel_blending, premul, + blank_color, base_addr, span, width, height, + src_offs_x, src_offs_y, dst_offs_x, dst_offs_y); + + switch (layer) { + + case VM_VIDEO_LAYER: + temp_reg = (win_blending) ? S5P_MXR_VP_BLEND_ENABLE : + S5P_MXR_VP_BLEND_DISABLE; + temp_reg |= S5P_MXR_VP_ALPHA_VALUE(alpha); + /* temp yuv pxl limiter setting*/ + temp_reg &= ~(1<<17); + writel(temp_reg, mixer_base + S5P_MXR_VIDEO_CFG); + break; + + case VM_GPR0_LAYER: + temp_reg = (blank_change) ? + S5P_MXR_BLANK_NOT_CHANGE_NEW_PIXEL : + S5P_MXR_BLANK_CHANGE_NEW_PIXEL; + temp_reg |= (premul) ? S5P_MXR_PRE_MUL_MODE : + S5P_MXR_NORMAL_MODE; + temp_reg |= (win_blending) ? S5P_MXR_WIN_BLEND_ENABLE : + S5P_MXR_WIN_BLEND_DISABLE; + temp_reg |= (pixel_blending) ? S5P_MXR_PIXEL_BLEND_ENABLE : + S5P_MXR_PIXEL_BLEND_DISABLE; + temp_reg |= S5P_MXR_EG_COLOR_FORMAT(color); + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC0_CFG); + writel(S5P_MXR_GPR_BLANK_COLOR(blank_color), + mixer_base + S5P_MXR_GRAPHIC0_BLANK); + + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC0_BLANK)); + + __s5p_vm_set_grp_layer_size(layer, span, width, height, + src_offs_x, src_offs_y); + + __s5p_vm_set_grp_base_address(layer, base_addr); + __s5p_vm_set_grp_layer_position(layer, dst_offs_x, + dst_offs_y); + + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC0_WH); + h_factor = grp_scaling_factor(width, dst_width, 1); + v_factor = grp_scaling_factor(height, dst_height, 0); + + temp_reg &= ~((0x3<<28)|(0x3<<12)); + + if (v_factor) { + + u32 reg = readl(mixer_base + S5P_MXR_CFG); + + /* In interlaced mode, vertical scaling must be + * replaced by PROGRESSIVE_MODE - pixel duplication + */ + if (mode == TVOUT_1080I_50 || + mode == TVOUT_1080I_59 || + mode == TVOUT_1080I_60) { + /* scaled up by progressive setting */ + reg |= S5P_MXR_PROGRESSVE_MODE; + writel(reg, mixer_base + S5P_MXR_CFG); + } else + /* scaled up by scale factor */ + temp_reg |= v_factor << 12; + } else { + u32 reg = readl(mixer_base + S5P_MXR_CFG); + + /* + * if v_factor is 0, recover the original mode + */ + if (mode == TVOUT_1080I_50 || + mode == TVOUT_1080I_59 || + mode == TVOUT_1080I_60) { + reg &= S5P_MXR_INTERLACE_MODE; + writel(reg, mixer_base + S5P_MXR_CFG); + } + } + + temp_reg |= h_factor << 28; + + writel(temp_reg , mixer_base + S5P_MXR_GRAPHIC0_WH); + + + break; + + case VM_GPR1_LAYER: + temp_reg = (blank_change) ? + S5P_MXR_BLANK_NOT_CHANGE_NEW_PIXEL : + S5P_MXR_BLANK_CHANGE_NEW_PIXEL; + temp_reg |= (premul) ? S5P_MXR_PRE_MUL_MODE : + S5P_MXR_NORMAL_MODE; + temp_reg |= (win_blending) ? S5P_MXR_WIN_BLEND_ENABLE : + S5P_MXR_WIN_BLEND_DISABLE; + temp_reg |= (pixel_blending) ? S5P_MXR_PIXEL_BLEND_ENABLE : + S5P_MXR_PIXEL_BLEND_DISABLE; + temp_reg |= S5P_MXR_EG_COLOR_FORMAT(color); + temp_reg |= S5P_MXR_GRP_ALPHA_VALUE(alpha); + + writel(temp_reg, mixer_base + S5P_MXR_GRAPHIC1_CFG); + writel(S5P_MXR_GPR_BLANK_COLOR(blank_color), + mixer_base + S5P_MXR_GRAPHIC1_BLANK); + + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_CFG)); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_GRAPHIC1_BLANK)); + + __s5p_vm_set_grp_layer_size(layer, span, width, height, + src_offs_x, src_offs_y); + + __s5p_vm_set_grp_base_address(layer, base_addr); + __s5p_vm_set_grp_layer_position(layer, dst_offs_x, dst_offs_y); + + temp_reg = readl(mixer_base + S5P_MXR_GRAPHIC1_WH); + h_factor = grp_scaling_factor(width, dst_width, 1); + v_factor = grp_scaling_factor(height, dst_height, 0); + + temp_reg &= ~((0x3<<28)|(0x3<<12)); + + if (v_factor) { + + u32 reg = readl(mixer_base + S5P_MXR_CFG); + + /* In interlaced mode, vertical scaling must be + * replaced by PROGRESSIVE_MODE - pixel duplication + */ + if (mode == TVOUT_1080I_50 || + mode == TVOUT_1080I_59 || + mode == TVOUT_1080I_60) { + /* scaled up by progressive setting */ + reg |= S5P_MXR_PROGRESSVE_MODE; + writel(reg, mixer_base + S5P_MXR_CFG); + } else + /* scaled up by scale factor */ + temp_reg |= v_factor << 12; + } else { + u32 reg = readl(mixer_base + S5P_MXR_CFG); + + /* + * if v_factor is 0, recover the original mode + */ + if (mode == TVOUT_1080I_50 || + mode == TVOUT_1080I_59 || + mode == TVOUT_1080I_60) { + reg &= S5P_MXR_INTERLACE_MODE; + writel(reg, mixer_base + S5P_MXR_CFG); + } + } + + temp_reg |= h_factor << 28; + + writel(temp_reg , mixer_base + S5P_MXR_GRAPHIC1_WH); + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + __s5p_vm_set_layer_priority(layer, priority); + + __s5p_vm_set_layer_show(layer, show); + + return VMIXER_NO_ERROR; +} + +void __s5p_vm_init_bg_dither_enable(bool cr_dither_enable, + bool cb_dither_enable, + bool y_dither_enable) +{ + u32 temp_reg = 0; + + VMPRINTK("%d, %d, %d\n\r", cr_dither_enable, cb_dither_enable, + y_dither_enable); + + temp_reg = (cr_dither_enable) ? + (temp_reg | S5P_MXR_BG_CR_DIHER_EN) : + (temp_reg & ~S5P_MXR_BG_CR_DIHER_EN); + temp_reg = (cb_dither_enable) ? + (temp_reg | S5P_MXR_BG_CB_DIHER_EN) : + (temp_reg & ~S5P_MXR_BG_CB_DIHER_EN); + temp_reg = (y_dither_enable) ? + (temp_reg | S5P_MXR_BG_Y_DIHER_EN) : + (temp_reg & ~S5P_MXR_BG_Y_DIHER_EN); + + writel(temp_reg, mixer_base + S5P_MXR_BG_CFG); + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_BG_CFG)); + +} + + +enum s5p_tv_vmx_err __s5p_vm_init_bg_color( + enum s5p_tv_vmx_bg_color_num color_num, + u32 color_y, + u32 color_cb, + u32 color_cr) +{ + return __s5p_vm_set_bg_color(color_num, color_y, color_cb, color_cr); +} + +enum s5p_tv_vmx_err __s5p_vm_init_csc_coef(enum s5p_yuv_fmt_component component, + enum s5p_tv_coef_y_mode mode, + u32 coeff0, + u32 coeff1, + u32 coeff2) +{ + u32 mxr_cm; + + VMPRINTK("%d, %d, %d, %d, %d\n\r", component, mode, coeff0, coeff1, + coeff2); + + switch (component) { + + case TVOUT_YUV_Y: + mxr_cm = (mode == VMIXER_COEF_Y_WIDE) ? + S5P_MXR_BG_COLOR_WIDE : S5P_MXR_BG_COLOR_NARROW; + mxr_cm |= S5P_MXR_BG_COEFF_0(coeff0) | + S5P_MXR_BG_COEFF_1(coeff1) | + S5P_MXR_BG_COEFF_2(coeff2); + writel(mxr_cm, mixer_base + S5P_MXR_CM_COEFF_Y); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + break; + + case TVOUT_YUV_CB: + mxr_cm = S5P_MXR_BG_COEFF_0(coeff0) | + S5P_MXR_BG_COEFF_1(coeff1) | + S5P_MXR_BG_COEFF_2(coeff2); + writel(mxr_cm, mixer_base + S5P_MXR_CM_COEFF_CB); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + break; + + case TVOUT_YUV_CR: + mxr_cm = S5P_MXR_BG_COEFF_0(coeff0) | + S5P_MXR_BG_COEFF_1(coeff1) | + S5P_MXR_BG_COEFF_2(coeff2); + writel(mxr_cm, S5P_MXR_CM_COEFF_CR); + VMPRINTK("--(0x%x)\n\r", + readl(mixer_base + S5P_MXR_CM_COEFF_CR)); + break; + + default: + VMPRINTK("invalid component parameter = %d\n\r", component); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + return VMIXER_NO_ERROR; +} + +void __s5p_vm_init_csc_coef_default(enum s5p_tv_vmx_csc_type csc_type) +{ + VMPRINTK("%d\n\r", csc_type); + + switch (csc_type) { + + case VMIXER_CSC_RGB_TO_YUV601_LR: + writel((0 << 30) | (153 << 20) | (300 << 10) | (58 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((936 << 20) | (851 << 10) | (262 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((262 << 20) | (805 << 10) | (982 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + case VMIXER_CSC_RGB_TO_YUV601_FR: + writel((1 << 30) | (132 << 20) | (258 << 10) | (50 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((948 << 20) | (875 << 10) | (225 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((225 << 20) | (836 << 10) | (988 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + case VMIXER_CSC_RGB_TO_YUV709_LR: + writel((0 << 30) | (109 << 20) | (366 << 10) | (36 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((964 << 20) | (822 << 10) | (216 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((262 << 20) | (787 << 10) | (1000 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + case VMIXER_CSC_RGB_TO_YUV709_FR: + writel((1 << 30) | (94 << 20) | (314 << 10) | (32 << 0), + mixer_base + S5P_MXR_CM_COEFF_Y); + writel((972 << 20) | (851 << 10) | (225 << 0), + mixer_base + S5P_MXR_CM_COEFF_CB); + writel((225 << 20) | (820 << 10) | (1004 << 0), + mixer_base + S5P_MXR_CM_COEFF_CR); + break; + + default: + VMPRINTK(" invalid csc_type parameter = %d\n\r", csc_type); + break; + } + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + VMPRINTK("--(0x%x)\n\r", readl(mixer_base + S5P_MXR_CM_COEFF_CR)); +} + +/* +* etc +*/ +enum s5p_tv_vmx_err __s5p_vm_get_layer_info(enum s5p_tv_vmx_layer layer, + bool *show, + u32 *priority) +{ + VMPRINTK("%d\n\r", layer); + + switch (layer) { + + case VM_VIDEO_LAYER: + *show = (readl(mixer_base + S5P_MXR_LAYER_CFG) & + S5P_MXR_VIDEO_LAYER_SHOW) ? 1 : 0; + *priority = S5P_MXR_VP_LAYER_PRIORITY_INFO( + readl(mixer_base + S5P_MXR_LAYER_CFG)); + break; + + case VM_GPR0_LAYER: + *show = (readl(mixer_base + S5P_MXR_LAYER_CFG) & + S5P_MXR_GRAPHIC0_LAYER_SHOW) ? 1 : 0; + *priority = S5P_MXR_GRP0_LAYER_PRIORITY_INFO( + readl(mixer_base + S5P_MXR_LAYER_CFG)); + break; + + case VM_GPR1_LAYER: + *show = (readl(mixer_base + S5P_MXR_LAYER_CFG) & + S5P_MXR_GRAPHIC1_LAYER_SHOW) ? 1 : 0; + *priority = S5P_MXR_GRP1_LAYER_PRIORITY_INFO( + readl(mixer_base + S5P_MXR_LAYER_CFG)); + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + VMPRINTK("%d, %d\n\r", *show, *priority); + + return VMIXER_NO_ERROR; +} + +/* +* start - start functions are only called under stopping vmixer +*/ + +void __s5p_vm_start(void) +{ + VMPRINTK("()\n\r"); + writel((readl(mixer_base + S5P_MXR_STATUS) | S5P_MXR_MIXER_START), + mixer_base + S5P_MXR_STATUS); + VMPRINTK("0x%x\n\r", readl(mixer_base + S5P_MXR_STATUS)); + + + VMPRINTK("S5P_MXR_STATUS \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_STATUS)); + VMPRINTK("S5P_MXR_INT_EN \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_INT_EN)); + VMPRINTK("S5P_MXR_BG_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_CFG)); + VMPRINTK("S5P_MXR_BG_COLOR0 \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_COLOR0)); + VMPRINTK("S5P_MXR_BG_COLOR1 \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_COLOR1)); + VMPRINTK("S5P_MXR_BG_COLOR2 \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_BG_COLOR2)); + VMPRINTK("S5P_MXR_CM_COEFF_Y \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + VMPRINTK("S5P_MXR_CM_COEFF_CB \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + VMPRINTK("S5P_MXR_CM_COEFF_CR \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CR)); + VMPRINTK("S5P_MXR_CM_COEFF_Y \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_Y)); + VMPRINTK("S5P_MXR_CM_COEFF_CB \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CB)); + VMPRINTK("S5P_MXR_CM_COEFF_CR \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CM_COEFF_CR)); + VMPRINTK("S5P_MXR_GRAPHIC0_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_CFG)); + VMPRINTK("S5P_MXR_GRAPHIC0_BASE \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_BASE)); + VMPRINTK("S5P_MXR_GRAPHIC0_SPAN \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_SPAN)); + VMPRINTK("S5P_MXR_GRAPHIC0_WH \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_WH)); + VMPRINTK("S5P_MXR_GRAPHIC0_SXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_SXY)); + VMPRINTK("S5P_MXR_GRAPHIC0_DXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_DXY)); + VMPRINTK("S5P_MXR_GRAPHIC0_BLANK \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC0_BLANK)); + VMPRINTK("S5P_MXR_GRAPHIC1_BASE \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_BASE)); + VMPRINTK("S5P_MXR_GRAPHIC1_SPAN \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_SPAN)); + VMPRINTK("S5P_MXR_GRAPHIC1_WH \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_WH)); + VMPRINTK("S5P_MXR_GRAPHIC1_SXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_SXY)); + VMPRINTK("S5P_MXR_GRAPHIC1_DXY \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_DXY)); + VMPRINTK("S5P_MXR_GRAPHIC1_BLANK \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_GRAPHIC1_BLANK)); + VMPRINTK("S5P_MXR_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_CFG)); + VMPRINTK("S5P_MXR_LAYER_CFG \t\t 0x%08x\n ", + readl(mixer_base + S5P_MXR_LAYER_CFG)); + +} + +/* +* stop - stop functions are only called under running vmixer +*/ + +void __s5p_vm_stop(void) +{ + u32 reg = readl(mixer_base + S5P_MXR_STATUS); + + reg &= ~S5P_MXR_MIXER_START; + + writel(reg, mixer_base + S5P_MXR_STATUS); + + do { + reg = readl(mixer_base + S5P_MXR_STATUS); + } while (reg & S5P_MXR_MIXER_START); +} + +/* +* interrupt - for debug +*/ + +enum s5p_tv_vmx_err __s5p_vm_set_underflow_interrupt_enable( + enum s5p_tv_vmx_layer layer, bool en) +{ + u32 enablemaks; + + VMPRINTK("%d, %d\n\r", layer, en); + + switch (layer) { + + case VM_VIDEO_LAYER: + enablemaks = S5P_MXR_VP_INT_ENABLE; + break; + + case VM_GPR0_LAYER: + enablemaks = S5P_MXR_GRP0_INT_ENABLE; + break; + + case VM_GPR1_LAYER: + enablemaks = S5P_MXR_GRP1_INT_ENABLE; + break; + + default: + VMPRINTK("invalid layer parameter = %d\n\r", layer); + return S5P_TV_VMX_ERR_INVALID_PARAM; + break; + } + + if (en) { + writel((readl(mixer_base + S5P_MXR_INT_EN) | enablemaks), + mixer_base + S5P_MXR_INT_EN); + } else { + writel((readl(mixer_base + S5P_MXR_INT_EN) & ~enablemaks), + mixer_base + S5P_MXR_INT_EN); + } + + VMPRINTK("0x%x)\n\r", readl(mixer_base + S5P_MXR_INT_EN)); + + return VMIXER_NO_ERROR; +} + +void __s5p_vm_clear_pend_all(void) +{ + writel(S5P_MXR_INT_FIRED | S5P_MXR_VP_INT_FIRED | + S5P_MXR_GRP0_INT_FIRED | S5P_MXR_GRP1_INT_FIRED, + mixer_base + S5P_MXR_INT_STATUS); +} + +irqreturn_t __s5p_mixer_irq(int irq, void *dev_id) +{ + bool v_i_f; + bool g0_i_f; + bool g1_i_f; + bool mxr_i_f; + u32 temp_reg = 0; + + v_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_VP_INT_FIRED) ? true : false; + g0_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_GRP0_INT_FIRED) ? true : false; + g1_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_GRP1_INT_FIRED) ? true : false; + mxr_i_f = (readl(mixer_base + S5P_MXR_INT_STATUS) + & S5P_MXR_INT_FIRED) ? true : false; + + if (mxr_i_f) { + temp_reg |= S5P_MXR_INT_FIRED; + + if (v_i_f) { + temp_reg |= S5P_MXR_VP_INT_FIRED; + printk("VP fifo under run!!\n\r"); + } + + if (g0_i_f) { + temp_reg |= S5P_MXR_GRP0_INT_FIRED; + printk("GRP0 fifo under run!!\n\r"); + } + + if (g1_i_f) { + temp_reg |= S5P_MXR_GRP1_INT_FIRED; + printk("GRP1 fifo under run!!\n\r"); + } + + writel(temp_reg, mixer_base + S5P_MXR_INT_STATUS); + } + + return IRQ_HANDLED; +} + +int __init __s5p_mixer_probe(struct platform_device *pdev, u32 res_num) +{ + struct resource *res; + size_t size; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + goto error; + + } + + size = (res->end - res->start) + 1; + + mixer_mem = request_mem_region(res->start, size, pdev->name); + + if (mixer_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + goto error; + + } + + mixer_base = ioremap(res->start, size); + + if (mixer_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + goto error; + + + } + return 0; +error: + return -ENOENT; + +} + +int __init __s5p_mixer_release(struct platform_device *pdev) +{ + iounmap(mixer_base); + + /* remove memory region */ + if (mixer_mem != NULL) { + if (release_resource(mixer_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(mixer_mem); + + mixer_mem = NULL; + } + + return 0; +} diff --git a/drivers/media/video/samsung/tv20/s5pv210/vp_coeff_s5pv210.h b/drivers/media/video/samsung/tv20/s5pv210/vp_coeff_s5pv210.h new file mode 100644 index 0000000..fb939fe --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/vp_coeff_s5pv210.h @@ -0,0 +1,310 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/vp_coeff_s5pv210.h + * + * Video Processor coefficient header file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +/* Horizontal Y 8tap */ +const signed char g_s_vp8tap_coef_y_h[] = { + /* VP_PP_H_NORMAL */ + 0, 0, 0, 0, 127, 0, 0, 0, + 0, 1, -2, 8, 126, -6, 2, -1, + 0, 1, -5, 16, 125, -12, 4, -1, + 0, 2, -8, 25, 121, -16, 5, -1, + -1, 3, -10, 35, 114, -18, 6, -1, + -1, 4, -13, 46, 107, -20, 6, -1, + -1, 5, -16, 57, 99, -21, 6, -1, + -1, 5, -18, 68, 89, -20, 6, -1, + -1, 6, -20, 79, 79, -20, 6, -1, + -1, 6, -20, 89, 68, -18, 5, -1, + -1, 6, -21, 99, 57, -16, 5, -1, + -1, 6, -20, 107, 46, -13, 4, -1, + -1, 6, -18, 114, 35, -10, 3, -1, + -1, 5, -16, 121, 25, -8, 2, 0, + -1, 4, -12, 125, 16, -5, 1, 0, + -1, 2, -6, 126, 8, -2, 1, 0, + + /* VP_PP_H_8_9 */ + 0, 3, -7, 12, 112, 12, -7, 3, + -1, 3, -9, 19, 113, 6, -5, 2, + -1, 3, -11, 27, 111, 0, -3, 2, + -1, 4, -13, 35, 108, -5, -1, 1, + -1, 4, -14, 43, 104, -9, 0, 1, + -1, 5, -16, 52, 99, -12, 1, 0, + -1, 5, -17, 61, 92, -14, 2, 0, + 0, 4, -17, 69, 85, -16, 3, 0, + 0, 4, -17, 77, 77, -17, 4, 0, + 0, 3, -16, 85, 69, -17, 4, 0, + 0, 2, -14, 92, 61, -17, 5, -1, + 0, 1, -12, 99, 52, -16, 5, -1, + 1, 0, -9, 104, 43, -14, 4, -1, + 1, -1, -5, 108, 35, -13, 4, -1, + 2, -3, 0, 111, 27, -11, 3, -1, + 2, -5, 6, 113, 19, -9, 3, -1, + + /* VP_PP_H_1_2 */ + 0, -3, 0, 35, 64, 35, 0, -3, + 0, -3, 1, 38, 64, 32, -1, -3, + 0, -3, 2, 41, 63, 29, -2, -2, + 0, -4, 4, 43, 63, 27, -3, -2, + 0, -4, 5, 46, 62, 24, -3, -2, + 0, -4, 7, 49, 60, 21, -3, -2, + -1, -4, 9, 51, 59, 19, -4, -1, + -1, -4, 12, 53, 57, 16, -4, -1, + -1, -4, 14, 55, 55, 14, -4, -1, + -1, -4, 16, 57, 53, 12, -4, -1, + -1, -4, 19, 59, 51, 9, -4, -1, + -2, -3, 21, 60, 49, 7, -4, 0, + -2, -3, 24, 62, 46, 5, -4, 0, + -2, -3, 27, 63, 43, 4, -4, 0, + -2, -2, 29, 63, 41, 2, -3, 0, + -3, -1, 32, 64, 38, 1, -3, 0, + + /* VP_PP_H_1_3 */ + 0, 0, 10, 32, 44, 32, 10, 0, + -1, 0, 11, 33, 45, 31, 9, 0, + -1, 0, 12, 35, 45, 29, 8, 0, + -1, 1, 13, 36, 44, 28, 7, 0, + -1, 1, 15, 37, 44, 26, 6, 0, + -1, 2, 16, 38, 43, 25, 5, 0, + -1, 2, 18, 39, 43, 23, 5, -1, + -1, 3, 19, 40, 42, 22, 4, -1, + -1, 3, 21, 41, 41, 21, 3, -1, + -1, 4, 22, 42, 40, 19, 3, -1, + -1, 5, 23, 43, 39, 18, 2, -1, + 0, 5, 25, 43, 38, 16, 2, -1, + 0, 6, 26, 44, 37, 15, 1, -1, + 0, 7, 28, 44, 36, 13, 1, -1, + 0, 8, 29, 45, 35, 12, 0, -1, + 0, 9, 31, 45, 33, 11, 0, -1, + + /* VP_PP_H_1_4 */ + 0, 2, 13, 30, 38, 30, 13, 2, + 0, 3, 14, 30, 38, 29, 12, 2, + 0, 3, 15, 31, 38, 28, 11, 2, + 0, 4, 16, 32, 38, 27, 10, 1, + 0, 4, 17, 33, 37, 26, 10, 1, + 0, 5, 18, 34, 37, 24, 9, 1, + 0, 5, 19, 34, 37, 24, 8, 1, + 1, 6, 20, 35, 36, 22, 7, 1, + 1, 6, 21, 36, 36, 21, 6, 1, + 1, 7, 22, 36, 35, 20, 6, 1, + 1, 8, 24, 37, 34, 19, 5, 0, + 1, 9, 24, 37, 34, 18, 5, 0, + 1, 10, 26, 37, 33, 17, 4, 0, + 1, 10, 27, 38, 32, 16, 4, 0, + 2, 11, 28, 38, 31, 15, 3, 0, + 2, 12, 29, 38, 30, 14, 3, 0 +}; + +/* Horizontal C 4tap */ +const signed char g_s_vp4tap_coef_c_h[] = { + /* VP_PP_H_NORMAL */ + 0, 0, 128, 0, + 0, 5, 126, -3, + -1, 11, 124, -6, + -1, 19, 118, -8, + -2, 27, 111, -8, + -3, 37, 102, -8, + -4, 48, 92, -8, + -5, 59, 81, -7, + -6, 70, 70, -6, + -7, 81, 59, -5, + -8, 92, 48, -4, + -8, 102, 37, -3, + -8, 111, 27, -2, + -8, 118, 19, -1, + -6, 124, 11, -1, + -3, 126, 5, 0, + + /* VP_PP_H_8_9 */ + 0, 8, 112, 8, + -1, 13, 113, 3, + -2, 19, 111, 0, + -2, 26, 107, -3, + -3, 34, 101, -4, + -3, 42, 94, -5, + -4, 51, 86, -5, + -5, 60, 78, -5, + -5, 69, 69, -5, + -5, 78, 60, -5, + -5, 86, 51, -4, + -5, 94, 42, -3, + -4, 101, 34, -3, + -3, 107, 26, -2, + 0, 111, 19, -2, + 3, 113, 13, -1, + + /* VP_PP_H_1_2 */ + 0, 26, 76, 26, + 0, 30, 76, 22, + 0, 34, 75, 19, + 1, 38, 73, 16, + 1, 43, 71, 13, + 2, 47, 69, 10, + 3, 51, 66, 8, + 4, 55, 63, 6, + 5, 59, 59, 5, + 6, 63, 55, 4, + 8, 66, 51, 3, + 10, 69, 47, 2, + 13, 71, 43, 1, + 16, 73, 38, 1, + 19, 75, 34, 0, + 22, 76, 30, 0, + + /* VP_PP_H_1_3 */ + 0, 30, 68, 30, + 2, 33, 66, 27, + 3, 36, 66, 23, + 3, 39, 65, 21, + 4, 43, 63, 18, + 5, 46, 62, 15, + 6, 49, 60, 13, + 8, 52, 57, 11, + 9, 55, 55, 9, + 11, 57, 52, 8, + 13, 60, 49, 6, + 15, 62, 46, 5, + 18, 63, 43, 4, + 21, 65, 39, 3, + 23, 66, 36, 3, + 27, 66, 33, 2, + + /* VP_PP_H_1_4 */ + 0, 31, 66, 31, + 3, 34, 63, 28, + 4, 37, 62, 25, + 4, 40, 62, 22, + 5, 43, 61, 19, + 6, 46, 59, 17, + 7, 48, 58, 15, + 9, 51, 55, 13, + 11, 53, 53, 11, + 13, 55, 51, 9, + 15, 58, 48, 7, + 17, 59, 46, 6, + 19, 61, 43, 5, + 22, 62, 40, 4, + 25, 62, 37, 4, + 28, 63, 34, 3, +}; + + +/* Vertical Y 8tap */ +const signed char g_s_vp4tap_coef_y_v[] = { + /* VP_PP_V_NORMAL */ + 0, 0, 127, 0, + 0, 5, 126, -3, + -1, 11, 124, -6, + -1, 19, 118, -8, + -2, 27, 111, -8, + -3, 37, 102, -8, + -4, 48, 92, -8, + -5, 59, 81, -7, + -6, 70, 70, -6, + -7, 81, 59, -5, + -8, 92, 48, -4, + -8, 102, 37, -3, + -8, 111, 27, -2, + -8, 118, 19, -1, + -6, 124, 11, -1, + -3, 126, 5, 0, + + /* VP_PP_V_5_6 */ + 0, 11, 106, 11, + -2, 16, 107, 7, + -2, 22, 105, 3, + -2, 29, 101, 0, + -3, 36, 96, -1, + -3, 44, 90, -3, + -4, 52, 84, -4, + -4, 60, 76, -4, + -4, 68, 68, -4, + -4, 76, 60, -4, + -4, 84, 52, -4, + -3, 90, 44, -3, + -1, 96, 36, -3, + 0, 101, 29, -2, + 3, 105, 22, -2, + 7, 107, 16, -2, + + /* VP_PP_V_3_4 */ + 0, 15, 98, 15, + -2, 21, 97, 12, + -2, 26, 96, 8, + -2, 32, 93, 5, + -2, 39, 89, 2, + -2, 46, 84, 0, + -3, 53, 79, -1, + -2, 59, 73, -2, + -2, 66, 66, -2, + -2, 73, 59, -2, + -1, 79, 53, -3, + 0, 84, 46, -2, + 2, 89, 39, -2, + 5, 93, 32, -2, + 8, 96, 26, -2, + 12, 97, 21, -2, + + /* VP_PP_V_1_2 */ + 0, 26, 76, 26, + 0, 30, 76, 22, + 0, 34, 75, 19, + 1, 38, 73, 16, + 1, 43, 71, 13, + 2, 47, 69, 10, + 3, 51, 66, 8, + 4, 55, 63, 6, + 5, 59, 59, 5, + 6, 63, 55, 4, + 8, 66, 51, 3, + 10, 69, 47, 2, + 13, 71, 43, 1, + 16, 73, 38, 1, + 19, 75, 34, 0, + 22, 76, 30, 0, + + /* VP_PP_V_1_3 */ + 0, 30, 68, 30, + 2, 33, 66, 27, + 3, 36, 66, 23, + 3, 39, 65, 21, + 4, 43, 63, 18, + 5, 46, 62, 15, + 6, 49, 60, 13, + 8, 52, 57, 11, + 9, 55, 55, 9, + 11, 57, 52, 8, + 13, 60, 49, 6, + 15, 62, 46, 5, + 18, 63, 43, 4, + 21, 65, 39, 3, + 23, 66, 36, 3, + 27, 66, 33, 2, + + /* VP_PP_V_1_4 */ + 0, 31, 66, 31, + 3, 34, 63, 28, + 4, 37, 62, 25, + 4, 40, 62, 22, + 5, 43, 61, 19, + 6, 46, 59, 17, + 7, 48, 58, 15, + 9, 51, 55, 13, + 11, 53, 53, 11, + 13, 55, 51, 9, + 15, 58, 48, 7, + 17, 59, 46, 6, + 19, 61, 43, 5, + 22, 62, 40, 4, + 25, 62, 37, 4, + 28, 63, 34, 3 +}; + diff --git a/drivers/media/video/samsung/tv20/s5pv210/vprocessor_s5pv210.c b/drivers/media/video/samsung/tv20/s5pv210/vprocessor_s5pv210.c new file mode 100644 index 0000000..34bcdf2 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5pv210/vprocessor_s5pv210.c @@ -0,0 +1,814 @@ +/* linux/drivers/media/video/samsung/tv20/s5pv210/vprocessor_s5pv210.c + * + * Video Processor raw ftn file for Samsung TVOut driver + * + * Copyright (c) 2010 Samsung Electronics + * http://www.samsungsemi.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> + +#include "tv_out_s5pv210.h" + +#include "regs/regs-vprocessor.h" +#include "vp_coeff_s5pv210.h" + +#ifdef COFIG_TVOUT_RAW_DBG +#define S5P_VP_DEBUG 1 +#endif + +#ifdef S5P_VP_DEBUG +#define VPPRINTK(fmt, args...)\ + printk(KERN_ERR "\t\t[VP] %s: " fmt, __func__ , ## args) +#else +#define VPPRINTK(fmt, args...) +#endif + +static struct resource *vp_mem; +void __iomem *vp_base; + +/* +* set +* - set functions are only called under running video processor +* - after running set functions, it is need to run __s5p_vp_update() function +* for update shadow registers +*/ +void __s5p_vp_set_field_id(enum s5p_vp_field mode) +{ + VPPRINTK("%d\n\r", mode); + + writel((mode == VPROC_TOP_FIELD) ? + vp_base + S5P_VP_FIELD_ID_TOP : + vp_base + S5P_VP_FIELD_ID_BOTTOM, + vp_base + S5P_VP_FIELD_ID); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_FIELD_ID)); +} + +enum s5p_tv_vp_err __s5p_vp_set_top_field_address(u32 top_y_addr, + u32 top_c_addr) +{ + VPPRINTK("0x%x, 0x%x\n\r", top_y_addr, top_c_addr); + + if (VP_PTR_ILLEGAL(top_y_addr) || VP_PTR_ILLEGAL(top_c_addr)) { + VPPRINTK(" address is not double word align = 0x%x, 0x%x\n\r", + top_y_addr, top_c_addr); + return S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN; + } + + writel(top_y_addr, vp_base + S5P_VP_TOP_Y_PTR); + + writel(top_c_addr, vp_base + S5P_VP_TOP_C_PTR); + + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_TOP_Y_PTR), + readl(vp_base + S5P_VP_TOP_C_PTR)); + + return VPROC_NO_ERROR; +} + +enum s5p_tv_vp_err __s5p_vp_set_bottom_field_address(u32 bottom_y_addr, + u32 bottom_c_addr) +{ + VPPRINTK("0x%x, 0x%x\n\r", bottom_y_addr, bottom_c_addr); + + if (VP_PTR_ILLEGAL(bottom_y_addr) || VP_PTR_ILLEGAL(bottom_c_addr)) { + VPPRINTK(" address is not double word align = 0x%x, 0x%x\n\r", + bottom_y_addr, bottom_c_addr); + return S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN; + } + + writel(bottom_y_addr, vp_base + S5P_VP_BOT_Y_PTR); + + writel(bottom_c_addr, vp_base + S5P_VP_BOT_C_PTR); + + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_BOT_Y_PTR), + readl(vp_base + S5P_VP_BOT_C_PTR)); + + return VPROC_NO_ERROR; +} + + +enum s5p_tv_vp_err __s5p_vp_set_img_size(u32 img_width, u32 img_height) +{ + VPPRINTK("%d, %d\n\r", img_width, img_height); + + if (VP_IMG_SIZE_ILLEGAL(img_width) || + VP_IMG_SIZE_ILLEGAL(img_height)) { + VPPRINTK(" image full size is not double word align =\ + %d, %d\n\r", + img_width, img_height); + + return S5P_TV_VP_ERR_BASE_ADDRESS_MUST_DOUBLE_WORD_ALIGN; + } + + writel(VP_IMG_HSIZE(img_width) | VP_IMG_VSIZE(img_height), + vp_base + S5P_VP_IMG_SIZE_Y); + + writel(VP_IMG_HSIZE(img_width) | VP_IMG_VSIZE(img_height / 2), + vp_base + S5P_VP_IMG_SIZE_C); + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_IMG_SIZE_Y), + readl(vp_base + S5P_VP_IMG_SIZE_C)); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_set_src_position(u32 src_off_x, + u32 src_x_fract_step, + u32 src_off_y) +{ + VPPRINTK("%d, %d, %d)\n\r", src_off_x, src_x_fract_step, src_off_y); + + writel(VP_SRC_H_POSITION(src_off_x) | + VP_SRC_X_FRACT_STEP(src_x_fract_step), + vp_base + S5P_VP_SRC_H_POSITION); + writel(VP_SRC_V_POSITION(src_off_y), vp_base + S5P_VP_SRC_V_POSITION); + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_SRC_H_POSITION), + readl(vp_base + S5P_VP_SRC_V_POSITION)); +} + +void __s5p_vp_set_dest_position(u32 dst_off_x, + u32 dst_off_y) +{ + VPPRINTK("%d, %d)\n\r", dst_off_x, dst_off_y); + + + writel(VP_DST_H_POSITION(dst_off_x), vp_base + S5P_VP_DST_H_POSITION); + writel(VP_DST_V_POSITION(dst_off_y), vp_base + S5P_VP_DST_V_POSITION); + + VPPRINTK("0x%x, 0x%x\n\r", readl(vp_base + S5P_VP_DST_H_POSITION), + readl(vp_base + S5P_VP_DST_V_POSITION)); +} + +void __s5p_vp_set_src_dest_size(u32 src_width, + u32 src_height, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + u32 h_ratio = (src_width << 16) / dst_width; + u32 v_ratio = (ipc_2d) ? + ((src_height << 17) / dst_height) : + ((src_height << 16) / dst_height); + + VPPRINTK("(%d, %d, %d, %d)++\n\r", src_width, src_height, + dst_width, dst_height); + + writel(VP_SRC_WIDTH(src_width), vp_base + S5P_VP_SRC_WIDTH); + writel(VP_SRC_HEIGHT(src_height), vp_base + S5P_VP_SRC_HEIGHT); + writel(VP_DST_WIDTH(dst_width), vp_base + S5P_VP_DST_WIDTH); + writel(VP_DST_HEIGHT(dst_height), vp_base + S5P_VP_DST_HEIGHT) ; + writel(VP_H_RATIO(h_ratio), vp_base + S5P_VP_H_RATIO); + writel(VP_V_RATIO(v_ratio), vp_base + S5P_VP_V_RATIO); + + writel((ipc_2d) ? (readl(vp_base + S5P_VP_MODE) | VP_2D_IPC_ON) : + (readl(vp_base + S5P_VP_MODE) & ~VP_2D_IPC_ON), + vp_base + S5P_VP_MODE); + + VPPRINTK("%d, %d, %d, %d, 0x%x, 0x%x\n\r", + readl(vp_base + S5P_VP_SRC_WIDTH), + readl(vp_base + S5P_VP_SRC_HEIGHT), + readl(vp_base + S5P_VP_DST_WIDTH), + readl(vp_base + S5P_VP_DST_HEIGHT), + readl(vp_base + S5P_VP_H_RATIO), + readl(vp_base + S5P_VP_V_RATIO)); +} + +enum s5p_tv_vp_err __s5p_vp_set_poly_filter_coef( + enum s5p_vp_poly_coeff poly_coeff, + signed char ch0, + signed char ch1, + signed char ch2, + signed char ch3) +{ + VPPRINTK("%d, %d, %d, %d, %d)\n\r", poly_coeff, ch0, ch1, ch2, ch3); + + if (poly_coeff > VPROC_POLY4_C1_HH || poly_coeff < VPROC_POLY8_Y0_LL || + (poly_coeff > VPROC_POLY8_Y3_HH && + poly_coeff < VPROC_POLY4_Y0_LL)) { + + VPPRINTK("invaild poly_coeff parameter \n\r"); + return S5P_TV_VP_ERR_INVALID_PARAM; + } + + writel((((0xff&ch0) << 24) | ((0xff&ch1) << 16) | ((0xff&ch2) << 8) | + (0xff&ch3)), vp_base + S5P_VP_POLY8_Y0_LL + poly_coeff*4); + + VPPRINTK("0x%08x, 0x%08x\n\r", + readl(vp_base + S5P_VP_POLY8_Y0_LL + poly_coeff*4), + vp_base + S5P_VP_POLY8_Y0_LL + poly_coeff*4); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_set_poly_filter_coef_default(u32 h_ratio, u32 v_ratio) +{ + enum s5p_tv_vp_filter_h_pp e_h_filter; + enum s5p_tv_vp_filter_v_pp e_v_filter; + u8 *poly_flt_coeff; + int i, j; + + VPPRINTK("%d, %d\n\r", h_ratio, v_ratio); + + /* + * For the real interlace mode, the vertical ratio should be + * used after divided by 2. Because in the interlace mode, all + * the VP output is used for SDOUT display and it should be the + * same as one field of the progressive mode. Therefore the same + * filter coefficients should be used for the same the final + * output video. When half of the interlace V_RATIO is same as + * the progressive V_RATIO, the final output video scale is same. + */ + + /*Horizontal Y 8tap */ + /*Horizontal C 4tap */ + + + if (h_ratio <= (0x1 << 16)) /* 720->720 or zoom in */ + e_h_filter = VPROC_PP_H_NORMAL; + + + + else if (h_ratio <= (0x9 << 13)) /* 720->640 */ + e_h_filter = VPROC_PP_H_8_9; + + + else if (h_ratio <= (0x1 << 17)) /* 2->1 */ + e_h_filter = VPROC_PP_H_1_2; + + + else if (h_ratio <= (0x3 << 16)) /* 2->1 */ + e_h_filter = VPROC_PP_H_1_3; + else + e_h_filter = VPROC_PP_H_1_4; /* 4->1 */ + + /* Vertical Y 4tap */ + + if (v_ratio <= (0x1 << 16)) /* 720->720 or zoom in*/ + e_v_filter = VPROC_PP_V_NORMAL; + else if (v_ratio <= (0x5 << 14)) /* 4->3*/ + e_v_filter = VPROC_PP_V_3_4; + else if (v_ratio <= (0x3 << 15)) /*6->5*/ + e_v_filter = VPROC_PP_V_5_6; + else if (v_ratio <= (0x1 << 17)) /* 2->1*/ + e_v_filter = VPROC_PP_V_1_2; + else if (v_ratio <= (0x3 << 16)) /* 3->1*/ + e_v_filter = VPROC_PP_V_1_3; + else + e_v_filter = VPROC_PP_V_1_4; + + poly_flt_coeff = (u8 *)(g_s_vp8tap_coef_y_h + e_h_filter * 16 * 8); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + __s5p_vp_set_poly_filter_coef( + VPROC_POLY8_Y0_LL + (i*4) + j, + *(poly_flt_coeff + 4*j*8 + (7 - i)), + *(poly_flt_coeff + (4*j + 1)*8 + (7 - i)), + *(poly_flt_coeff + (4*j + 2)*8 + (7 - i)), + *(poly_flt_coeff + (4*j + 3)*8 + (7 - i))); + } + } + + poly_flt_coeff = (u8 *)(g_s_vp4tap_coef_c_h + e_h_filter * 16 * 4); + + for (i = 0; i < 2; i++) { + for (j = 0; j < 4; j++) { + __s5p_vp_set_poly_filter_coef( + VPROC_POLY4_C0_LL + (i*4) + j, + *(poly_flt_coeff + 4*j*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 1)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 2)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 3)*4 + (3 - i))); + } + } + + poly_flt_coeff = (u8 *)(g_s_vp4tap_coef_y_v + e_v_filter * 16 * 4); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + __s5p_vp_set_poly_filter_coef( + VPROC_POLY4_Y0_LL + (i*4) + j, + *(poly_flt_coeff + 4*j*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 1)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 2)*4 + (3 - i)), + *(poly_flt_coeff + (4*j + 3)*4 + (3 - i))); + } + } + + VPPRINTK("%d, %d\n\r", e_h_filter, e_v_filter); +} + +void __s5p_vp_set_src_dest_size_with_default_poly_filter_coef(u32 src_width, + u32 src_height, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + u32 h_ratio = (src_width << 16) / dst_width; + u32 v_ratio = (ipc_2d) ? ((src_height << 17) / dst_height) : + ((src_height << 16) / dst_height); + + __s5p_vp_set_src_dest_size(src_width, src_height, dst_width, + dst_height, ipc_2d); + __s5p_vp_set_poly_filter_coef_default(h_ratio, v_ratio); +} + +enum s5p_tv_vp_err __s5p_vp_set_brightness_contrast_control( + enum s5p_vp_line_eq eq_num, + u32 intc, + u32 slope) +{ + VPPRINTK("%d, %d, %d\n\r", eq_num, intc, slope); + + if ((eq_num > VProc_LINE_EQ_7) || (eq_num < VProc_LINE_EQ_0)) { + VPPRINTK("invaild eq_num parameter \n\r"); + return S5P_TV_VP_ERR_INVALID_PARAM; + } + + writel(VP_LINE_INTC(intc) | VP_LINE_SLOPE(slope), + vp_base + S5P_PP_LINE_EQ0 + eq_num*4); + + VPPRINTK("0x%08x, 0x%08x\n\r", + readl(vp_base + S5P_PP_LINE_EQ0 + eq_num*4), + vp_base + S5P_PP_LINE_EQ0 + eq_num*4); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_set_brightness(bool brightness) +{ + unsigned short i; + + VPPRINTK("%d\n\r", brightness); + + g_vp_contrast_brightness = + VP_LINE_INTC_CLEAR(g_vp_contrast_brightness) | + VP_LINE_INTC(brightness); + + for (i = 0; i < 8; i++) + writel(g_vp_contrast_brightness, + vp_base + S5P_PP_LINE_EQ0 + i*4); + + + VPPRINTK("%d\n\r", g_vp_contrast_brightness); +} + +void __s5p_vp_set_contrast(u8 contrast) +{ + unsigned short i; + + VPPRINTK("%d\n\r", contrast); + + g_vp_contrast_brightness = + VP_LINE_SLOPE_CLEAR(g_vp_contrast_brightness) | + VP_LINE_SLOPE(contrast); + + for (i = 0; i < 8; i++) + writel(g_vp_contrast_brightness, + vp_base + S5P_PP_LINE_EQ0 + i*4); + + VPPRINTK("%d\n\r", g_vp_contrast_brightness); +} + +enum s5p_tv_vp_err __s5p_vp_update(void) +{ + VPPRINTK("()\n\r"); + + writel(readl(vp_base + S5P_VP_SHADOW_UPDATE) | + S5P_VP_SHADOW_UPDATE_ENABLE, + vp_base + S5P_VP_SHADOW_UPDATE); + + VPPRINTK("()\n\r"); + + return VPROC_NO_ERROR; +} + +/* +* get - get info +*/ +enum s5p_vp_field __s5p_vp_get_field_id(void) +{ + VPPRINTK("()\n\r"); + return (readl(vp_base + S5P_VP_FIELD_ID) == + S5P_VP_FIELD_ID_BOTTOM) ? + VPROC_BOTTOM_FIELD : VPROC_TOP_FIELD; +} + +/* +* etc +*/ +unsigned short __s5p_vp_get_update_status(void) +{ + VPPRINTK("()\n\r"); + return readl(vp_base + S5P_VP_SHADOW_UPDATE) & + S5P_VP_SHADOW_UPDATE_ENABLE; +} + + +void __s5p_vp_init_field_id(enum s5p_vp_field mode) +{ + __s5p_vp_set_field_id(mode); +} + +void __s5p_vp_init_op_mode(bool line_skip, + enum s5p_vp_mem_mode mem_mode, + enum s5p_vp_chroma_expansion chroma_exp, + enum s5p_vp_filed_id_toggle toggle_id) +{ + u32 temp_reg; + VPPRINTK("%d, %d, %d, %d\n\r", line_skip, mem_mode, + chroma_exp, toggle_id); + + temp_reg = (line_skip) ? VP_LINE_SKIP_ON : VP_LINE_SKIP_OFF; + temp_reg |= (mem_mode == VPROC_2D_TILE_MODE) ? + VP_MEM_2D_MODE : VP_MEM_LINEAR_MODE; + temp_reg |= (chroma_exp == VPROC_USING_C_TOP_BOTTOM) ? + VP_CHROMA_USE_TOP_BOTTOM : VP_CHROMA_USE_TOP; + temp_reg |= (toggle_id == S5P_TV_VP_FILED_ID_TOGGLE_VSYNC) ? + VP_FIELD_ID_TOGGLE_VSYNC : VP_FIELD_ID_TOGGLE_USER; + + writel(temp_reg, vp_base + S5P_VP_MODE); + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_MODE)); +} + +void __s5p_vp_init_pixel_rate_control(enum s5p_vp_pxl_rate rate) +{ + VPPRINTK("%d\n\r", rate); + + writel(VP_PEL_RATE_CTRL(rate), vp_base + S5P_VP_PER_RATE_CTRL); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_PER_RATE_CTRL)); +} + +enum s5p_tv_vp_err __s5p_vp_init_layer(u32 top_y_addr, + u32 top_c_addr, + u32 bottom_y_addr, + u32 bottom_c_addr, + enum s5p_endian_type src_img_endian, + u32 img_width, + u32 img_height, + u32 src_off_x, + u32 src_x_fract_step, + u32 src_off_y, + u32 src_width, + u32 src_height, + u32 dst_off_x, + u32 dst_off_y, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + VPPRINTK("%d\n\r", src_img_endian); + + writel(1, vp_base + S5P_VP_ENDIAN_MODE); + + error = __s5p_vp_set_top_field_address(top_y_addr, top_c_addr); + + if (error != VPROC_NO_ERROR) + return error; + + error = __s5p_vp_set_bottom_field_address(bottom_y_addr, + bottom_c_addr); + + if (error != VPROC_NO_ERROR) + return error; + + error = __s5p_vp_set_img_size(img_width, img_height); + + if (error != VPROC_NO_ERROR) + return error; + + __s5p_vp_set_src_position(src_off_x, src_x_fract_step, src_off_y); + + __s5p_vp_set_dest_position(dst_off_x, dst_off_y); + + __s5p_vp_set_src_dest_size(src_width, src_height, dst_width, + dst_height, ipc_2d); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_VP_ENDIAN_MODE)); + + return error; + +} + +enum s5p_tv_vp_err __s5p_vp_init_layer_def_poly_filter_coef(u32 top_y_addr, + u32 top_c_addr, + u32 bottom_y_addr, + u32 bottom_c_addr, + enum s5p_endian_type src_img_endian, + u32 img_width, + u32 img_height, + u32 src_off_x, + u32 src_x_fract_step, + u32 src_off_y, + u32 src_width, + u32 src_height, + u32 dst_off_x, + u32 dst_off_y, + u32 dst_width, + u32 dst_height, + bool ipc_2d) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + u32 h_ratio = (src_width << 16) / dst_width; + u32 v_ratio = (ipc_2d) ? ((src_height << 17) / dst_height) : + ((src_height << 16) / dst_height); + + __s5p_vp_set_poly_filter_coef_default(h_ratio, v_ratio); + error = __s5p_vp_init_layer(top_y_addr, top_c_addr, + bottom_y_addr, bottom_c_addr, + src_img_endian, + img_width, img_height, + src_off_x, src_x_fract_step, src_off_y, + src_width, src_height, + dst_off_x, dst_off_y, + dst_width, dst_height, + ipc_2d); + return error; +} + +enum s5p_tv_vp_err __s5p_vp_init_poly_filter_coef( + enum s5p_vp_poly_coeff poly_coeff, + signed char ch0, + signed char ch1, + signed char ch2, + signed char ch3) +{ + return __s5p_vp_set_poly_filter_coef(poly_coeff, ch0, ch1, ch2, ch3); +} + +void __s5p_vp_init_bypass_post_process(bool bypass) +{ + VPPRINTK("%d\n\r", bypass); + + writel((bypass) ? VP_BY_PASS_ENABLE : VP_BY_PASS_DISABLE, + vp_base + S5P_PP_BYPASS); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_BYPASS)); +} + +enum s5p_tv_vp_err __s5p_vp_init_csc_coef( + enum s5p_vp_csc_coeff csc_coeff, u32 coeff) +{ + VPPRINTK("%d, %d\n\r", csc_coeff, coeff); + + if (csc_coeff > VPROC_CSC_CR2CR_COEF || + csc_coeff < VPROC_CSC_Y2Y_COEF) { + VPPRINTK("invaild csc_coeff parameter \n\r"); + return S5P_TV_VP_ERR_INVALID_PARAM; + } + + writel(VP_CSC_COEF(coeff), + vp_base + S5P_PP_CSC_Y2Y_COEF + csc_coeff*4); + + VPPRINTK("0x%08x\n\r", + readl(vp_base + S5P_PP_CSC_Y2Y_COEF + csc_coeff*4)); + + return VPROC_NO_ERROR; +} + +void __s5p_vp_init_saturation(u32 sat) +{ + VPPRINTK("%d\n\r", sat); + + writel(VP_SATURATION(sat), vp_base + S5P_PP_SATURATION); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_SATURATION)); +} + +void __s5p_vp_init_sharpness(u32 th_h_noise, + enum s5p_vp_sharpness_control sharpness) +{ + VPPRINTK("%d, %d\n\r", th_h_noise, sharpness); + + writel(VP_TH_HNOISE(th_h_noise) | VP_SHARPNESS(sharpness), + vp_base + S5P_PP_SHARPNESS); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_SHARPNESS)); +} + +enum s5p_tv_vp_err __s5p_vp_init_brightness_contrast_control( + enum s5p_vp_line_eq eq_num, + u32 intc, + u32 slope) +{ + return __s5p_vp_set_brightness_contrast_control(eq_num, intc, slope); +} + +void __s5p_vp_init_brightness(bool brightness) +{ + __s5p_vp_set_brightness(brightness); +} + + +void __s5p_vp_init_contrast(u8 contrast) +{ + __s5p_vp_set_contrast(contrast); +} + +void __s5p_vp_init_brightness_offset(u32 offset) +{ + VPPRINTK("%d\n\r", offset); + + writel(VP_BRIGHT_OFFSET(offset), vp_base + S5P_PP_BRIGHT_OFFSET); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_BRIGHT_OFFSET)); +} + +void __s5p_vp_init_csc_control(bool sub_y_offset_en, bool csc_en) +{ + u32 temp_reg; + VPPRINTK("%d, %d\n\r", sub_y_offset_en, csc_en); + + temp_reg = (sub_y_offset_en) ? VP_SUB_Y_OFFSET_ENABLE : + VP_SUB_Y_OFFSET_DISABLE; + temp_reg |= (csc_en) ? VP_CSC_ENABLE : VP_CSC_DISABLE; + writel(temp_reg, vp_base + S5P_PP_CSC_EN); + + VPPRINTK("0x%08x\n\r", readl(vp_base + S5P_PP_CSC_EN)); +} + +enum s5p_tv_vp_err __s5p_vp_init_csc_coef_default(enum s5p_vp_csc_type csc_type) +{ + VPPRINTK("%d\n\r", csc_type); + + switch (csc_type) { + + case VPROC_CSC_SD_HD: + writel(Y2Y_COEF_601_TO_709, vp_base + S5P_PP_CSC_Y2Y_COEF); + writel(CB2Y_COEF_601_TO_709, vp_base + S5P_PP_CSC_CB2Y_COEF); + writel(CR2Y_COEF_601_TO_709, vp_base + S5P_PP_CSC_CR2Y_COEF); + writel(Y2CB_COEF_601_TO_709, vp_base + S5P_PP_CSC_Y2CB_COEF); + writel(CB2CB_COEF_601_TO_709, vp_base + S5P_PP_CSC_CB2CB_COEF); + writel(CR2CB_COEF_601_TO_709, vp_base + S5P_PP_CSC_CR2CB_COEF); + writel(Y2CR_COEF_601_TO_709, vp_base + S5P_PP_CSC_Y2CR_COEF); + writel(CB2CR_COEF_601_TO_709, vp_base + S5P_PP_CSC_CB2CR_COEF); + writel(CR2CR_COEF_601_TO_709, vp_base + S5P_PP_CSC_CR2CR_COEF); + break; + + case VPROC_CSC_HD_SD: + writel(Y2Y_COEF_709_TO_601, vp_base + S5P_PP_CSC_Y2Y_COEF); + writel(CB2Y_COEF_709_TO_601, vp_base + S5P_PP_CSC_CB2Y_COEF); + writel(CR2Y_COEF_709_TO_601, vp_base + S5P_PP_CSC_CR2Y_COEF); + writel(Y2CB_COEF_709_TO_601, vp_base + S5P_PP_CSC_Y2CB_COEF); + writel(CB2CB_COEF_709_TO_601, vp_base + S5P_PP_CSC_CB2CB_COEF); + writel(CR2CB_COEF_709_TO_601, vp_base + S5P_PP_CSC_CR2CB_COEF); + writel(Y2CR_COEF_709_TO_601, vp_base + S5P_PP_CSC_Y2CR_COEF); + writel(CB2CR_COEF_709_TO_601, vp_base + S5P_PP_CSC_CB2CR_COEF); + writel(CR2CR_COEF_709_TO_601, vp_base + S5P_PP_CSC_CR2CR_COEF); + break; + + default: + VPPRINTK("invalid csc_type parameter = %d\n\r", csc_type); + return S5P_TV_VP_ERR_INVALID_PARAM; + break; + } + + VPPRINTK("0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x,\ + 0x%08x, 0x%08x)\n\r", + readl(vp_base + S5P_PP_CSC_Y2Y_COEF), + readl(vp_base + S5P_PP_CSC_CB2Y_COEF), + readl(vp_base + S5P_PP_CSC_CR2Y_COEF), + readl(vp_base + S5P_PP_CSC_Y2CB_COEF), + readl(vp_base + S5P_PP_CSC_CB2CB_COEF), + readl(vp_base + S5P_PP_CSC_CR2CB_COEF), + readl(vp_base + S5P_PP_CSC_Y2CR_COEF), + readl(vp_base + S5P_PP_CSC_CB2CR_COEF), + readl(vp_base + S5P_PP_CSC_CR2CR_COEF)); + + return VPROC_NO_ERROR; +} + +/* +* start - start functions are only called under stopping video processor +*/ +enum s5p_tv_vp_err __s5p_vp_start(void) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + VPPRINTK("()\n\r"); + + writel(VP_ON_ENABLE, vp_base + S5P_VP_ENABLE); + + error = __s5p_vp_update(); + + VPPRINTK("()\n\r"); + return error; +} + +/* +* stop - stop functions are only called under running video processor +*/ +enum s5p_tv_vp_err __s5p_vp_stop(void) +{ + enum s5p_tv_vp_err error = VPROC_NO_ERROR; + + VPPRINTK("()\n\r"); + + writel((readl(vp_base + S5P_VP_ENABLE) & ~VP_ON_ENABLE), + vp_base + S5P_VP_ENABLE); + + error = __s5p_vp_update(); + + while (!(readl(vp_base + S5P_VP_ENABLE) & VP_POWER_DOWN_RDY)) + msleep(1); + + + return error; +} + +/* +* reset - reset function +*/ +void __s5p_vp_sw_reset(void) +{ + VPPRINTK("()\n\r"); + + writel((readl(vp_base + S5P_VP_SRESET) | VP_SOFT_RESET), + vp_base + S5P_VP_SRESET); + + while (readl(vp_base + S5P_VP_SRESET) & VP_SOFT_RESET) + msleep(10); + + + VPPRINTK("()\n\r"); +} + +int __init __s5p_vp_probe(struct platform_device *pdev, u32 res_num) +{ + struct resource *res; + size_t size; + + res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); + + if (res == NULL) { + dev_err(&pdev->dev, + "failed to get memory region resource\n"); + goto error; + + } + + size = (res->end - res->start) + 1; + + vp_mem = request_mem_region(res->start, size, pdev->name); + + if (vp_mem == NULL) { + dev_err(&pdev->dev, + "failed to get memory region\n"); + goto error; + + } + + vp_base = ioremap(res->start, size); + + if (vp_base == NULL) { + dev_err(&pdev->dev, + "failed to ioremap address region\n"); + goto error; + + + } + + return 0; +error: + return -ENOENT; + +} + +int __init __s5p_vp_release(struct platform_device *pdev) +{ + iounmap(vp_base); + + /* remove memory region */ + if (vp_mem != NULL) { + if (release_resource(vp_mem)) + dev_err(&pdev->dev, + "Can't remove tvout drv !!\n"); + + kfree(vp_mem); + + vp_mem = NULL; + } + + return 0; +} + |