diff options
Diffstat (limited to 'drivers/media/video')
96 files changed, 70258 insertions, 1 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index bb53de7..515f638 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1031,6 +1031,48 @@ config USB_S2255 This driver can be compiled as a module, called s2255drv. 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 + ---help--- + This driver supports S5KA3DFX SoC camera module + +config VIDEO_S5K4ECGX + tristate "S5K4ECGX Camera Sensor" + depends on I2C && VIDEO_V4L2 + ---help--- + This driver supports S5K4ECGX SoC camera module + +config VIDEO_S5K4ECGX_DEBUG + bool "S5K4ECGX Camera Sensor Debugging" + depends on VIDEO_S5K4ECGX + default n + ---help--- + Enable extra debug messages for S5K4ECGX camera driver + +config VIDEO_S5K4ECGX_V_1_0 + bool "S5K4ECGX Camera Sensor Version 1.0 Support" + depends on VIDEO_S5K4ECGX + default y + ---help--- + Enabled support for Rev 1.0 sensor + +config VIDEO_S5K4ECGX_V_1_1 + bool "S5K4ECGX Camera Sensor Version 1.1 Support" + depends on VIDEO_S5K4ECGX + default y + ---help--- + Enabled support for Rev 1.1 sensor + +source "drivers/media/video/samsung/Kconfig" + endif # VIDEO_CAPTURE_DRIVERS menuconfig V4L_MEM2MEM_DRIVERS diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index f0fecd6..bea5bbb 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -84,7 +84,9 @@ 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: obj-$(CONFIG_VIDEO_BT848) += bt8xx/ @@ -174,6 +176,7 @@ obj-$(CONFIG_ARCH_DAVINCI) += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o obj-$(CONFIG_VIDEO_AU0828) += au0828/ +obj-$(CONFIG_VIDEO_SAMSUNG) += samsung/ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ diff --git a/drivers/media/video/ce147.c b/drivers/media/video/ce147.c new file mode 100755 index 0000000..a3e2b1e --- /dev/null +++ b/drivers/media/video/ce147.c @@ -0,0 +1,5640 @@ +/* + * 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) + 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; + + case FLASH_MODE_TORCH: + ce147_buf_set_flash_manual[1] = 0x01; + break; + + 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 || 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; + } + 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_flash[2] = { 0x03, 0x00 }; + unsigned int ce147_len_set_flash = 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; + + 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) +{ + int err; + struct ce147_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(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; + + case V4L2_CID_CAMERA_FINISH_AUTO_FOCUS: +#if defined(CONFIG_SAMSUNG_FASCINATE) + state->disable_aeawb_lock = ctrl->value; +#endif + 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/s5k4ecgx.c b/drivers/media/video/s5k4ecgx.c new file mode 100755 index 0000000..9d9d5b4 --- /dev/null +++ b/drivers/media/video/s5k4ecgx.c @@ -0,0 +1,2837 @@ +/* drivers/media/video/s5k4ecgx.c + * + * Driver for s5k4ecgx (5MP Camera) from SEC + * + * Copyright (C) 2010, SAMSUNG ELECTRONICS + * + * 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/version.h> +#include <linux/vmalloc.h> +#include <linux/completion.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/s5k4ecgx.h> +#include <linux/videodev2_samsung.h> + +#ifdef CONFIG_VIDEO_S5K4ECGX_V_1_0 +#include "s5k4ecgx_regs_1_0.h" +#define S5K4ECGX_VERSION_1_0 0x00 +#endif + +#ifdef CONFIG_VIDEO_S5K4ECGX_V_1_1 +#include "s5k4ecgx_regs_1_1.h" +#define S5K4ECGX_VERSION_1_1 0x11 +#endif + +#define FORMAT_FLAGS_COMPRESSED 0x3 +#define SENSOR_JPEG_SNAPSHOT_MEMSIZE 0x410580 + +#define DEFAULT_PIX_FMT V4L2_PIX_FMT_UYVY /* YUV422 */ +#define DEFAULT_MCLK 24000000 +#define POLL_TIME_MS 10 +#define CAPTURE_POLL_TIME_MS 1000 + +/* maximum time for one frame at minimum fps (15fps) in normal mode */ +#define NORMAL_MODE_MAX_ONE_FRAME_DELAY_MS 67 +/* maximum time for one frame at minimum fps (4fps) in night mode */ +#define NIGHT_MODE_MAX_ONE_FRAME_DELAY_MS 250 + +/* time to move lens to target position before last af mode register write */ +#define LENS_MOVE_TIME_MS 100 + +/* level at or below which we need to enable flash when in auto mode */ +#define LOW_LIGHT_LEVEL 0x1D + +/* level at or below which we need to use low light capture mode */ +#define HIGH_LIGHT_LEVEL 0x80 + +#define FIRST_AF_SEARCH_COUNT 80 +#define SECOND_AF_SEARCH_COUNT 80 +#define AE_STABLE_SEARCH_COUNT 4 + +#define FIRST_SETTING_FOCUS_MODE_DELAY_MS 100 +#define SECOND_SETTING_FOCUS_MODE_DELAY_MS 200 + +#ifdef CONFIG_VIDEO_S5K4ECGX_DEBUG +enum { + S5K4ECGX_DEBUG_I2C = 1U << 0, + S5K4ECGX_DEBUG_I2C_BURSTS = 1U << 1, +}; +static uint32_t s5k4ecgx_debug_mask = S5K4ECGX_DEBUG_I2C_BURSTS; +module_param_named(debug_mask, s5k4ecgx_debug_mask, uint, S_IWUSR | S_IRUGO); + +#define s5k4ecgx_debug(mask, x...) \ + do { \ + if (s5k4ecgx_debug_mask & mask) \ + pr_info(x); \ + } while (0) +#else + +#define s5k4ecgx_debug(mask, x...) + +#endif + +#define S5K4ECGX_VERSION_1_1 0x11 + +/* result values returned to HAL */ +enum { + AUTO_FOCUS_FAILED, + AUTO_FOCUS_DONE, + AUTO_FOCUS_CANCELLED, +}; + +enum af_operation_status { + AF_NONE = 0, + AF_START, + AF_CANCEL, + AF_INITIAL, +}; + +enum s5k4ecgx_oprmode { + S5K4ECGX_OPRMODE_VIDEO = 0, + S5K4ECGX_OPRMODE_IMAGE = 1, +}; + +enum s5k4ecgx_preview_frame_size { + S5K4ECGX_PREVIEW_QCIF = 0, /* 176x144 */ + S5K4ECGX_PREVIEW_CIF, /* 352x288 */ + S5K4ECGX_PREVIEW_VGA, /* 640x480 */ + S5K4ECGX_PREVIEW_D1, /* 720x480 */ + S5K4ECGX_PREVIEW_WVGA, /* 800x480 */ + S5K4ECGX_PREVIEW_SVGA, /* 800x600 */ + S5K4ECGX_PREVIEW_WSVGA, /* 1024x600*/ + S5K4ECGX_PREVIEW_MAX, +}; + +enum s5k4ecgx_capture_frame_size { + S5K4ECGX_CAPTURE_VGA = 0, /* 640x480 */ + S5K4ECGX_CAPTURE_WVGA, /* 800x480 */ + S5K4ECGX_CAPTURE_SVGA, /* 800x600 */ + S5K4ECGX_CAPTURE_WSVGA, /* 1024x600 */ + S5K4ECGX_CAPTURE_1MP, /* 1280x960 */ + S5K4ECGX_CAPTURE_W1MP, /* 1600x960 */ + S5K4ECGX_CAPTURE_2MP, /* UXGA - 1600x1200 */ + S5K4ECGX_CAPTURE_W2MP, /* 35mm Academy Offset Standard 1.66 */ + /* 2048x1232, 2.4MP */ + S5K4ECGX_CAPTURE_3MP, /* QXGA - 2048x1536 */ + S5K4ECGX_CAPTURE_W4MP, /* WQXGA - 2560x1536 */ + S5K4ECGX_CAPTURE_5MP, /* 2560x1920 */ + S5K4ECGX_CAPTURE_MAX, +}; + +struct s5k4ecgx_framesize { + u32 index; + u32 width; + u32 height; +}; + +static const struct s5k4ecgx_framesize s5k4ecgx_preview_framesize_list[] = { + { S5K4ECGX_PREVIEW_QCIF, 176, 144 }, + { S5K4ECGX_PREVIEW_CIF, 352, 288 }, + { S5K4ECGX_PREVIEW_VGA, 640, 480 }, + { S5K4ECGX_PREVIEW_D1, 720, 480 }, +}; + +static const struct s5k4ecgx_framesize s5k4ecgx_capture_framesize_list[] = { + { S5K4ECGX_CAPTURE_VGA, 640, 480 }, + { S5K4ECGX_CAPTURE_1MP, 1280, 960 }, + { S5K4ECGX_CAPTURE_2MP, 1600, 1200 }, + { S5K4ECGX_CAPTURE_3MP, 2048, 1536 }, + { S5K4ECGX_CAPTURE_5MP, 2560, 1920 }, +}; + +struct s5k4ecgx_version { + u32 major; + u32 minor; +}; + +struct s5k4ecgx_date_info { + u32 year; + u32 month; + u32 date; +}; + +enum s5k4ecgx_runmode { + S5K4ECGX_RUNMODE_NOTREADY, + S5K4ECGX_RUNMODE_IDLE, + S5K4ECGX_RUNMODE_RUNNING, + S5K4ECGX_RUNMODE_CAPTURE, +}; + +struct s5k4ecgx_firmware { + u32 addr; + u32 size; +}; + +struct s5k4ecgx_jpeg_param { + u32 enable; + u32 quality; + u32 main_size; /* Main JPEG file size */ + u32 thumb_size; /* Thumbnail file size */ + u32 main_offset; + u32 thumb_offset; + u32 postview_offset; +}; + +struct s5k4ecgx_position { + int x; + int y; +}; + +struct gps_info_common { + u32 direction; + u32 dgree; + u32 minute; + u32 second; +}; + +struct s5k4ecgx_gps_info { + unsigned char gps_buf[8]; + unsigned char altitude_buf[4]; + int gps_timeStamp; +}; + +struct s5k4ecgx_regset { + u32 size; + u8 *data; +}; + +struct s5k4ecgx_regset_table { + const u32 *reg; + int array_size; +}; + +#define S5K4ECGX_REGSET(x, y) \ + [(x)] = { \ + .reg = (y), \ + .array_size = ARRAY_SIZE((y)), \ +} + +#define S5K4ECGX_REGSET_TABLE(y) \ + { \ + .reg = (y), \ + .array_size = ARRAY_SIZE((y)), \ +} + +struct s5k4ecgx_regs { + struct s5k4ecgx_regset_table ev[EV_MAX]; + struct s5k4ecgx_regset_table metering[METERING_MAX]; + struct s5k4ecgx_regset_table iso[ISO_MAX]; + struct s5k4ecgx_regset_table effect[IMAGE_EFFECT_MAX]; + struct s5k4ecgx_regset_table white_balance[WHITE_BALANCE_MAX]; + struct s5k4ecgx_regset_table preview_size[S5K4ECGX_PREVIEW_MAX]; + struct s5k4ecgx_regset_table capture_size[S5K4ECGX_CAPTURE_MAX]; + struct s5k4ecgx_regset_table scene_mode[SCENE_MODE_MAX]; + struct s5k4ecgx_regset_table saturation[SATURATION_MAX]; + struct s5k4ecgx_regset_table contrast[CONTRAST_MAX]; + struct s5k4ecgx_regset_table sharpness[SHARPNESS_MAX]; + struct s5k4ecgx_regset_table fps[FRAME_RATE_MAX]; + struct s5k4ecgx_regset_table preview_return; + struct s5k4ecgx_regset_table jpeg_quality_high; + struct s5k4ecgx_regset_table jpeg_quality_normal; + struct s5k4ecgx_regset_table jpeg_quality_low; + struct s5k4ecgx_regset_table flash_start; + struct s5k4ecgx_regset_table flash_end; + struct s5k4ecgx_regset_table af_assist_flash_start; + struct s5k4ecgx_regset_table af_assist_flash_end; + struct s5k4ecgx_regset_table af_low_light_mode_on; + struct s5k4ecgx_regset_table af_low_light_mode_off; + struct s5k4ecgx_regset_table ae_awb_lock_on; + struct s5k4ecgx_regset_table ae_awb_lock_off; + struct s5k4ecgx_regset_table low_cap_on; + struct s5k4ecgx_regset_table low_cap_off; + struct s5k4ecgx_regset_table wdr_on; + struct s5k4ecgx_regset_table wdr_off; + struct s5k4ecgx_regset_table face_detection_on; + struct s5k4ecgx_regset_table face_detection_off; + struct s5k4ecgx_regset_table capture_start; + struct s5k4ecgx_regset_table af_macro_mode_1; + struct s5k4ecgx_regset_table af_macro_mode_2; + struct s5k4ecgx_regset_table af_macro_mode_3; + struct s5k4ecgx_regset_table af_normal_mode_1; + struct s5k4ecgx_regset_table af_normal_mode_2; + struct s5k4ecgx_regset_table af_normal_mode_3; + struct s5k4ecgx_regset_table af_return_macro_position; + struct s5k4ecgx_regset_table single_af_start; + struct s5k4ecgx_regset_table single_af_off_1; + struct s5k4ecgx_regset_table single_af_off_2; + struct s5k4ecgx_regset_table dtp_start; + struct s5k4ecgx_regset_table dtp_stop; + struct s5k4ecgx_regset_table init_reg_1; + struct s5k4ecgx_regset_table init_reg_2; + struct s5k4ecgx_regset_table flash_init; + struct s5k4ecgx_regset_table reset_crop; + struct s5k4ecgx_regset_table get_ae_stable_status; + struct s5k4ecgx_regset_table get_light_level; + struct s5k4ecgx_regset_table get_1st_af_search_status; + struct s5k4ecgx_regset_table get_2nd_af_search_status; + struct s5k4ecgx_regset_table get_capture_status; + struct s5k4ecgx_regset_table get_esd_status; + struct s5k4ecgx_regset_table get_iso; + struct s5k4ecgx_regset_table get_shutterspeed; +}; + +#ifdef CONFIG_VIDEO_S5K4ECGX_V_1_0 +static const struct s5k4ecgx_regs regs_for_fw_version_1_0 = { + .ev = { + S5K4ECGX_REGSET(EV_MINUS_4, s5k4ecgx_EV_Minus_4_v1), + S5K4ECGX_REGSET(EV_MINUS_3, s5k4ecgx_EV_Minus_3_v1), + S5K4ECGX_REGSET(EV_MINUS_2, s5k4ecgx_EV_Minus_2_v1), + S5K4ECGX_REGSET(EV_MINUS_1, s5k4ecgx_EV_Minus_1_v1), + S5K4ECGX_REGSET(EV_DEFAULT, s5k4ecgx_EV_Default_v1), + S5K4ECGX_REGSET(EV_PLUS_1, s5k4ecgx_EV_Plus_1_v1), + S5K4ECGX_REGSET(EV_PLUS_2, s5k4ecgx_EV_Plus_2_v1), + S5K4ECGX_REGSET(EV_PLUS_3, s5k4ecgx_EV_Plus_3_v1), + S5K4ECGX_REGSET(EV_PLUS_4, s5k4ecgx_EV_Plus_4_v1), + }, + .metering = { + S5K4ECGX_REGSET(METERING_MATRIX, s5k4ecgx_Metering_Matrix_v1), + S5K4ECGX_REGSET(METERING_CENTER, s5k4ecgx_Metering_Center_v1), + S5K4ECGX_REGSET(METERING_SPOT, s5k4ecgx_Metering_Spot_v1), + }, + .iso = { + S5K4ECGX_REGSET(ISO_AUTO, s5k4ecgx_ISO_Auto_v1), + S5K4ECGX_REGSET(ISO_50, s5k4ecgx_ISO_100_v1), /* use 100 */ + S5K4ECGX_REGSET(ISO_100, s5k4ecgx_ISO_100_v1), + S5K4ECGX_REGSET(ISO_200, s5k4ecgx_ISO_200_v1), + S5K4ECGX_REGSET(ISO_400, s5k4ecgx_ISO_400_v1), + S5K4ECGX_REGSET(ISO_800, s5k4ecgx_ISO_400_v1), /* use 400 */ + S5K4ECGX_REGSET(ISO_1600, s5k4ecgx_ISO_400_v1), /* use 400 */ + S5K4ECGX_REGSET(ISO_SPORTS, s5k4ecgx_ISO_Auto_v1),/* use auto */ + S5K4ECGX_REGSET(ISO_NIGHT, s5k4ecgx_ISO_Auto_v1), /* use auto */ + S5K4ECGX_REGSET(ISO_MOVIE, s5k4ecgx_ISO_Auto_v1), /* use auto */ + }, + .effect = { + S5K4ECGX_REGSET(IMAGE_EFFECT_NONE, s5k4ecgx_Effect_Normal_v1), + S5K4ECGX_REGSET(IMAGE_EFFECT_BNW, + s5k4ecgx_Effect_Black_White_v1), + S5K4ECGX_REGSET(IMAGE_EFFECT_SEPIA, s5k4ecgx_Effect_Sepia_v1), + S5K4ECGX_REGSET(IMAGE_EFFECT_NEGATIVE, + s5k4ecgx_Effect_Negative_v1), + }, + .white_balance = { + S5K4ECGX_REGSET(WHITE_BALANCE_AUTO, s5k4ecgx_WB_Auto_v1), + S5K4ECGX_REGSET(WHITE_BALANCE_SUNNY, s5k4ecgx_WB_Sunny_v1), + S5K4ECGX_REGSET(WHITE_BALANCE_CLOUDY, s5k4ecgx_WB_Cloudy_v1), + S5K4ECGX_REGSET(WHITE_BALANCE_TUNGSTEN, + s5k4ecgx_WB_Tungsten_v1), + S5K4ECGX_REGSET(WHITE_BALANCE_FLUORESCENT, + s5k4ecgx_WB_Fluorescent_v1), + }, + .preview_size = { + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_QCIF, s5k4ecgx_176_Preview_v1), + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_CIF, s5k4ecgx_352_Preview_v1), + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_VGA, s5k4ecgx_640_Preview_v1), + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_D1, s5k4ecgx_720_Preview_v1), + }, + .capture_size = { + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_VGA, s5k4ecgx_VGA_Capture_v1), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_1MP, s5k4ecgx_1M_Capture_v1), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_2MP, s5k4ecgx_2M_Capture_v1), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_3MP, s5k4ecgx_3M_Capture_v1), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_5MP, s5k4ecgx_5M_Capture_v1), + }, + .scene_mode = { + S5K4ECGX_REGSET(SCENE_MODE_NONE, s5k4ecgx_Scene_Default_v1), + S5K4ECGX_REGSET(SCENE_MODE_PORTRAIT, + s5k4ecgx_Scene_Portrait_v1), + S5K4ECGX_REGSET(SCENE_MODE_NIGHTSHOT, + s5k4ecgx_Scene_Nightshot_v1), + S5K4ECGX_REGSET(SCENE_MODE_LANDSCAPE, + s5k4ecgx_Scene_Landscape_v1), + S5K4ECGX_REGSET(SCENE_MODE_SPORTS, s5k4ecgx_Scene_Sports_v1), + S5K4ECGX_REGSET(SCENE_MODE_PARTY_INDOOR, + s5k4ecgx_Scene_Party_Indoor_v1), + S5K4ECGX_REGSET(SCENE_MODE_BEACH_SNOW, + s5k4ecgx_Scene_Beach_Snow_v1), + S5K4ECGX_REGSET(SCENE_MODE_SUNSET, s5k4ecgx_Scene_Sunset_v1), + S5K4ECGX_REGSET(SCENE_MODE_FIREWORKS, + s5k4ecgx_Scene_Fireworks_v1), + S5K4ECGX_REGSET(SCENE_MODE_CANDLE_LIGHT, + s5k4ecgx_Scene_Candle_Light_v1), + }, + .saturation = { + S5K4ECGX_REGSET(SATURATION_MINUS_2, + s5k4ecgx_Saturation_Minus_2_v1), + S5K4ECGX_REGSET(SATURATION_MINUS_1, + s5k4ecgx_Saturation_Minus_1_v1), + S5K4ECGX_REGSET(SATURATION_DEFAULT, + s5k4ecgx_Saturation_Default_v1), + S5K4ECGX_REGSET(SATURATION_PLUS_1, + s5k4ecgx_Saturation_Plus_1_v1), + S5K4ECGX_REGSET(SATURATION_PLUS_2, + s5k4ecgx_Saturation_Plus_2_v1), + }, + .contrast = { + S5K4ECGX_REGSET(CONTRAST_MINUS_2, s5k4ecgx_Contrast_Minus_2_v1), + S5K4ECGX_REGSET(CONTRAST_MINUS_1, s5k4ecgx_Contrast_Minus_1_v1), + S5K4ECGX_REGSET(CONTRAST_DEFAULT, s5k4ecgx_Contrast_Default_v1), + S5K4ECGX_REGSET(CONTRAST_PLUS_1, s5k4ecgx_Contrast_Plus_1_v1), + S5K4ECGX_REGSET(CONTRAST_PLUS_2, s5k4ecgx_Contrast_Plus_2_v1), + }, + .sharpness = { + S5K4ECGX_REGSET(SHARPNESS_MINUS_2, + s5k4ecgx_Sharpness_Minus_2_v1), + S5K4ECGX_REGSET(SHARPNESS_MINUS_1, + s5k4ecgx_Sharpness_Minus_1_v1), + S5K4ECGX_REGSET(SHARPNESS_DEFAULT, + s5k4ecgx_Sharpness_Default_v1), + S5K4ECGX_REGSET(SHARPNESS_PLUS_1, s5k4ecgx_Sharpness_Plus_1_v1), + S5K4ECGX_REGSET(SHARPNESS_PLUS_2, s5k4ecgx_Sharpness_Plus_2_v1), + }, + .preview_return = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Preview_Return_v1), + .jpeg_quality_high = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Jpeg_Quality_High_v1), + .jpeg_quality_normal = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Jpeg_Quality_Normal_v1), + .jpeg_quality_low = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Jpeg_Quality_Low_v1), + .flash_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Flash_Start_v1), + .flash_end = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Flash_End_v1), + .af_assist_flash_start = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Pre_Flash_Start_v1), + .af_assist_flash_end = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Pre_Flash_End_v1), + .af_low_light_mode_on = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Low_Light_Mode_On_v1), + .af_low_light_mode_off = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Low_Light_Mode_Off_v1), + .ae_awb_lock_on = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AE_AWB_Lock_On_v1), + .ae_awb_lock_off = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AE_AWB_Lock_Off_v1), + .low_cap_on = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Low_Cap_On_v1), + .low_cap_off = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Low_Cap_Off_v1), + .wdr_on = S5K4ECGX_REGSET_TABLE(s5k4ecgx_WDR_on_v1), + .wdr_off = S5K4ECGX_REGSET_TABLE(s5k4ecgx_WDR_off_v1), + .face_detection_on = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Face_Detection_On_v1), + .face_detection_off = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Face_Detection_Off_v1), + .capture_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Capture_Start_v1), + .af_macro_mode_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Macro_mode_1_v1), + .af_macro_mode_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Macro_mode_2_v1), + .af_macro_mode_3 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Macro_mode_3_v1), + .af_normal_mode_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Normal_mode_1_v1), + .af_normal_mode_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Normal_mode_2_v1), + .af_normal_mode_3 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Normal_mode_3_v1), + .af_return_macro_position = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Return_Macro_pos_v1), + .single_af_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Single_AF_Start_v1), + .single_af_off_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Single_AF_Off_1_v1), + .single_af_off_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Single_AF_Off_2_v1), + .dtp_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_DTP_init_v1), + .dtp_stop = S5K4ECGX_REGSET_TABLE(s5k4ecgx_DTP_stop_v1), + .init_reg_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_init_reg1_v1), + .init_reg_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_init_reg2_v1), + .flash_init = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Flash_init_v1), + .reset_crop = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Reset_Crop_v1), + .get_ae_stable_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Get_AE_Stable_Status_v1), + .get_light_level = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Get_Light_Level_v1), + .get_1st_af_search_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_1st_af_search_status_v1), + .get_2nd_af_search_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_2nd_af_search_status_v1), + .get_capture_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_capture_status_v1), + .get_esd_status = S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_esd_status_v1), + .get_iso = S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_iso_reg_v1), + .get_shutterspeed = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_shutterspeed_reg_v1), +}; +#endif + +#ifdef CONFIG_VIDEO_S5K4ECGX_V_1_1 +static const struct s5k4ecgx_regs regs_for_fw_version_1_1 = { + .ev = { + S5K4ECGX_REGSET(EV_MINUS_4, s5k4ecgx_EV_Minus_4), + S5K4ECGX_REGSET(EV_MINUS_3, s5k4ecgx_EV_Minus_3), + S5K4ECGX_REGSET(EV_MINUS_2, s5k4ecgx_EV_Minus_2), + S5K4ECGX_REGSET(EV_MINUS_1, s5k4ecgx_EV_Minus_1), + S5K4ECGX_REGSET(EV_DEFAULT, s5k4ecgx_EV_Default), + S5K4ECGX_REGSET(EV_PLUS_1, s5k4ecgx_EV_Plus_1), + S5K4ECGX_REGSET(EV_PLUS_2, s5k4ecgx_EV_Plus_2), + S5K4ECGX_REGSET(EV_PLUS_3, s5k4ecgx_EV_Plus_3), + S5K4ECGX_REGSET(EV_PLUS_4, s5k4ecgx_EV_Plus_4), + }, + .metering = { + S5K4ECGX_REGSET(METERING_MATRIX, s5k4ecgx_Metering_Matrix), + S5K4ECGX_REGSET(METERING_CENTER, s5k4ecgx_Metering_Center), + S5K4ECGX_REGSET(METERING_SPOT, s5k4ecgx_Metering_Spot), + }, + .iso = { + S5K4ECGX_REGSET(ISO_AUTO, s5k4ecgx_ISO_Auto), + S5K4ECGX_REGSET(ISO_50, s5k4ecgx_ISO_100), /* map to 100 */ + S5K4ECGX_REGSET(ISO_100, s5k4ecgx_ISO_100), + S5K4ECGX_REGSET(ISO_200, s5k4ecgx_ISO_200), + S5K4ECGX_REGSET(ISO_400, s5k4ecgx_ISO_400), + S5K4ECGX_REGSET(ISO_800, s5k4ecgx_ISO_400), /* map to 400 */ + S5K4ECGX_REGSET(ISO_1600, s5k4ecgx_ISO_400), /* map to 400 */ + S5K4ECGX_REGSET(ISO_SPORTS, s5k4ecgx_ISO_Auto),/* map to auto */ + S5K4ECGX_REGSET(ISO_NIGHT, s5k4ecgx_ISO_Auto), /* map to auto */ + S5K4ECGX_REGSET(ISO_MOVIE, s5k4ecgx_ISO_Auto), /* map to auto */ + }, + .effect = { + S5K4ECGX_REGSET(IMAGE_EFFECT_NONE, s5k4ecgx_Effect_Normal), + S5K4ECGX_REGSET(IMAGE_EFFECT_BNW, s5k4ecgx_Effect_Black_White), + S5K4ECGX_REGSET(IMAGE_EFFECT_SEPIA, s5k4ecgx_Effect_Sepia), + S5K4ECGX_REGSET(IMAGE_EFFECT_NEGATIVE, + s5k4ecgx_Effect_Negative), + }, + .white_balance = { + S5K4ECGX_REGSET(WHITE_BALANCE_AUTO, s5k4ecgx_WB_Auto), + S5K4ECGX_REGSET(WHITE_BALANCE_SUNNY, s5k4ecgx_WB_Sunny), + S5K4ECGX_REGSET(WHITE_BALANCE_CLOUDY, s5k4ecgx_WB_Cloudy), + S5K4ECGX_REGSET(WHITE_BALANCE_TUNGSTEN, s5k4ecgx_WB_Tungsten), + S5K4ECGX_REGSET(WHITE_BALANCE_FLUORESCENT, + s5k4ecgx_WB_Fluorescent), + }, + .preview_size = { + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_QCIF, s5k4ecgx_176_Preview), + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_CIF, s5k4ecgx_352_Preview), + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_VGA, s5k4ecgx_640_Preview), + S5K4ECGX_REGSET(S5K4ECGX_PREVIEW_D1, s5k4ecgx_720_Preview), + }, + .capture_size = { + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_VGA, s5k4ecgx_VGA_Capture), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_1MP, s5k4ecgx_1M_Capture), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_2MP, s5k4ecgx_2M_Capture), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_3MP, s5k4ecgx_3M_Capture), + S5K4ECGX_REGSET(S5K4ECGX_CAPTURE_5MP, s5k4ecgx_5M_Capture), + }, + .scene_mode = { + S5K4ECGX_REGSET(SCENE_MODE_NONE, s5k4ecgx_Scene_Default), + S5K4ECGX_REGSET(SCENE_MODE_PORTRAIT, s5k4ecgx_Scene_Portrait), + S5K4ECGX_REGSET(SCENE_MODE_NIGHTSHOT, s5k4ecgx_Scene_Nightshot), + S5K4ECGX_REGSET(SCENE_MODE_LANDSCAPE, s5k4ecgx_Scene_Landscape), + S5K4ECGX_REGSET(SCENE_MODE_SPORTS, s5k4ecgx_Scene_Sports), + S5K4ECGX_REGSET(SCENE_MODE_PARTY_INDOOR, + s5k4ecgx_Scene_Party_Indoor), + S5K4ECGX_REGSET(SCENE_MODE_BEACH_SNOW, + s5k4ecgx_Scene_Beach_Snow), + S5K4ECGX_REGSET(SCENE_MODE_SUNSET, s5k4ecgx_Scene_Sunset), + S5K4ECGX_REGSET(SCENE_MODE_FIREWORKS, s5k4ecgx_Scene_Fireworks), + S5K4ECGX_REGSET(SCENE_MODE_CANDLE_LIGHT, + s5k4ecgx_Scene_Candle_Light), + }, + .saturation = { + S5K4ECGX_REGSET(SATURATION_MINUS_2, + s5k4ecgx_Saturation_Minus_2), + S5K4ECGX_REGSET(SATURATION_MINUS_1, + s5k4ecgx_Saturation_Minus_1), + S5K4ECGX_REGSET(SATURATION_DEFAULT, + s5k4ecgx_Saturation_Default), + S5K4ECGX_REGSET(SATURATION_PLUS_1, s5k4ecgx_Saturation_Plus_1), + S5K4ECGX_REGSET(SATURATION_PLUS_2, s5k4ecgx_Saturation_Plus_2), + }, + .contrast = { + S5K4ECGX_REGSET(CONTRAST_MINUS_2, s5k4ecgx_Contrast_Minus_2), + S5K4ECGX_REGSET(CONTRAST_MINUS_1, s5k4ecgx_Contrast_Minus_1), + S5K4ECGX_REGSET(CONTRAST_DEFAULT, s5k4ecgx_Contrast_Default), + S5K4ECGX_REGSET(CONTRAST_PLUS_1, s5k4ecgx_Contrast_Plus_1), + S5K4ECGX_REGSET(CONTRAST_PLUS_2, s5k4ecgx_Contrast_Plus_2), + }, + .sharpness = { + S5K4ECGX_REGSET(SHARPNESS_MINUS_2, s5k4ecgx_Sharpness_Minus_2), + S5K4ECGX_REGSET(SHARPNESS_MINUS_1, s5k4ecgx_Sharpness_Minus_1), + S5K4ECGX_REGSET(SHARPNESS_DEFAULT, s5k4ecgx_Sharpness_Default), + S5K4ECGX_REGSET(SHARPNESS_PLUS_1, s5k4ecgx_Sharpness_Plus_1), + S5K4ECGX_REGSET(SHARPNESS_PLUS_2, s5k4ecgx_Sharpness_Plus_2), + }, + .fps = { + S5K4ECGX_REGSET(FRAME_RATE_AUTO, s5k4ecgx_FPS_Auto), + S5K4ECGX_REGSET(FRAME_RATE_7, s5k4ecgx_FPS_7), + S5K4ECGX_REGSET(FRAME_RATE_15, s5k4ecgx_FPS_15), + S5K4ECGX_REGSET(FRAME_RATE_30, s5k4ecgx_FPS_30), + }, + .preview_return = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Preview_Return), + .jpeg_quality_high = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Jpeg_Quality_High), + .jpeg_quality_normal = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Jpeg_Quality_Normal), + .jpeg_quality_low = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Jpeg_Quality_Low), + .flash_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Flash_Start), + .flash_end = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Flash_End), + .af_assist_flash_start = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Pre_Flash_Start), + .af_assist_flash_end = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Pre_Flash_End), + .af_low_light_mode_on = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Low_Light_Mode_On), + .af_low_light_mode_off = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Low_Light_Mode_Off), + .ae_awb_lock_on = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AE_AWB_Lock_On), + .ae_awb_lock_off = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AE_AWB_Lock_Off), + .low_cap_on = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Low_Cap_On), + .low_cap_off = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Low_Cap_Off), + .wdr_on = S5K4ECGX_REGSET_TABLE(s5k4ecgx_WDR_on), + .wdr_off = S5K4ECGX_REGSET_TABLE(s5k4ecgx_WDR_off), + .face_detection_on = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Face_Detection_On), + .face_detection_off = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Face_Detection_Off), + .capture_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Capture_Start), + .af_macro_mode_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Macro_mode_1), + .af_macro_mode_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Macro_mode_2), + .af_macro_mode_3 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Macro_mode_3), + .af_normal_mode_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Normal_mode_1), + .af_normal_mode_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Normal_mode_2), + .af_normal_mode_3 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Normal_mode_3), + .af_return_macro_position = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_AF_Return_Macro_pos), + .single_af_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Single_AF_Start), + .single_af_off_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Single_AF_Off_1), + .single_af_off_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Single_AF_Off_2), + .dtp_start = S5K4ECGX_REGSET_TABLE(s5k4ecgx_DTP_init), + .dtp_stop = S5K4ECGX_REGSET_TABLE(s5k4ecgx_DTP_stop), + .init_reg_1 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_init_reg1), + .init_reg_2 = S5K4ECGX_REGSET_TABLE(s5k4ecgx_init_reg2), + .flash_init = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Flash_init), + .reset_crop = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Reset_Crop), + .get_ae_stable_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_Get_AE_Stable_Status), + .get_light_level = S5K4ECGX_REGSET_TABLE(s5k4ecgx_Get_Light_Level), + .get_1st_af_search_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_1st_af_search_status), + .get_2nd_af_search_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_2nd_af_search_status), + .get_capture_status = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_capture_status), + .get_esd_status = S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_esd_status), + .get_iso = S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_iso_reg), + .get_shutterspeed = + S5K4ECGX_REGSET_TABLE(s5k4ecgx_get_shutterspeed_reg), +}; +#endif + +struct s5k4ecgx_state { + struct s5k4ecgx_platform_data *pdata; + struct v4l2_subdev sd; + struct v4l2_pix_format pix; + struct v4l2_fract timeperframe; + struct s5k4ecgx_jpeg_param jpeg; + struct s5k4ecgx_version fw; + struct s5k4ecgx_version prm; + struct s5k4ecgx_date_info dateinfo; + struct s5k4ecgx_position position; + struct v4l2_streamparm strm; + struct s5k4ecgx_gps_info gps_info; + struct mutex ctrl_lock; + enum s5k4ecgx_runmode runmode; + enum s5k4ecgx_oprmode oprmode; + enum af_operation_status af_status; + int preview_framesize_index; + int capture_framesize_index; + int sensor_version; + int freq; /* MCLK in Hz */ + int check_dataline; + int check_previewdata; + bool flash_on; + bool torch_on; + bool sensor_af_in_low_light_mode; + bool flash_state_on_previous_capture; + bool initialized; + bool restore_preview_size_needed; + int one_frame_delay_ms; + const struct s5k4ecgx_regs *regs; +}; + +static const struct v4l2_mbus_framefmt capture_fmts[] = { + { + .code = V4L2_MBUS_FMT_FIXED, + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; + +/** + * s5k4ecgx_i2c_read_twobyte: Read 2 bytes from sensor + */ +static int s5k4ecgx_i2c_read_twobyte(struct i2c_client *client, + u16 subaddr, u16 *data) +{ + int err; + unsigned char buf[2]; + struct i2c_msg msg[2]; + + cpu_to_be16s(&subaddr); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = (u8 *)&subaddr; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = buf; + + err = i2c_transfer(client->adapter, msg, 2); + if (unlikely(err != 2)) { + dev_err(&client->dev, + "%s: register read fail\n", __func__); + return -EIO; + } + + *data = ((buf[0] << 8) | buf[1]); + + return 0; +} + +/** + * s5k4ecgx_i2c_write_twobyte: 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 s5k4ecgx_i2c_write_twobyte(struct i2c_client *client, + u16 addr, u16 w_data) +{ + int retry_count = 5; + unsigned char buf[4]; + struct i2c_msg msg = {client->addr, 0, 4, buf}; + int ret = 0; + + buf[0] = addr >> 8; + buf[1] = addr; + buf[2] = w_data >> 8; + buf[3] = w_data & 0xff; + + s5k4ecgx_debug(S5K4ECGX_DEBUG_I2C, "%s : W(0x%02X%02X%02X%02X)\n", + __func__, buf[0], buf[1], buf[2], buf[3]); + + do { + ret = i2c_transfer(client->adapter, &msg, 1); + if (likely(ret == 1)) + break; + msleep(POLL_TIME_MS); + dev_err(&client->dev, "%s: I2C err %d, retry %d.\n", + __func__, ret, retry_count); + } while (retry_count-- > 0); + if (ret != 1) { + dev_err(&client->dev, "%s: I2C is not working.\n", __func__); + return -EIO; + } + + return 0; +} + +static int s5k4ecgx_write_regs(struct v4l2_subdev *sd, const u32 regs[], + int size) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int i, err; + + for (i = 0; i < size; i++) { + err = s5k4ecgx_i2c_write_twobyte(client, + (regs[i] >> 16), regs[i]); + if (unlikely(err != 0)) { + dev_err(&client->dev, + "%s: register write failed\n", __func__); + return err; + } + } + + return 0; +} + +static int s5k4ecgx_set_from_table(struct v4l2_subdev *sd, + const char *setting_name, + const struct s5k4ecgx_regset_table *table, + int table_size, int index) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + dev_dbg(&client->dev, "%s: set %s index %d\n", + __func__, setting_name, index); + if ((index < 0) || (index >= table_size)) { + dev_err(&client->dev, + "%s: index(%d) out of range[0:%d] for table for %s\n", + __func__, index, table_size, setting_name); + return -EINVAL; + } + table += index; + if (table->reg == NULL) + return -EINVAL; + return s5k4ecgx_write_regs(sd, table->reg, table->array_size); +} + +static int s5k4ecgx_set_parameter(struct v4l2_subdev *sd, + int *current_value_ptr, + int new_value, + const char *setting_name, + const struct s5k4ecgx_regset_table *table, + int table_size) +{ + int err; + + if (*current_value_ptr == new_value) + return 0; + + err = s5k4ecgx_set_from_table(sd, setting_name, table, + table_size, new_value); + + if (!err) + *current_value_ptr = new_value; + return err; +} + +static int s5k4ecgx_set_preview_stop(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + if (state->runmode == S5K4ECGX_RUNMODE_RUNNING) + state->runmode = S5K4ECGX_RUNMODE_IDLE; + + dev_dbg(&client->dev, "%s:\n", __func__); + + return 0; +} + +static int s5k4ecgx_set_preview_start(struct v4l2_subdev *sd) +{ + int err; + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + bool set_size = true; + + dev_dbg(&client->dev, "%s: runmode = %d\n", + __func__, state->runmode); + + if (!state->pix.width || !state->pix.height || + !state->strm.parm.capture.timeperframe.denominator) + return -EINVAL; + + if (state->runmode == S5K4ECGX_RUNMODE_CAPTURE) { + dev_dbg(&client->dev, "%s: sending Preview_Return cmd\n", + __func__); + err = s5k4ecgx_set_from_table(sd, "preview return", + &state->regs->preview_return, 1, 0); + if (err < 0) { + dev_err(&client->dev, + "%s: failed: s5k4ecgx_Preview_Return\n", + __func__); + return -EIO; + } + set_size = state->restore_preview_size_needed; + } + + if (set_size) { + err = s5k4ecgx_set_from_table(sd, "preview_size", + state->regs->preview_size, + ARRAY_SIZE(state->regs->preview_size), + state->preview_framesize_index); + if (err < 0) { + dev_err(&client->dev, + "%s: failed: Could not set preview size\n", + __func__); + return -EIO; + } + } + + dev_dbg(&client->dev, "%s: runmode now RUNNING\n", __func__); + state->runmode = S5K4ECGX_RUNMODE_RUNNING; + + return 0; +} + +static int s5k4ecgx_set_capture_size(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + int err; + + dev_dbg(&client->dev, "%s: index:%d\n", __func__, + state->capture_framesize_index); + + err = s5k4ecgx_set_from_table(sd, "capture_size", + state->regs->capture_size, + ARRAY_SIZE(state->regs->capture_size), + state->capture_framesize_index); + if (err < 0) { + dev_err(&client->dev, + "%s: failed: i2c_write for capture_size index %d\n", + __func__, state->capture_framesize_index); + } + state->runmode = S5K4ECGX_RUNMODE_CAPTURE; + + return err; +} + +static int s5k4ecgx_set_jpeg_quality(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + dev_dbg(&client->dev, + "%s: jpeg.quality %d\n", __func__, state->jpeg.quality); + if (state->jpeg.quality < 0) + state->jpeg.quality = 0; + if (state->jpeg.quality > 100) + state->jpeg.quality = 100; + + switch (state->jpeg.quality) { + case 90 ... 100: + dev_dbg(&client->dev, + "%s: setting to high jpeg quality\n", __func__); + return s5k4ecgx_set_from_table(sd, "jpeg quality high", + &state->regs->jpeg_quality_high, 1, 0); + case 80 ... 89: + dev_dbg(&client->dev, + "%s: setting to normal jpeg quality\n", __func__); + return s5k4ecgx_set_from_table(sd, "jpeg quality normal", + &state->regs->jpeg_quality_normal, 1, 0); + default: + dev_dbg(&client->dev, + "%s: setting to low jpeg quality\n", __func__); + return s5k4ecgx_set_from_table(sd, "jpeg quality low", + &state->regs->jpeg_quality_low, 1, 0); + } +} + +static u16 s5k4ecgx_get_light_level(struct v4l2_subdev *sd) +{ + int err; + u16 read_value = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + err = s5k4ecgx_set_from_table(sd, "get light level", + &state->regs->get_light_level, 1, 0); + if (err) { + dev_err(&client->dev, + "%s: write cmd failed, returning 0\n", __func__); + goto out; + } + err = s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + if (err) { + dev_err(&client->dev, + "%s: read cmd failed, returning 0\n", __func__); + goto out; + } + + dev_dbg(&client->dev, "%s: read_value = %d (0x%X)\n", + __func__, read_value, read_value); + +out: + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + return read_value; +} + +static int s5k4ecgx_start_capture(struct v4l2_subdev *sd) +{ + int err; + u16 read_value; + u16 light_level; + int poll_time_ms; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + struct s5k4ecgx_platform_data *pdata = client->dev.platform_data; + + /* reset cropping if our current preview is not 640x480, + * otherwise the capture will be wrong because of the cropping + */ + if (state->preview_framesize_index != S5K4ECGX_PREVIEW_VGA) { + int err = s5k4ecgx_set_from_table(sd, "reset crop", + &state->regs->reset_crop, 1, 0); + if (err < 0) { + dev_err(&client->dev, + "%s: failed: Could not set preview size\n", + __func__); + return -EIO; + } + state->restore_preview_size_needed = true; + } else + state->restore_preview_size_needed = false; + + msleep(50); + light_level = s5k4ecgx_get_light_level(sd); + + dev_dbg(&client->dev, "%s: light_level = %d\n", __func__, + light_level); + + state->flash_state_on_previous_capture = false; + if (parms->scene_mode != SCENE_MODE_NIGHTSHOT) { + switch (parms->flash_mode) { + case FLASH_MODE_AUTO: + if (light_level > LOW_LIGHT_LEVEL) { + /* light level bright enough + * that we don't need flash + */ + break; + } + /* fall through to flash start */ + case FLASH_MODE_ON: + if (parms->focus_mode == FOCUS_MODE_INFINITY) { + s5k4ecgx_set_from_table(sd, + "AF assist flash start", + &state->regs->af_assist_flash_start, + 1, 0); + s5k4ecgx_set_from_table(sd, + "AF assist flash end", + &state->regs->af_assist_flash_end, + 1, 0); + msleep(10); + } + s5k4ecgx_set_from_table(sd, "flash start", + &state->regs->flash_start, 1, 0); + state->flash_on = true; + state->flash_state_on_previous_capture = true; + pdata->flash_onoff(1); + break; + default: + break; + } + } + + /* if light is low, use low light capture settings, EXCEPT + * if scene mode set to NIGHTSHOT or SPORTS because they + * have their own settings (though a low light sport setting + * could be useful) + */ + if ((light_level <= HIGH_LIGHT_LEVEL) && + (parms->scene_mode != SCENE_MODE_NIGHTSHOT) && + (parms->scene_mode != SCENE_MODE_SPORTS)) { + s5k4ecgx_set_from_table(sd, "low cap on", + &state->regs->low_cap_on, 1, 0); + } + + err = s5k4ecgx_set_capture_size(sd); + if (err < 0) { + dev_err(&client->dev, + "%s: failed: i2c_write for capture_resolution\n", + __func__); + return -EIO; + } + + dev_dbg(&client->dev, "%s: send Capture_Start cmd\n", __func__); + s5k4ecgx_set_from_table(sd, "capture start", + &state->regs->capture_start, 1, 0); + + /* a shot takes takes at least 50ms so sleep that amount first + * and then start polling for completion. + */ + msleep(50); + /* Enter read mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x002C, 0x7000); + poll_time_ms = 50; + do { + s5k4ecgx_set_from_table(sd, "get capture status", + &state->regs->get_capture_status, 1, 0); + s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, + "%s: s5k4ecgx_Capture_Start check = %#x\n", + __func__, read_value); + if (read_value != 0x00) + break; + msleep(POLL_TIME_MS); + poll_time_ms += POLL_TIME_MS; + } while (poll_time_ms < CAPTURE_POLL_TIME_MS); + + dev_dbg(&client->dev, "%s: capture done check finished after %d ms\n", + __func__, poll_time_ms); + + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + s5k4ecgx_set_from_table(sd, "ae awb lock off", + &state->regs->ae_awb_lock_off, 1, 0); + + if ((light_level <= HIGH_LIGHT_LEVEL) && + (parms->scene_mode != SCENE_MODE_NIGHTSHOT) && + (parms->scene_mode != SCENE_MODE_SPORTS)) { + s5k4ecgx_set_from_table(sd, "low cap off", + &state->regs->low_cap_off, 1, 0); + } + + if ((parms->scene_mode != SCENE_MODE_NIGHTSHOT) && (state->flash_on)) { + state->flash_on = false; + pdata->flash_onoff(0); + s5k4ecgx_set_from_table(sd, "flash end", + &state->regs->flash_end, 1, 0); + } + + return 0; +} + +/* wide dynamic range support */ +static int s5k4ecgx_set_wdr(struct v4l2_subdev *sd, int value) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + if (value == WDR_ON) + return s5k4ecgx_set_from_table(sd, "wdr on", + &state->regs->wdr_on, 1, 0); + return s5k4ecgx_set_from_table(sd, "wdr off", + &state->regs->wdr_off, 1, 0); +} + +static int s5k4ecgx_set_face_detection(struct v4l2_subdev *sd, int value) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + if (value == FACE_DETECTION_ON) + return s5k4ecgx_set_from_table(sd, "face detection on", + &state->regs->face_detection_on, 1, 0); + return s5k4ecgx_set_from_table(sd, "face detection off", + &state->regs->face_detection_off, 1, 0); +} + +static int s5k4ecgx_return_focus(struct v4l2_subdev *sd) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + err = s5k4ecgx_set_from_table(sd, + "af normal mode 1", + &state->regs->af_normal_mode_1, 1, 0); + if (err < 0) + goto fail; + msleep(FIRST_SETTING_FOCUS_MODE_DELAY_MS); + err = s5k4ecgx_set_from_table(sd, + "af normal mode 2", + &state->regs->af_normal_mode_2, 1, 0); + if (err < 0) + goto fail; + msleep(SECOND_SETTING_FOCUS_MODE_DELAY_MS); + err = s5k4ecgx_set_from_table(sd, + "af normal mode 3", + &state->regs->af_normal_mode_3, 1, 0); + if (err < 0) + goto fail; + + return 0; +fail: + dev_err(&client->dev, + "%s: i2c_write failed\n", __func__); + return -EIO; +} + +static int s5k4ecgx_set_focus_mode(struct v4l2_subdev *sd, int value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + int err; + + if (parms->focus_mode == value) + return 0; + + dev_dbg(&client->dev, "%s value(%d)\n", __func__, value); + + switch (value) { + case FOCUS_MODE_MACRO: + dev_dbg(&client->dev, + "%s: FOCUS_MODE_MACRO\n", __func__); + err = s5k4ecgx_set_from_table(sd, "af macro mode 1", + &state->regs->af_macro_mode_1, 1, 0); + if (err < 0) + goto fail; + msleep(FIRST_SETTING_FOCUS_MODE_DELAY_MS); + err = s5k4ecgx_set_from_table(sd, "af macro mode 2", + &state->regs->af_macro_mode_2, 1, 0); + if (err < 0) + goto fail; + msleep(SECOND_SETTING_FOCUS_MODE_DELAY_MS); + err = s5k4ecgx_set_from_table(sd, "af macro mode 3", + &state->regs->af_macro_mode_3, 1, 0); + if (err < 0) + goto fail; + parms->focus_mode = FOCUS_MODE_MACRO; + break; + + case FOCUS_MODE_INFINITY: + case FOCUS_MODE_AUTO: + err = s5k4ecgx_set_from_table(sd, + "af normal mode 1", + &state->regs->af_normal_mode_1, 1, 0); + if (err < 0) + goto fail; + msleep(FIRST_SETTING_FOCUS_MODE_DELAY_MS); + err = s5k4ecgx_set_from_table(sd, + "af normal mode 2", + &state->regs->af_normal_mode_2, 1, 0); + if (err < 0) + goto fail; + msleep(SECOND_SETTING_FOCUS_MODE_DELAY_MS); + err = s5k4ecgx_set_from_table(sd, + "af normal mode 3", + &state->regs->af_normal_mode_3, 1, 0); + if (err < 0) + goto fail; + parms->focus_mode = value; + break; + default: + return -EINVAL; + break; + } + + return 0; +fail: + dev_err(&client->dev, + "%s: i2c_write failed\n", __func__); + return -EIO; +} + +static void s5k4ecgx_auto_focus_flash_start(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct s5k4ecgx_platform_data *pdata = client->dev.platform_data; + int count; + u16 read_value; + + s5k4ecgx_set_from_table(sd, "AF assist flash start", + &state->regs->af_assist_flash_start, 1, 0); + state->flash_on = true; + pdata->af_assist_onoff(1); + + /* delay 200ms (SLSI value) and then poll to see if AE is stable. + * once it is stable, lock it and then return to do AF + */ + msleep(200); + + /* enter read mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x002C, 0x7000); + for (count = 0; count < AE_STABLE_SEARCH_COUNT; count++) { + if (state->af_status == AF_CANCEL) + break; + s5k4ecgx_set_from_table(sd, "get ae stable status", + &state->regs->get_ae_stable_status, 1, 0); + s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, "%s: ae stable status = %#x\n", + __func__, read_value); + if (read_value == 0x1) + break; + msleep(state->one_frame_delay_ms); + } + + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + /* if we were cancelled, turn off flash */ + if (state->af_status == AF_CANCEL) { + dev_dbg(&client->dev, + "%s: AF cancelled\n", __func__); + s5k4ecgx_set_from_table(sd, "AF assist flash end", + &state->regs->af_assist_flash_end, 1, 0); + state->flash_on = false; + pdata->af_assist_onoff(0); + } +} + +static int s5k4ecgx_start_auto_focus(struct v4l2_subdev *sd) +{ + int light_level; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + + dev_dbg(&client->dev, "%s: start SINGLE AF operation, flash mode %d\n", + __func__, parms->flash_mode); + + /* in case user calls auto_focus repeatedly without a cancel + * or a capture, we need to cancel here to allow ae_awb + * to work again, or else we could be locked forever while + * that app is running, which is not the expected behavior. + */ + s5k4ecgx_set_from_table(sd, "ae awb lock off", + &state->regs->ae_awb_lock_off, 1, 0); + + if (parms->scene_mode == SCENE_MODE_NIGHTSHOT) { + /* user selected night shot mode, assume we need low light + * af mode. flash is always off in night shot mode + */ + goto enable_af_low_light_mode; + } + + light_level = s5k4ecgx_get_light_level(sd); + + switch (parms->flash_mode) { + case FLASH_MODE_AUTO: + if (light_level > LOW_LIGHT_LEVEL) { + /* flash not needed */ + break; + } + /* fall through to turn on flash for AF assist */ + case FLASH_MODE_ON: + s5k4ecgx_auto_focus_flash_start(sd); + if (state->af_status == AF_CANCEL) + return 0; + break; + case FLASH_MODE_OFF: + break; + default: + dev_err(&client->dev, + "%s: Unknown Flash mode 0x%x\n", + __func__, parms->flash_mode); + break; + } + + if (light_level > LOW_LIGHT_LEVEL) { + if (state->sensor_af_in_low_light_mode) { + state->sensor_af_in_low_light_mode = false; + s5k4ecgx_set_from_table(sd, "af low light mode off", + &state->regs->af_low_light_mode_off, 1, 0); + } + } else { +enable_af_low_light_mode: + if (!state->sensor_af_in_low_light_mode) { + state->sensor_af_in_low_light_mode = true; + s5k4ecgx_set_from_table(sd, "af low light mode on", + &state->regs->af_low_light_mode_on, 1, 0); + } + } + + s5k4ecgx_set_from_table(sd, "single af start", + &state->regs->single_af_start, 1, 0); + state->af_status = AF_INITIAL; + dev_dbg(&client->dev, "%s: af_status set to start\n", __func__); + + return 0; +} + +/* called by HAL after auto focus was finished. + * it might off the assist flash + */ +static int s5k4ecgx_finish_auto_focus(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + if (state->flash_on) { + struct s5k4ecgx_platform_data *pd = client->dev.platform_data; + s5k4ecgx_set_from_table(sd, "AF assist flash end", + &state->regs->af_assist_flash_end, 1, 0); + state->flash_on = false; + pd->af_assist_onoff(0); + } + + dev_dbg(&client->dev, "%s: single AF finished\n", __func__); + state->af_status = AF_NONE; + return 0; +} + +static int s5k4ecgx_stop_auto_focus(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + int focus_mode = parms->focus_mode; + + dev_dbg(&client->dev, "%s: single AF Off command Setting\n", __func__); + + /* always cancel ae_awb, in case AF already finished before + * we got called. + */ + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + s5k4ecgx_set_from_table(sd, "ae awb lock off", + &state->regs->ae_awb_lock_off, 1, 0); + if (state->flash_on) + s5k4ecgx_finish_auto_focus(sd); + + 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__); + + if (focus_mode == FOCUS_MODE_MACRO) { + /* for change focus mode forcely */ + parms->focus_mode = -1; + s5k4ecgx_set_focus_mode(sd, FOCUS_MODE_MACRO); + } else if (focus_mode == FOCUS_MODE_AUTO) { + /* for change focus mode forcely */ + parms->focus_mode = -1; + s5k4ecgx_set_focus_mode(sd, FOCUS_MODE_AUTO); + } + + return 0; + } + + /* auto focus was in progress. the other thread + * is either in the middle of s5k4ecgx_get_auto_focus_result_first(), + * s5k4ecgx_get_auto_focus_result_second() + * or will call it shortly. set a flag to have + * it abort it's polling. that thread will + * also do cleanup like restore focus position. + * + * it might be enough to just send sensor commands + * to abort auto focus and the other thread would get + * that state from it's polling calls, but I'm not sure. + */ + state->af_status = AF_CANCEL; + dev_dbg(&client->dev, + "%s: sending Single_AF_Off commands to sensor\n", __func__); + + s5k4ecgx_set_from_table(sd, "single af off 1", + &state->regs->single_af_off_1, 1, 0); + + msleep(state->one_frame_delay_ms); + + s5k4ecgx_set_from_table(sd, "single af off 2", + &state->regs->single_af_off_2, 1, 0); + + return 0; +} + +/* called by HAL after auto focus was started to get the first search result*/ +static int s5k4ecgx_get_auto_focus_result_first(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + u16 read_value; + + 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; + } + + /* must delay 2 frame times before checking result of 1st phase */ + mutex_unlock(&state->ctrl_lock); + msleep(state->one_frame_delay_ms*2); + mutex_lock(&state->ctrl_lock); + + /* lock AE and AWB after first AF search */ + s5k4ecgx_set_from_table(sd, "ae awb lock on", + &state->regs->ae_awb_lock_on, 1, 0); + + dev_dbg(&client->dev, "%s: 1st AF search\n", __func__); + /* enter read mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x002C, 0x7000); + state->af_status = AF_START; + } else if (state->af_status == AF_CANCEL) { + dev_dbg(&client->dev, + "%s: AF is cancelled while doing\n", __func__); + ctrl->value = AUTO_FOCUS_CANCELLED; + s5k4ecgx_finish_auto_focus(sd); + return 0; + } + s5k4ecgx_set_from_table(sd, "get 1st af search status", + &state->regs->get_1st_af_search_status, + 1, 0); + s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, + "%s: 1st i2c_read --- read_value == 0x%x\n", + __func__, read_value); + ctrl->value = read_value; + return 0; +} + +/* called by HAL after first search was succeed to get the second search result*/ +static int s5k4ecgx_get_auto_focus_result_second(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + u16 read_value; + + if (state->af_status == AF_CANCEL) { + dev_dbg(&client->dev, + "%s: AF is cancelled while doing\n", __func__); + ctrl->value = AUTO_FOCUS_CANCELLED; + s5k4ecgx_finish_auto_focus(sd); + return 0; + } + s5k4ecgx_set_from_table(sd, "get 2nd af search status", + &state->regs->get_2nd_af_search_status, + 1, 0); + s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, + "%s: 2nd i2c_read --- read_value == 0x%x\n", + __func__, read_value); + ctrl->value = read_value; + return 0; +} + +static void s5k4ecgx_init_parameters(struct v4l2_subdev *sd) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + + state->strm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + parms->capture.capturemode = 0; + parms->capture.timeperframe.numerator = 1; + parms->capture.timeperframe.denominator = 30; + parms->contrast = CONTRAST_DEFAULT; + parms->effects = IMAGE_EFFECT_NONE; + parms->brightness = EV_DEFAULT; + parms->flash_mode = FLASH_MODE_AUTO; + parms->focus_mode = FOCUS_MODE_AUTO; + parms->iso = ISO_AUTO; + parms->metering = METERING_CENTER; + parms->saturation = SATURATION_DEFAULT; + parms->scene_mode = SCENE_MODE_NONE; + parms->sharpness = SHARPNESS_DEFAULT; + parms->white_balance = WHITE_BALANCE_AUTO; + + 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; + + state->fw.major = 1; + + state->one_frame_delay_ms = NORMAL_MODE_MAX_ONE_FRAME_DELAY_MS; +} + +static void s5k4ecgx_set_framesize(struct v4l2_subdev *sd, + const struct s5k4ecgx_framesize *frmsize, + int frmsize_count, bool exact_match); +static int s5k4ecgx_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + dev_dbg(&client->dev, "%s: code = 0x%x, field = 0x%x," + " colorspace = 0x%x, width = %d, height = %d\n", + __func__, fmt->code, fmt->field, + fmt->colorspace, + fmt->width, fmt->height); + + 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 = S5K4ECGX_OPRMODE_IMAGE; + /* + * In case of image capture mode, + * if the given image resolution is not supported, + * use the next higher image resolution. */ + s5k4ecgx_set_framesize(sd, s5k4ecgx_capture_framesize_list, + ARRAY_SIZE(s5k4ecgx_capture_framesize_list), + false); + + } else { + state->oprmode = S5K4ECGX_OPRMODE_VIDEO; + /* + * In case of video mode, + * if the given video resolution is not matching, use + * the default rate (currently S5K4ECGX_PREVIEW_WVGA). + */ + s5k4ecgx_set_framesize(sd, s5k4ecgx_preview_framesize_list, + ARRAY_SIZE(s5k4ecgx_preview_framesize_list), + true); + } + + state->jpeg.enable = state->pix.pixelformat == V4L2_PIX_FMT_JPEG; + + return 0; +} + +static int s5k4ecgx_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_frmsizeenum *fsize) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + /* 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 (SVGA) + */ + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = state->pix.width; + fsize->discrete.height = state->pix.height; + return 0; +} + +static int s5k4ecgx_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + pr_debug("%s: index = %d\n", __func__, index); + + if (index >= ARRAY_SIZE(capture_fmts)) + return -EINVAL; + + *code = capture_fmts[index].code; + + return 0; +} + +static int s5k4ecgx_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + int num_entries; + int i; + + num_entries = ARRAY_SIZE(capture_fmts); + + pr_debug("%s: code = 0x%x, colorspace = 0x%x, num_entries = %d\n", + __func__, fmt->code, fmt->colorspace, num_entries); + + for (i = 0; i < num_entries; i++) { + if (capture_fmts[i].code == fmt->code && + capture_fmts[i].colorspace == fmt->colorspace) { + pr_debug("%s: match found, returning 0\n", __func__); + return 0; + } + } + + pr_debug("%s: no match found, returning -EINVAL\n", __func__); + return -EINVAL; +} + +static void s5k4ecgx_enable_torch(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct s5k4ecgx_platform_data *pdata = client->dev.platform_data; + + s5k4ecgx_set_from_table(sd, "torch start", + &state->regs->flash_start, 1, 0); + state->torch_on = true; + pdata->torch_onoff(1); +} + +static void s5k4ecgx_disable_torch(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct s5k4ecgx_platform_data *pdata = client->dev.platform_data; + + if (state->torch_on) { + state->torch_on = false; + pdata->torch_onoff(0); + s5k4ecgx_set_from_table(sd, "torch end", + &state->regs->flash_end, 1, 0); + } +} +static int s5k4ecgx_set_flash_mode(struct v4l2_subdev *sd, int value) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + + if (parms->flash_mode == value) + return 0; + + if ((value >= FLASH_MODE_OFF) && (value <= FLASH_MODE_TORCH)) { + pr_debug("%s: setting flash mode to %d\n", + __func__, value); + parms->flash_mode = value; + if (parms->flash_mode == FLASH_MODE_TORCH) + s5k4ecgx_enable_torch(sd); + else + s5k4ecgx_disable_torch(sd); + return 0; + } + pr_debug("%s: trying to set invalid flash mode %d\n", + __func__, value); + return -EINVAL; +} + +static int s5k4ecgx_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + memcpy(param, &state->strm, sizeof(param)); + return 0; +} + +static int s5k4ecgx_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + int err = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *new_parms = + (struct sec_cam_parm *)¶m->parm.raw_data; + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + + dev_dbg(&client->dev, "%s: start\n", __func__); + + if (param->parm.capture.timeperframe.numerator != + parms->capture.timeperframe.numerator || + param->parm.capture.timeperframe.denominator != + parms->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; + } + + /* + * 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 + */ + parms->capture.timeperframe.numerator = 1; + parms->capture.timeperframe.denominator = fps; + } + + /* we return an error if one happened but don't stop trying to + * set all parameters passed + */ + err = s5k4ecgx_set_parameter(sd, &parms->contrast, new_parms->contrast, + "contrast", state->regs->contrast, + ARRAY_SIZE(state->regs->contrast)); + err |= s5k4ecgx_set_parameter(sd, &parms->effects, new_parms->effects, + "effect", state->regs->effect, + ARRAY_SIZE(state->regs->effect)); + err |= s5k4ecgx_set_parameter(sd, &parms->brightness, + new_parms->brightness, "brightness", + state->regs->ev, ARRAY_SIZE(state->regs->ev)); + err |= s5k4ecgx_set_flash_mode(sd, new_parms->flash_mode); + /* Must delay 150ms before setting macro mode due to a camera + * sensor requirement */ + if ((new_parms->focus_mode == FOCUS_MODE_MACRO) && + (parms->focus_mode != FOCUS_MODE_MACRO)) + msleep(150); + err |= s5k4ecgx_set_focus_mode(sd, new_parms->focus_mode); + err |= s5k4ecgx_set_parameter(sd, &parms->iso, new_parms->iso, + "iso", state->regs->iso, + ARRAY_SIZE(state->regs->iso)); + err |= s5k4ecgx_set_parameter(sd, &parms->metering, new_parms->metering, + "metering", state->regs->metering, + ARRAY_SIZE(state->regs->metering)); + err |= s5k4ecgx_set_parameter(sd, &parms->saturation, + new_parms->saturation, "saturation", + state->regs->saturation, + ARRAY_SIZE(state->regs->saturation)); + err |= s5k4ecgx_set_parameter(sd, &parms->scene_mode, + new_parms->scene_mode, "scene_mode", + state->regs->scene_mode, + ARRAY_SIZE(state->regs->scene_mode)); + err |= s5k4ecgx_set_parameter(sd, &parms->sharpness, + new_parms->sharpness, "sharpness", + state->regs->sharpness, + ARRAY_SIZE(state->regs->sharpness)); + err |= s5k4ecgx_set_parameter(sd, &parms->white_balance, + new_parms->white_balance, "white balance", + state->regs->white_balance, + ARRAY_SIZE(state->regs->white_balance)); + err |= s5k4ecgx_set_parameter(sd, &parms->fps, + new_parms->fps, "fps", + state->regs->fps, + ARRAY_SIZE(state->regs->fps)); + + if (parms->scene_mode == SCENE_MODE_NIGHTSHOT) + state->one_frame_delay_ms = NIGHT_MODE_MAX_ONE_FRAME_DELAY_MS; + else + state->one_frame_delay_ms = NORMAL_MODE_MAX_ONE_FRAME_DELAY_MS; + + dev_dbg(&client->dev, "%s: returning %d\n", __func__, err); + 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 sets the + * most appropriate frame size. + * + * The list is stored in an increasing order (as far as possible). + * Hence 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 perfect match, we set the last entry (which is supposed + * to be the largest resolution supported.) + */ +static void s5k4ecgx_set_framesize(struct v4l2_subdev *sd, + const struct s5k4ecgx_framesize *frmsize, + int frmsize_count, bool preview) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct s5k4ecgx_framesize *last_frmsize = + &frmsize[frmsize_count - 1]; + + dev_dbg(&client->dev, "%s: Requested Res: %dx%d\n", __func__, + state->pix.width, state->pix.height); + + do { + /* + * In case of image capture mode, + * if the given image resolution is not supported, + * return the next higher image resolution. */ + if (preview) { + if (frmsize->width == state->pix.width && + frmsize->height == state->pix.height) { + break; + } + } else { + dev_dbg(&client->dev, + "%s: compare frmsize %dx%d to %dx%d\n", + __func__, + frmsize->width, frmsize->height, + state->pix.width, state->pix.height); + if (frmsize->width >= state->pix.width && + frmsize->height >= state->pix.height) { + dev_dbg(&client->dev, + "%s: select frmsize %dx%d, index=%d\n", + __func__, + frmsize->width, frmsize->height, + frmsize->index); + break; + } + } + + frmsize++; + } while (frmsize <= last_frmsize); + + if (frmsize > last_frmsize) + frmsize = last_frmsize; + + state->pix.width = frmsize->width; + state->pix.height = frmsize->height; + if (preview) { + state->preview_framesize_index = frmsize->index; + dev_dbg(&client->dev, "%s: Preview Res Set: %dx%d, index %d\n", + __func__, state->pix.width, state->pix.height, + state->preview_framesize_index); + } else { + state->capture_framesize_index = frmsize->index; + dev_dbg(&client->dev, "%s: Capture Res Set: %dx%d, index %d\n", + __func__, state->pix.width, state->pix.height, + state->capture_framesize_index); + } +} + +static int s5k4ecgx_check_dataline_stop(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + int err; + + dev_dbg(&client->dev, "%s\n", __func__); + + err = s5k4ecgx_set_from_table(sd, "DTP stop", + &state->regs->dtp_stop, 1, 0); + if (err < 0) { + v4l_info(client, "%s: register set failed\n", __func__); + return -EIO; + } + + state->check_dataline = 0; + + return err; +} + +static void s5k4ecgx_get_esd_int(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 read_value; + int err; + + if ((S5K4ECGX_RUNMODE_RUNNING == state->runmode) && + (state->af_status != AF_START)) { + err = s5k4ecgx_set_from_table(sd, "get esd status", + &state->regs->get_esd_status, + 1, 0); + err |= s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, + "%s: read_value == 0x%x\n", __func__, read_value); + /* return to write mode */ + err |= s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + if (err < 0) { + v4l_info(client, + "Failed I2C for getting ESD information\n"); + ctrl->value = 0x01; + } else { + if (read_value != 0x0000) { + v4l_info(client, "ESD interrupt happened!!\n"); + ctrl->value = 0x01; + } else { + dev_dbg(&client->dev, + "%s: No ESD interrupt!!\n", __func__); + ctrl->value = 0x00; + } + } + } else + ctrl->value = 0x00; +} + +/* returns the real iso currently used by sensor due to lighting + * conditions, not the requested iso we sent using s_ctrl. + */ +static int s5k4ecgx_get_iso(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + u16 read_value1 = 0; + u16 read_value2 = 0; + int read_value; + + err = s5k4ecgx_set_from_table(sd, "get iso", + &state->regs->get_iso, 1, 0); + err |= s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value1); + err |= s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value2); + + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + read_value = read_value1 * read_value2 / 384; + + if (read_value > 0x400) + ctrl->value = ISO_400; + else if (read_value > 0x200) + ctrl->value = ISO_200; + else if (read_value > 0x100) + ctrl->value = ISO_100; + else + ctrl->value = ISO_50; + + dev_dbg(&client->dev, "%s: get iso == %d (0x%x, 0x%x)\n", + __func__, ctrl->value, read_value1, read_value2); + + return err; +} + +static int s5k4ecgx_get_shutterspeed(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + u16 read_value_1; + u16 read_value_2; + u32 read_value; + + err = s5k4ecgx_set_from_table(sd, "get shutterspeed", + &state->regs->get_shutterspeed, 1, 0); + err |= s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value_1); + err |= s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value_2); + + read_value = (read_value_2 << 16) | (read_value_1 & 0xffff); + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + ctrl->value = read_value * 1000 / 400; + dev_dbg(&client->dev, + "%s: get shutterspeed == %d\n", __func__, ctrl->value); + + return err; +} + +static int s5k4ecgx_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + int err = 0; + + if (!state->initialized) { + dev_err(&client->dev, + "%s: return error because uninitialized\n", __func__); + return -ENODEV; + } + + mutex_lock(&state->ctrl_lock); + + switch (ctrl->id) { + case V4L2_CID_CAMERA_WHITE_BALANCE: + ctrl->value = parms->white_balance; + break; + case V4L2_CID_CAMERA_EFFECT: + ctrl->value = parms->effects; + break; + case V4L2_CID_CAMERA_CONTRAST: + ctrl->value = parms->contrast; + break; + case V4L2_CID_CAMERA_SATURATION: + ctrl->value = parms->saturation; + break; + case V4L2_CID_CAMERA_SHARPNESS: + ctrl->value = parms->sharpness; + break; + case V4L2_CID_CAM_JPEG_MAIN_SIZE: + ctrl->value = state->jpeg.main_size; + break; + case V4L2_CID_CAM_JPEG_MAIN_OFFSET: + ctrl->value = state->jpeg.main_offset; + break; + case V4L2_CID_CAM_JPEG_THUMB_SIZE: + ctrl->value = state->jpeg.thumb_size; + break; + case V4L2_CID_CAM_JPEG_THUMB_OFFSET: + ctrl->value = state->jpeg.thumb_offset; + break; + case V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET: + ctrl->value = state->jpeg.postview_offset; + break; + case V4L2_CID_CAM_JPEG_MEMSIZE: + ctrl->value = SENSOR_JPEG_SNAPSHOT_MEMSIZE; + break; + case V4L2_CID_CAM_JPEG_QUALITY: + ctrl->value = state->jpeg.quality; + break; + case V4L2_CID_CAMERA_AUTO_FOCUS_RESULT_FIRST: + err = s5k4ecgx_get_auto_focus_result_first(sd, ctrl); + break; + case V4L2_CID_CAMERA_AUTO_FOCUS_RESULT_SECOND: + err = s5k4ecgx_get_auto_focus_result_second(sd, ctrl); + break; + case V4L2_CID_CAM_DATE_INFO_YEAR: + ctrl->value = 2010; + break; + case V4L2_CID_CAM_DATE_INFO_MONTH: + ctrl->value = 2; + break; + case V4L2_CID_CAM_DATE_INFO_DATE: + ctrl->value = 25; + break; + case V4L2_CID_CAM_SENSOR_VER: + ctrl->value = 1; + break; + case V4L2_CID_CAM_FW_MINOR_VER: + ctrl->value = state->fw.minor; + break; + case V4L2_CID_CAM_FW_MAJOR_VER: + ctrl->value = state->fw.major; + break; + case V4L2_CID_CAM_PRM_MINOR_VER: + ctrl->value = state->prm.minor; + break; + case V4L2_CID_CAM_PRM_MAJOR_VER: + ctrl->value = state->prm.major; + break; + case V4L2_CID_ESD_INT: + s5k4ecgx_get_esd_int(sd, ctrl); + break; + case V4L2_CID_CAMERA_GET_ISO: + err = s5k4ecgx_get_iso(sd, ctrl); + break; + case V4L2_CID_CAMERA_GET_SHT_TIME: + err = s5k4ecgx_get_shutterspeed(sd, ctrl); + break; + case V4L2_CID_CAMERA_GET_FLASH_ONOFF: + ctrl->value = state->flash_state_on_previous_capture; + break; + case V4L2_CID_CAMERA_OBJ_TRACKING_STATUS: + case V4L2_CID_CAMERA_SMART_AUTO_STATUS: + break; + default: + err = -ENOIOCTLCMD; + dev_err(&client->dev, "%s: unknown ctrl id 0x%x\n", + __func__, ctrl->id); + break; + } + + mutex_unlock(&state->ctrl_lock); + + return err; +} + +static int s5k4ecgx_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + int err = 0; + int value = ctrl->value; + + if (!state->initialized && + (ctrl->id != V4L2_CID_CAMERA_CHECK_DATALINE)) { + dev_err(&client->dev, + "%s: return error because uninitialized\n", __func__); + return -ENODEV; + } + + dev_dbg(&client->dev, "%s: V4l2 control ID =%d, val = %d\n", + __func__, ctrl->id - V4L2_CID_PRIVATE_BASE, value); + + mutex_lock(&state->ctrl_lock); + + switch (ctrl->id) { + case V4L2_CID_CAMERA_FLASH_MODE: + err = s5k4ecgx_set_flash_mode(sd, value); + break; + case V4L2_CID_CAMERA_BRIGHTNESS: + if (state->runmode == S5K4ECGX_RUNMODE_RUNNING) { + err = s5k4ecgx_set_parameter(sd, &parms->brightness, + value, "brightness", + state->regs->ev, + ARRAY_SIZE(state->regs->ev)); + } else { + dev_err(&client->dev, + "%s: trying to set brightness when not " + "in preview mode\n", + __func__); + err = -EINVAL; + } + break; + case V4L2_CID_CAMERA_WHITE_BALANCE: + if (state->runmode == S5K4ECGX_RUNMODE_RUNNING) { + err = s5k4ecgx_set_parameter(sd, &parms->white_balance, + value, "white balance", + state->regs->white_balance, + ARRAY_SIZE(state->regs->white_balance)); + } else { + dev_err(&client->dev, + "%s: trying to set white balance when not " + "in preview mode\n", + __func__); + err = -EINVAL; + } + break; + case V4L2_CID_CAMERA_EFFECT: + if (state->runmode == S5K4ECGX_RUNMODE_RUNNING) { + err = s5k4ecgx_set_parameter(sd, &parms->effects, + value, "effects", state->regs->effect, + ARRAY_SIZE(state->regs->effect)); + } else { + dev_err(&client->dev, + "%s: trying to set effect when not " + "in preview mode\n", + __func__); + err = -EINVAL; + } + break; + case V4L2_CID_CAMERA_ISO: + if (state->runmode == S5K4ECGX_RUNMODE_RUNNING) { + err = s5k4ecgx_set_parameter(sd, &parms->iso, + value, "iso", + state->regs->iso, + ARRAY_SIZE(state->regs->iso)); + } else { + dev_err(&client->dev, + "%s: trying to set iso when not " + "in preview mode\n", + __func__); + err = -EINVAL; + } + break; + case V4L2_CID_CAMERA_METERING: + if (state->runmode == S5K4ECGX_RUNMODE_RUNNING) { + err = s5k4ecgx_set_parameter(sd, &parms->metering, + value, "metering", + state->regs->metering, + ARRAY_SIZE(state->regs->metering)); + } else { + dev_err(&client->dev, + "%s: trying to set metering when not " + "in preview mode\n", + __func__); + err = -EINVAL; + } + break; + case V4L2_CID_CAMERA_CONTRAST: + err = s5k4ecgx_set_parameter(sd, &parms->contrast, + value, "contrast", + state->regs->contrast, + ARRAY_SIZE(state->regs->contrast)); + break; + case V4L2_CID_CAMERA_SATURATION: + err = s5k4ecgx_set_parameter(sd, &parms->saturation, + value, "saturation", + state->regs->saturation, + ARRAY_SIZE(state->regs->saturation)); + break; + case V4L2_CID_CAMERA_SHARPNESS: + err = s5k4ecgx_set_parameter(sd, &parms->sharpness, + value, "sharpness", + state->regs->sharpness, + ARRAY_SIZE(state->regs->sharpness)); + break; + case V4L2_CID_CAMERA_WDR: + err = s5k4ecgx_set_wdr(sd, value); + break; + case V4L2_CID_CAMERA_FACE_DETECTION: + err = s5k4ecgx_set_face_detection(sd, value); + break; + case V4L2_CID_CAMERA_FOCUS_MODE: + err = s5k4ecgx_set_focus_mode(sd, value); + break; + case V4L2_CID_CAM_JPEG_QUALITY: + if (state->runmode == S5K4ECGX_RUNMODE_RUNNING) { + state->jpeg.quality = value; + err = s5k4ecgx_set_jpeg_quality(sd); + } else { + dev_err(&client->dev, + "%s: trying to set jpeg quality when not " + "in preview mode\n", + __func__); + err = -EINVAL; + } + break; + case V4L2_CID_CAMERA_SCENE_MODE: + err = s5k4ecgx_set_parameter(sd, &parms->scene_mode, + SCENE_MODE_NONE, "scene_mode", + state->regs->scene_mode, + ARRAY_SIZE(state->regs->scene_mode)); + if (err < 0) { + dev_err(&client->dev, + "%s: failed to set scene-mode default value\n", + __func__); + break; + } + if (value != SCENE_MODE_NONE) { + err = s5k4ecgx_set_parameter(sd, &parms->scene_mode, + value, "scene_mode", + state->regs->scene_mode, + ARRAY_SIZE(state->regs->scene_mode)); + } + if (parms->scene_mode == SCENE_MODE_NIGHTSHOT) { + state->one_frame_delay_ms = + NIGHT_MODE_MAX_ONE_FRAME_DELAY_MS; + } else { + state->one_frame_delay_ms = + NORMAL_MODE_MAX_ONE_FRAME_DELAY_MS; + } + + break; + case V4L2_CID_CAMERA_GPS_LATITUDE: + dev_err(&client->dev, + "%s: V4L2_CID_CAMERA_GPS_LATITUDE: not implemented\n", + __func__); + break; + case V4L2_CID_CAMERA_GPS_LONGITUDE: + dev_err(&client->dev, + "%s: V4L2_CID_CAMERA_GPS_LONGITUDE: not implemented\n", + __func__); + break; + case V4L2_CID_CAMERA_GPS_TIMESTAMP: + dev_err(&client->dev, + "%s: V4L2_CID_CAMERA_GPS_TIMESTAMP: not implemented\n", + __func__); + break; + case V4L2_CID_CAMERA_GPS_ALTITUDE: + dev_err(&client->dev, + "%s: V4L2_CID_CAMERA_GPS_ALTITUDE: not implemented\n", + __func__); + break; + case V4L2_CID_CAMERA_OBJECT_POSITION_X: + state->position.x = value; + break; + case V4L2_CID_CAMERA_OBJECT_POSITION_Y: + state->position.y = value; + break; + case V4L2_CID_CAMERA_SET_AUTO_FOCUS: + if (value == AUTO_FOCUS_ON) + err = s5k4ecgx_start_auto_focus(sd); + else if (value == AUTO_FOCUS_OFF) + err = s5k4ecgx_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: + dev_dbg(&client->dev, + "%s: camera frame rate request for %d fps\n", + __func__, value); + err = s5k4ecgx_set_parameter(sd, &parms->fps, + value, "fps", + state->regs->fps, + ARRAY_SIZE(state->regs->fps)); + break; + case V4L2_CID_CAM_CAPTURE: + err = s5k4ecgx_start_capture(sd); + 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 (value) + err = s5k4ecgx_set_preview_start(sd); + else + err = s5k4ecgx_set_preview_stop(sd); + break; + case V4L2_CID_CAMERA_CHECK_DATALINE: + dev_dbg(&client->dev, "%s: check_dataline set to %d\n", + __func__, value); + state->check_dataline = value; + break; + case V4L2_CID_CAMERA_CHECK_DATALINE_STOP: + err = s5k4ecgx_check_dataline_stop(sd); + break; + case V4L2_CID_CAMERA_RETURN_FOCUS: + if (parms->focus_mode != FOCUS_MODE_MACRO) + err = s5k4ecgx_return_focus(sd); + break; + case V4L2_CID_CAMERA_FINISH_AUTO_FOCUS: + err = s5k4ecgx_finish_auto_focus(sd); + break; + default: + dev_err(&client->dev, "%s: unknown set ctrl id 0x%x\n", + __func__, ctrl->id); + err = -ENOIOCTLCMD; + break; + } + + if (err < 0) + dev_err(&client->dev, "%s: videoc_s_ctrl failed %d\n", __func__, + err); + + mutex_unlock(&state->ctrl_lock); + + dev_dbg(&client->dev, "%s: videoc_s_ctrl returning %d\n", + __func__, err); + + return err; +} + +static int s5k4ecgx_s_ext_ctrl(struct v4l2_subdev *sd, + struct v4l2_ext_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + int err = 0; + struct gps_info_common *tempGPSType = NULL; + + switch (ctrl->id) { + + case V4L2_CID_CAMERA_GPS_LATITUDE: + tempGPSType = (struct gps_info_common *)ctrl->reserved2[1]; + state->gps_info.gps_buf[0] = tempGPSType->direction; + state->gps_info.gps_buf[1] = tempGPSType->dgree; + state->gps_info.gps_buf[2] = tempGPSType->minute; + state->gps_info.gps_buf[3] = tempGPSType->second; + break; + case V4L2_CID_CAMERA_GPS_LONGITUDE: + tempGPSType = (struct gps_info_common *)ctrl->reserved2[1]; + state->gps_info.gps_buf[4] = tempGPSType->direction; + state->gps_info.gps_buf[5] = tempGPSType->dgree; + state->gps_info.gps_buf[6] = tempGPSType->minute; + state->gps_info.gps_buf[7] = tempGPSType->second; + break; + case V4L2_CID_CAMERA_GPS_ALTITUDE: + tempGPSType = (struct gps_info_common *)ctrl->reserved2[1]; + state->gps_info.altitude_buf[0] = tempGPSType->direction; + state->gps_info.altitude_buf[1] = + (tempGPSType->dgree) & 0x00ff; + state->gps_info.altitude_buf[2] = + ((tempGPSType->dgree) & 0xff00) >> 8; + state->gps_info.altitude_buf[3] = tempGPSType->minute; + break; + case V4L2_CID_CAMERA_GPS_TIMESTAMP: + state->gps_info.gps_timeStamp = *((int *)ctrl->reserved2[1]); + err = 0; + break; + default: + dev_err(&client->dev, "%s: unknown ctrl->id %d\n", + __func__, ctrl->id); + err = -ENOIOCTLCMD; + break; + } + + if (err < 0) + dev_err(&client->dev, "%s: vidioc_s_ext_ctrl failed %d\n", + __func__, err); + + return err; +} + +static int s5k4ecgx_s_ext_ctrls(struct v4l2_subdev *sd, + struct v4l2_ext_controls *ctrls) +{ + struct v4l2_ext_control *ctrl = ctrls->controls; + int ret; + int i; + + for (i = 0; i < ctrls->count; i++, ctrl++) { + ret = s5k4ecgx_s_ext_ctrl(sd, ctrl); + + if (ret) { + ctrls->error_idx = i; + break; + } + } + + return ret; +} + +#ifdef CONFIG_VIDEO_S5K4ECGX_DEBUG +static void s5k4ecgx_dump_regset(struct s5k4ecgx_regset *regset) +{ + if ((regset->data[0] == 0x00) && (regset->data[1] == 0x2A)) { + if (regset->size <= 6) + pr_err("odd regset size %d\n", regset->size); + pr_info("regset: addr = 0x%02X%02X, data[0,1] = 0x%02X%02X," + " total data size = %d\n", + regset->data[2], regset->data[3], + regset->data[6], regset->data[7], + regset->size-6); + } else { + pr_info("regset: 0x%02X%02X%02X%02X\n", + regset->data[0], regset->data[1], + regset->data[2], regset->data[3]); + if (regset->size != 4) + pr_err("odd regset size %d\n", regset->size); + } +} +#endif + +static int s5k4ecgx_i2c_write_block(struct v4l2_subdev *sd, u8 *buf, int size) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int retry_count = 5; + int ret; + struct i2c_msg msg = {client->addr, 0, size, buf}; + +#ifdef CONFIG_VIDEO_S5K4ECGX_DEBUG + if (s5k4ecgx_debug_mask & S5K4ECGX_DEBUG_I2C_BURSTS) { + if ((buf[0] == 0x0F) && (buf[1] == 0x12)) + pr_info("%s : data[0,1] = 0x%02X%02X," + " total data size = %d\n", + __func__, buf[2], buf[3], size-2); + else + pr_info("%s : 0x%02X%02X%02X%02X\n", + __func__, buf[0], buf[1], buf[2], buf[3]); + } +#endif + + do { + ret = i2c_transfer(client->adapter, &msg, 1); + if (likely(ret == 1)) + break; + msleep(POLL_TIME_MS); + } while (retry_count-- > 0); + if (ret != 1) { + dev_err(&client->dev, "%s: I2C is not working.\n", __func__); + return -EIO; + } + +#ifdef CONFIG_VIDEO_S5K4ECGX_V_1_0 + { + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + if (state->fw.minor == 0) { + /* v1.0 sensor have problems sometimes if we write + * too much data too fast, so add a sleep. I've + * tried various combinations of size/delay. Checking + * for a larger size doesn't seem to work reliably, and + * a delay of 1ms sometimes isn't enough either. + */ + if (size > 16) + msleep(2); + } + } +#endif + return 0; +} + +/* + * Parse the init_reg2 array into a number of register sets that + * we can send over as i2c burst writes instead of writing each + * entry of init_reg2 as a single 4 byte write. Write the + * new data structures and then free them. + */ +static int s5k4ecgx_write_init_reg2_burst(struct v4l2_subdev *sd) +{ + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + struct s5k4ecgx_regset *regset_table; + struct s5k4ecgx_regset *regset; + struct s5k4ecgx_regset *end_regset; + u8 *regset_data; + u8 *dst_ptr; + const u32 *end_src_ptr; + bool flag_copied; + int init_reg_2_array_size = state->regs->init_reg_2.array_size; + int init_reg_2_size = init_reg_2_array_size * sizeof(u32); + const u32 *src_ptr = state->regs->init_reg_2.reg; + u32 src_value; + int err; + + pr_debug("%s : start\n", __func__); + + regset_data = vmalloc(init_reg_2_size); + if (regset_data == NULL) + return -ENOMEM; + regset_table = vmalloc(sizeof(struct s5k4ecgx_regset) * + init_reg_2_size); + if (regset_table == NULL) { + kfree(regset_data); + return -ENOMEM; + } + + dst_ptr = regset_data; + regset = regset_table; + end_src_ptr = &state->regs->init_reg_2.reg[init_reg_2_array_size]; + + src_value = *src_ptr++; + while (src_ptr <= end_src_ptr) { + /* initial value for a regset */ + regset->data = dst_ptr; + flag_copied = false; + *dst_ptr++ = src_value >> 24; + *dst_ptr++ = src_value >> 16; + *dst_ptr++ = src_value >> 8; + *dst_ptr++ = src_value; + + /* check subsequent values for a data flag (starts with + 0x0F12) or something else */ + do { + src_value = *src_ptr++; + if ((src_value & 0xFFFF0000) != 0x0F120000) { + /* src_value is start of next regset */ + regset->size = dst_ptr - regset->data; + regset++; + break; + } + /* copy the 0x0F12 flag if not done already */ + if (!flag_copied) { + *dst_ptr++ = src_value >> 24; + *dst_ptr++ = src_value >> 16; + flag_copied = true; + } + /* copy the data part */ + *dst_ptr++ = src_value >> 8; + *dst_ptr++ = src_value; + } while (src_ptr < end_src_ptr); + } + pr_debug("%s : finished creating table\n", __func__); + + end_regset = regset; + pr_debug("%s : first regset = %p, last regset = %p, count = %d\n", + __func__, regset_table, regset, end_regset - regset_table); + pr_debug("%s : regset_data = %p, end = %p, dst_ptr = %p\n", __func__, + regset_data, regset_data + (init_reg_2_size * sizeof(u32)), + dst_ptr); + +#ifdef CONFIG_VIDEO_S5K4ECGX_DEBUG + if (s5k4ecgx_debug_mask & S5K4ECGX_DEBUG_I2C_BURSTS) { + int last_regset_end_addr = 0; + regset = regset_table; + do { + s5k4ecgx_dump_regset(regset); + if (regset->size > 4) { + int regset_addr = (regset->data[2] << 8 | + regset->data[3]); + if (last_regset_end_addr == regset_addr) + pr_info("%s : this regset can be" + " combined with previous\n", + __func__); + last_regset_end_addr = (regset_addr + + regset->size - 6); + } + regset++; + } while (regset < end_regset); + } +#endif + regset = regset_table; + pr_debug("%s : start writing init reg 2 bursts\n", __func__); + do { + if (regset->size > 4) { + /* write the address packet */ + err = s5k4ecgx_i2c_write_block(sd, regset->data, 4); + if (err) + break; + /* write the data in a burst */ + err = s5k4ecgx_i2c_write_block(sd, regset->data+4, + regset->size-4); + + } else + err = s5k4ecgx_i2c_write_block(sd, regset->data, + regset->size); + if (err) + break; + regset++; + } while (regset < end_regset); + + pr_debug("%s : finished writing init reg 2 bursts\n", __func__); + + vfree(regset_data); + vfree(regset_table); + + return err; +} + +static int s5k4ecgx_init_regs(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + u16 read_value; + + /* we'd prefer to do this in probe, but the framework hasn't + * turned on the camera yet so our i2c operations would fail + * if we tried to do it in probe, so we have to do it here + * and keep track if we succeeded or not. + */ + + /* enter read mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x002C, 0x7000); + + s5k4ecgx_i2c_write_twobyte(client, 0x002E, 0x01A6); + s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + + pr_info("%s : revision %08X\n", __func__, read_value); + + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + +#ifdef CONFIG_VIDEO_S5K4ECGX_V_1_0 + if (read_value == S5K4ECGX_VERSION_1_0) { + state->regs = ®s_for_fw_version_1_0; + state->initialized = true; + return 0; + } +#endif +#ifdef CONFIG_VIDEO_S5K4ECGX_V_1_1 + if (read_value == S5K4ECGX_VERSION_1_1) { + state->fw.minor = 1; + state->regs = ®s_for_fw_version_1_1; + state->initialized = true; + return 0; + } +#endif + + dev_err(&client->dev, "%s: unknown fw version 0x%x\n", + __func__, read_value); + return -ENODEV; +} + +static int s5k4ecgx_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + dev_dbg(&client->dev, "%s: start\n", __func__); + + s5k4ecgx_init_parameters(sd); + + if (s5k4ecgx_init_regs(&state->sd) < 0) + return -ENODEV; + + dev_dbg(&client->dev, "%s: state->check_dataline : %d\n", + __func__, state->check_dataline); + + if (s5k4ecgx_set_from_table(sd, "init reg 1", + &state->regs->init_reg_1, 1, 0) < 0) + return -EIO; + + /* delay 10ms after wakeup of SOC processor */ + msleep(10); + + if (s5k4ecgx_write_init_reg2_burst(sd) < 0) + return -EIO; + + if (s5k4ecgx_set_from_table(sd, "flash init", + &state->regs->flash_init, 1, 0) < 0) + return -EIO; + + if (state->check_dataline) { + if (s5k4ecgx_set_from_table(sd, "dtp start", + &state->regs->dtp_start, 1, 0) < 0) + return -EIO; + } + + dev_dbg(&client->dev, "%s: end\n", __func__); + + return 0; +} + +static const struct v4l2_subdev_core_ops s5k4ecgx_core_ops = { + .init = s5k4ecgx_init, /* initializing API */ + .g_ctrl = s5k4ecgx_g_ctrl, + .s_ctrl = s5k4ecgx_s_ctrl, + .s_ext_ctrls = s5k4ecgx_s_ext_ctrls, +}; + +static const struct v4l2_subdev_video_ops s5k4ecgx_video_ops = { + .s_mbus_fmt = s5k4ecgx_s_mbus_fmt, + .enum_framesizes = s5k4ecgx_enum_framesizes, + .enum_mbus_fmt = s5k4ecgx_enum_mbus_fmt, + .try_mbus_fmt = s5k4ecgx_try_mbus_fmt, + .g_parm = s5k4ecgx_g_parm, + .s_parm = s5k4ecgx_s_parm, +}; + +static const struct v4l2_subdev_ops s5k4ecgx_ops = { + .core = &s5k4ecgx_core_ops, + .video = &s5k4ecgx_video_ops, +}; + + +/* + * s5k4ecgx_probe + * Fetching platform data is being done with s_config subdev call. + * In probe routine, we just register subdev device + */ +static int s5k4ecgx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct v4l2_subdev *sd; + struct s5k4ecgx_state *state; + struct s5k4ecgx_platform_data *pdata = client->dev.platform_data; + + if ((pdata == NULL) || (pdata->flash_onoff == NULL)) { + dev_err(&client->dev, "%s: bad platform data\n", __func__); + return -ENODEV; + } + + state = kzalloc(sizeof(struct s5k4ecgx_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + mutex_init(&state->ctrl_lock); + + state->runmode = S5K4ECGX_RUNMODE_NOTREADY; + sd = &state->sd; + strcpy(sd->name, S5K4ECGX_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, &s5k4ecgx_ops); + + dev_dbg(&client->dev, "5MP camera S5K4ECGX loaded.\n"); + + return 0; +} + +static int s5k4ecgx_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + v4l2_device_unregister_subdev(sd); + mutex_destroy(&state->ctrl_lock); + kfree(state); + + dev_dbg(&client->dev, "Unloaded camera sensor S5K4ECGX.\n"); + + return 0; +} + +static const struct i2c_device_id s5k4ecgx_id[] = { + { S5K4ECGX_DRIVER_NAME, 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, s5k4ecgx_id); + +static struct i2c_driver v4l2_i2c_driver = { + .driver.name = S5K4ECGX_DRIVER_NAME, + .probe = s5k4ecgx_probe, + .remove = s5k4ecgx_remove, + .id_table = s5k4ecgx_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("LSI S5K4ECGX 5MP SOC camera driver"); +MODULE_AUTHOR("Seok-Young Jang <quartz.jang@samsung.com>"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/video/s5k4ecgx_regs_1_0.h b/drivers/media/video/s5k4ecgx_regs_1_0.h new file mode 100755 index 0000000..afafe7f --- /dev/null +++ b/drivers/media/video/s5k4ecgx_regs_1_0.h @@ -0,0 +1,4797 @@ +/* drivers/media/video/s5k4ecgx_regs_1_0.h + * + * Driver for s5k4ecgx (5MP Camera) from SEC(LSI), firmware EVT1.0 + * + * Copyright (C) 2010, SAMSUNG ELECTRONICS + * + * 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. + */ + + +#ifndef __S5K4ECGX_REGS_1_0_H__ +#define __S5K4ECGX_REGS_1_0_H__ + +/* ARM initialization */ +static const u32 s5k4ecgx_init_reg1_v1[] = { + /* direct addressing, hw addresses */ + 0xFCFCD000, + 0x00040000, + 0xFCFCD000, + 0x00100001, + 0xFCFCD000, + 0x10300000, + 0x00140001, +}; + +static const u32 s5k4ecgx_init_reg2_v1[] = { + /* start analog settings, indirect addressing mode */ + 0x0028D000, + + 0x002A007A, + 0x0F120000, + + 0x002AE406, + 0x0F120092, + + 0x002AE410, + 0x0F123804, + + 0x002AE420, + 0x0F120003, + 0x0F120060, + + 0x002AE42E, + 0x0F120004, + + 0x002AF400, + 0x0F125A3C, + 0x0F120023, + 0x0F128080, + 0x0F1203AF, + 0x0F12000A, + 0x0F12AA54, + 0x0F120040, + 0x0F12464E, + 0x0F120240, + 0x0F120240, + 0x0F120040, + 0x0F121000, + 0x0F125558, + 0x0F12D000, + 0x0F120010, + 0x0F120202, + 0x0F120401, + 0x0F120022, + 0x0F120088, + 0x0F12009F, + 0x0F120000, + 0x0F121800, + 0x0F120088, + 0x0F120000, + 0x0F122428, + 0x0F120000, + 0x0F1203EE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x002AF480, + 0x0F120004, + 0x0F1205B6, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F120007, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F12024E, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F1205B6, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F12024F, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120075, + 0x0F1200CF, + 0x0F120000, + 0x0F120000, + 0x0F120075, + 0x0F1200D6, + 0x0F120000, + 0x0F120000, + 0x0F120004, + 0x0F1201F4, + 0x0F120000, + 0x0F120000, + 0x0F1200F0, + 0x0F1201F4, + 0x0F12029E, + 0x0F1205B2, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1201F8, + 0x0F120228, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120208, + 0x0F120238, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x002AF590, + 0x0F120000, + + 0x002AF500, + 0x0F120218, + 0x0F120238, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F120009, + 0x0F1200DE, + 0x0F1205C0, + 0x0F120000, + 0x0F120000, + 0x0F1200DF, + 0x0F1200E4, + 0x0F1201F8, + 0x0F1201FD, + 0x0F1205B6, + 0x0F1205BB, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1201F8, + 0x0F120000, + 0x0F120000, + 0x0F120077, + 0x0F12007E, + 0x0F12024F, + 0x0F12025E, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120708, + 0x0F12080C, + + 0x002A1082, + 0x0F125555, + 0x0F125555, + + 0x002A1088, + 0x0F12055D, + + 0x002A100E, + 0x0F120000, + + /* switch to sw address bank */ + 0x00287000, + + 0x002A0716, + 0x0F120100, + + /* Start of Patch Data for firmware */ + 0x002A3A10, + 0x0F12B5F8, + 0x0F124A3E, + 0x0F12493E, + 0x0F12483F, + 0x0F12C004, + 0x0F126001, + 0x0F124C3E, + 0x0F122500, + 0x0F128265, + 0x0F128025, + 0x0F12493D, + 0x0F12483E, + 0x0F122701, + 0x0F12002A, + 0x0F12F000, + 0x0F12FC38, + 0x0F12493C, + 0x0F12483D, + 0x0F122602, + 0x0F12003A, + 0x0F12F000, + 0x0F12FC32, + 0x0F12493B, + 0x0F12483C, + 0x0F120032, + 0x0F122703, + 0x0F12F000, + 0x0F12FC2C, + 0x0F128225, + 0x0F12493A, + 0x0F12483A, + 0x0F122604, + 0x0F12003A, + 0x0F12F000, + 0x0F12FC25, + 0x0F12200E, + 0x0F128420, + 0x0F122701, + 0x0F1283E7, + 0x0F124937, + 0x0F124837, + 0x0F120032, + 0x0F122405, + 0x0F12F000, + 0x0F12FC1B, + 0x0F124936, + 0x0F124836, + 0x0F122606, + 0x0F120022, + 0x0F12F000, + 0x0F12FC15, + 0x0F124C28, + 0x0F123460, + 0x0F1281E7, + 0x0F124825, + 0x0F123824, + 0x0F1286C5, + 0x0F124932, + 0x0F124832, + 0x0F120032, + 0x0F122707, + 0x0F12F000, + 0x0F12FC09, + 0x0F124931, + 0x0F124831, + 0x0F122608, + 0x0F12003A, + 0x0F12F000, + 0x0F12FC03, + 0x0F124930, + 0x0F124830, + 0x0F120032, + 0x0F122709, + 0x0F12F000, + 0x0F12FBFD, + 0x0F122005, + 0x0F128160, + 0x0F12492E, + 0x0F12482E, + 0x0F126281, + 0x0F128225, + 0x0F128265, + 0x0F12482D, + 0x0F128320, + 0x0F12482D, + 0x0F128360, + 0x0F120270, + 0x0F1283A0, + 0x0F122005, + 0x0F120300, + 0x0F1283E0, + 0x0F124828, + 0x0F12492A, + 0x0F123840, + 0x0F126001, + 0x0F12492A, + 0x0F12482A, + 0x0F12240A, + 0x0F12003A, + 0x0F12F000, + 0x0F12FBE3, + 0x0F124929, + 0x0F124829, + 0x0F120022, + 0x0F12250B, + 0x0F12F000, + 0x0F12FBDD, + 0x0F124820, + 0x0F124927, + 0x0F123080, + 0x0F126381, + 0x0F124927, + 0x0F124827, + 0x0F12240C, + 0x0F12002A, + 0x0F12F000, + 0x0F12FBD3, + 0x0F124926, + 0x0F124826, + 0x0F120022, + 0x0F12F000, + 0x0F12FBCE, + 0x0F12BCF8, + 0x0F12BC08, + 0x0F124718, + 0x0F120000, + 0x0F120174, + 0x0F124EC1, + 0x0F12FFFE, + 0x0F120000, + 0x0F121EF0, + 0x0F127000, + 0x0F124780, + 0x0F127000, + 0x0F123BF3, + 0x0F127000, + 0x0F12A1D9, + 0x0F120000, + 0x0F123B9D, + 0x0F127000, + 0x0F12A0BD, + 0x0F120000, + 0x0F123C8D, + 0x0F127000, + 0x0F12217B, + 0x0F120000, + 0x0F123CE9, + 0x0F127000, + 0x0F12E0DF, + 0x0F120000, + 0x0F123E73, + 0x0F127000, + 0x0F12053B, + 0x0F120000, + 0x0F123D71, + 0x0F127000, + 0x0F12509B, + 0x0F120000, + 0x0F123FF9, + 0x0F127000, + 0x0F12D42F, + 0x0F120000, + 0x0F123EB5, + 0x0F127000, + 0x0F1249D1, + 0x0F120000, + 0x0F123F4F, + 0x0F127000, + 0x0F121E57, + 0x0F120000, + 0x0F124033, + 0x0F127000, + 0x0F1200C0, + 0x0F127000, + 0x0F124E34, + 0x0F120000, + 0x0F127C53, + 0x0F120000, + 0x0F1240BF, + 0x0F127000, + 0x0F1240FB, + 0x0F127000, + 0x0F12F5D7, + 0x0F120000, + 0x0F12406F, + 0x0F127000, + 0x0F12BAB1, + 0x0F120000, + 0x0F124187, + 0x0F127000, + 0x0F124129, + 0x0F127000, + 0x0F12C10D, + 0x0F120000, + 0x0F124203, + 0x0F127000, + 0x0F12B231, + 0x0F120000, + 0x0F12B570, + 0x0F12000C, + 0x0F126820, + 0x0F126865, + 0x0F12F000, + 0x0F12FB84, + 0x0F124BFC, + 0x0F120402, + 0x0F120C12, + 0x0F12819A, + 0x0F1248FB, + 0x0F1289C1, + 0x0F12428A, + 0x0F12D305, + 0x0F124AFA, + 0x0F128986, + 0x0F128852, + 0x0F1242B2, + 0x0F12D300, + 0x0F128199, + 0x0F128801, + 0x0F122900, + 0x0F12D008, + 0x0F1249F7, + 0x0F12002B, + 0x0F126E0A, + 0x0F122105, + 0x0F121C80, + 0x0F12F000, + 0x0F12FB74, + 0x0F126020, + 0x0F12E006, + 0x0F12899A, + 0x0F1248F3, + 0x0F12002B, + 0x0F122105, + 0x0F12F000, + 0x0F12FB6C, + 0x0F126020, + 0x0F126820, + 0x0F12BC70, + 0x0F12BC08, + 0x0F124718, + 0x0F12B5F8, + 0x0F120004, + 0x0F122000, + 0x0F129000, + 0x0F120020, + 0x0F122501, + 0x0F123810, + 0x0F122601, + 0x0F1240A5, + 0x0F124086, + 0x0F124FEA, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F1243A8, + 0x0F128038, + 0x0F12E002, + 0x0F128878, + 0x0F1243B0, + 0x0F128078, + 0x0F12F000, + 0x0F12FB59, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F124328, + 0x0F128038, + 0x0F12E002, + 0x0F128878, + 0x0F124330, + 0x0F128078, + 0x0F1248DA, + 0x0F122105, + 0x0F128982, + 0x0F1248DD, + 0x0F12466B, + 0x0F12F000, + 0x0F12FB41, + 0x0F121C41, + 0x0F124CD7, + 0x0F120049, + 0x0F120040, + 0x0F121909, + 0x0F121900, + 0x0F12466B, + 0x0F128A89, + 0x0F128A80, + 0x0F12881A, + 0x0F12F000, + 0x0F12FB45, + 0x0F128A61, + 0x0F120540, + 0x0F1202C9, + 0x0F120D40, + 0x0F124301, + 0x0F1248D4, + 0x0F128081, + 0x0F1249D4, + 0x0F1248D4, + 0x0F123120, + 0x0F128BC0, + 0x0F128809, + 0x0F121841, + 0x0F120020, + 0x0F123060, + 0x0F128A82, + 0x0F124291, + 0x0F12D205, + 0x0F128AC0, + 0x0F1249CF, + 0x0F127388, + 0x0F122001, + 0x0F1231A0, + 0x0F1270C8, + 0x0F12BCF8, + 0x0F12BC08, + 0x0F124718, + 0x0F12B5F8, + 0x0F1248C6, + 0x0F122200, + 0x0F1230A0, + 0x0F1281C2, + 0x0F126808, + 0x0F124669, + 0x0F12F000, + 0x0F12FB29, + 0x0F12466B, + 0x0F128818, + 0x0F12F000, + 0x0F12FB2D, + 0x0F120005, + 0x0F12466B, + 0x0F128858, + 0x0F12F000, + 0x0F12FB30, + 0x0F120004, + 0x0F122101, + 0x0F121928, + 0x0F1202C9, + 0x0F121A08, + 0x0F120286, + 0x0F120029, + 0x0F120030, + 0x0F12F000, + 0x0F12FB2E, + 0x0F120005, + 0x0F122701, + 0x0F1202BF, + 0x0F120021, + 0x0F120030, + 0x0F12F000, + 0x0F12FB27, + 0x0F1249B5, + 0x0F124AB8, + 0x0F123140, + 0x0F123220, + 0x0F12808D, + 0x0F128295, + 0x0F1280CF, + 0x0F1282D7, + 0x0F128108, + 0x0F128310, + 0x0F12E7CE, + 0x0F126808, + 0x0F120400, + 0x0F120C00, + 0x0F126849, + 0x0F120409, + 0x0F120C09, + 0x0F124AAA, + 0x0F128A12, + 0x0F122A00, + 0x0F12D00D, + 0x0F122300, + 0x0F121A89, + 0x0F12D400, + 0x0F12000B, + 0x0F120419, + 0x0F120C09, + 0x0F1223FF, + 0x0F1233C1, + 0x0F121810, + 0x0F124298, + 0x0F12D800, + 0x0F120003, + 0x0F120418, + 0x0F120C00, + 0x0F124AA9, + 0x0F128150, + 0x0F128191, + 0x0F124770, + 0x0F12B5F8, + 0x0F122400, + 0x0F124DA7, + 0x0F124F9E, + 0x0F1248A7, + 0x0F128C39, + 0x0F128041, + 0x0F122101, + 0x0F128001, + 0x0F12F000, + 0x0F12FAFB, + 0x0F1248A5, + 0x0F128BC0, + 0x0F12F000, + 0x0F12FAFF, + 0x0F12260D, + 0x0F120736, + 0x0F122000, + 0x0F1200E1, + 0x0F1219CA, + 0x0F120041, + 0x0F12194B, + 0x0F12199B, + 0x0F12881B, + 0x0F121851, + 0x0F12844B, + 0x0F121C40, + 0x0F120400, + 0x0F120C00, + 0x0F122804, + 0x0F12D3F4, + 0x0F123508, + 0x0F12042D, + 0x0F120C2D, + 0x0F121C64, + 0x0F120424, + 0x0F120C24, + 0x0F122C07, + 0x0F12D3E9, + 0x0F12E78A, + 0x0F12B5F0, + 0x0F12B087, + 0x0F126808, + 0x0F129006, + 0x0F126848, + 0x0F120405, + 0x0F120C2D, + 0x0F126888, + 0x0F120403, + 0x0F120C1B, + 0x0F124892, + 0x0F128B80, + 0x0F122800, + 0x0F12D100, + 0x0F122300, + 0x0F12001C, + 0x0F124A90, + 0x0F12466E, + 0x0F121E91, + 0x0F121E88, + 0x0F12C607, + 0x0F12498F, + 0x0F120023, + 0x0F122207, + 0x0F120028, + 0x0F12F000, + 0x0F12FAD3, + 0x0F12487E, + 0x0F128BC1, + 0x0F122900, + 0x0F12D030, + 0x0F122100, + 0x0F124888, + 0x0F124A7B, + 0x0F12380A, + 0x0F1288C0, + 0x0F1200C3, + 0x0F12189A, + 0x0F124696, + 0x0F124A86, + 0x0F121C40, + 0x0F12189B, + 0x0F12469C, + 0x0F124B76, + 0x0F1200C0, + 0x0F1218C6, + 0x0F121887, + 0x0F120048, + 0x0F124672, + 0x0F124663, + 0x0F121812, + 0x0F12181B, + 0x0F128C52, + 0x0F128EDB, + 0x0F12435A, + 0x0F120092, + 0x0F120C15, + 0x0F124A6F, + 0x0F121882, + 0x0F12235A, + 0x0F12529D, + 0x0F121833, + 0x0F121838, + 0x0F128C5B, + 0x0F128EC0, + 0x0F124343, + 0x0F120098, + 0x0F120C00, + 0x0F123260, + 0x0F128050, + 0x0F121C49, + 0x0F120409, + 0x0F120C09, + 0x0F122904, + 0x0F12D3E3, + 0x0F124A66, + 0x0F12325A, + 0x0F120013, + 0x0F123308, + 0x0F12E00A, + 0x0F124870, + 0x0F124971, + 0x0F12380A, + 0x0F1288C0, + 0x0F1200C2, + 0x0F121852, + 0x0F123236, + 0x0F121C40, + 0x0F1200C0, + 0x0F121843, + 0x0F123336, + 0x0F122100, + 0x0F124864, + 0x0F123020, + 0x0F124684, + 0x0F124E69, + 0x0F120048, + 0x0F123E0A, + 0x0F128937, + 0x0F125A15, + 0x0F128976, + 0x0F12437D, + 0x0F125A1F, + 0x0F124377, + 0x0F124E65, + 0x0F1219ED, + 0x0F121986, + 0x0F123660, + 0x0F1289F6, + 0x0F124366, + 0x0F1219AD, + 0x0F12022D, + 0x0F120C2D, + 0x0F12AE04, + 0x0F125235, + 0x0F124666, + 0x0F127C76, + 0x0F124375, + 0x0F129E06, + 0x0F12026D, + 0x0F120C2D, + 0x0F125235, + 0x0F121C49, + 0x0F122904, + 0x0F12D3E1, + 0x0F12B007, + 0x0F12BCF0, + 0x0F12BC08, + 0x0F124718, + 0x0F12B5F8, + 0x0F120004, + 0x0F12F7FF, + 0x0F12FF53, + 0x0F122101, + 0x0F12000D, + 0x0F120020, + 0x0F123810, + 0x0F124081, + 0x0F1240A5, + 0x0F124F4A, + 0x0F12000E, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F1243A8, + 0x0F128038, + 0x0F12E002, + 0x0F128878, + 0x0F1243B0, + 0x0F128078, + 0x0F12F000, + 0x0F12FA5E, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F124328, + 0x0F128038, + 0x0F12E6EC, + 0x0F128878, + 0x0F124330, + 0x0F128078, + 0x0F12E6E8, + 0x0F12B5F8, + 0x0F120004, + 0x0F124F48, + 0x0F124949, + 0x0F1278FA, + 0x0F122001, + 0x0F122A00, + 0x0F12D102, + 0x0F122000, + 0x0F1286C8, + 0x0F12E003, + 0x0F127AFA, + 0x0F122A00, + 0x0F12D000, + 0x0F1286C8, + 0x0F122101, + 0x0F12000D, + 0x0F120020, + 0x0F123810, + 0x0F124081, + 0x0F1240A5, + 0x0F12000E, + 0x0F122C10, + 0x0F12DA04, + 0x0F124932, + 0x0F128808, + 0x0F1243A8, + 0x0F128008, + 0x0F12E003, + 0x0F124930, + 0x0F128848, + 0x0F1243B0, + 0x0F128048, + 0x0F12F000, + 0x0F12FA39, + 0x0F122C10, + 0x0F12DA04, + 0x0F12482C, + 0x0F128801, + 0x0F124329, + 0x0F128001, + 0x0F12E003, + 0x0F124829, + 0x0F128841, + 0x0F124331, + 0x0F128041, + 0x0F124934, + 0x0F128B08, + 0x0F1206C2, + 0x0F12D50A, + 0x0F127ABA, + 0x0F120652, + 0x0F12D507, + 0x0F122210, + 0x0F124390, + 0x0F128308, + 0x0F124830, + 0x0F127AF9, + 0x0F126B00, + 0x0F12F000, + 0x0F12FA27, + 0x0F12481C, + 0x0F123060, + 0x0F1289C0, + 0x0F122800, + 0x0F12D009, + 0x0F1278F8, + 0x0F122800, + 0x0F12D006, + 0x0F127AF8, + 0x0F122800, + 0x0F12D003, + 0x0F127AB8, + 0x0F122140, + 0x0F124308, + 0x0F1272B8, + 0x0F12E69B, + 0x0F12B5F8, + 0x0F120004, + 0x0F124826, + 0x0F128981, + 0x0F122900, + 0x0F12D007, + 0x0F128940, + 0x0F122800, + 0x0F12D104, + 0x0F12481E, + 0x0F1222BF, + 0x0F127A81, + 0x0F124011, + 0x0F127281, + 0x0F122101, + 0x0F12000D, + 0x0F120020, + 0x0F123810, + 0x0F124081, + 0x0F1240A5, + 0x0F124F0E, + 0x0F12000E, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F1243A8, + 0x0F128038, + 0x0F12E002, + 0x0F128878, + 0x0F1243B0, + 0x0F128078, + 0x0F12F000, + 0x0F12F9FE, + 0x0F122C10, + 0x0F12DA2D, + 0x0F128838, + 0x0F124328, + 0x0F128038, + 0x0F12E674, + 0x0F1221C0, + 0x0F127000, + 0x0F124780, + 0x0F127000, + 0x0F122D00, + 0x0F127000, + 0x0F122AD0, + 0x0F127000, + 0x0F120924, + 0x0F127000, + 0x0F121100, + 0x0F12D000, + 0x0F12E300, + 0x0F12D000, + 0x0F1229D0, + 0x0F127000, + 0x0F122C30, + 0x0F127000, + 0x0F125000, + 0x0F12D000, + 0x0F12A006, + 0x0F120000, + 0x0F12A000, + 0x0F12D000, + 0x0F1206F8, + 0x0F127000, + 0x0F120888, + 0x0F127000, + 0x0F1221DA, + 0x0F127000, + 0x0F1208AC, + 0x0F127000, + 0x0F1220BC, + 0x0F127000, + 0x0F121ECC, + 0x0F127000, + 0x0F122FA4, + 0x0F127000, + 0x0F12235C, + 0x0F127000, + 0x0F120234, + 0x0F127000, + 0x0F128878, + 0x0F124330, + 0x0F128078, + 0x0F12E646, + 0x0F12B570, + 0x0F124D99, + 0x0F124C99, + 0x0F128B28, + 0x0F120701, + 0x0F12D507, + 0x0F122108, + 0x0F124388, + 0x0F128328, + 0x0F124997, + 0x0F126B20, + 0x0F1268C9, + 0x0F12F000, + 0x0F12F9C4, + 0x0F128B28, + 0x0F1206C1, + 0x0F12D50A, + 0x0F124994, + 0x0F127A8A, + 0x0F120652, + 0x0F12D406, + 0x0F122210, + 0x0F124390, + 0x0F128328, + 0x0F127AC9, + 0x0F126B20, + 0x0F12F000, + 0x0F12F9A6, + 0x0F12E5DC, + 0x0F12B570, + 0x0F124D8E, + 0x0F124C8F, + 0x0F1288EA, + 0x0F122A14, + 0x0F12D101, + 0x0F122200, + 0x0F1281A2, + 0x0F12F000, + 0x0F12F9B3, + 0x0F1288E8, + 0x0F122821, + 0x0F12D10F, + 0x0F128B28, + 0x0F122800, + 0x0F12D10C, + 0x0F12200C, + 0x0F125E20, + 0x0F128961, + 0x0F124288, + 0x0F12DC07, + 0x0F124882, + 0x0F123880, + 0x0F126B80, + 0x0F12F000, + 0x0F12F9AB, + 0x0F1289A0, + 0x0F121C40, + 0x0F1281A0, + 0x0F12E5BE, + 0x0F12B5F8, + 0x0F120004, + 0x0F122101, + 0x0F12000D, + 0x0F120020, + 0x0F123810, + 0x0F124081, + 0x0F1240A5, + 0x0F124F7E, + 0x0F12000E, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F1243A8, + 0x0F128038, + 0x0F12E002, + 0x0F128878, + 0x0F1243B0, + 0x0F128078, + 0x0F12F000, + 0x0F12F99A, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F124328, + 0x0F128038, + 0x0F12E002, + 0x0F128878, + 0x0F124330, + 0x0F128078, + 0x0F124874, + 0x0F128800, + 0x0F120400, + 0x0F12D504, + 0x0F12F000, + 0x0F12F993, + 0x0F12496E, + 0x0F122012, + 0x0F1280C8, + 0x0F12E5E3, + 0x0F12B570, + 0x0F124E6A, + 0x0F128881, + 0x0F1278F2, + 0x0F124D6E, + 0x0F124C6A, + 0x0F122A00, + 0x0F12D005, + 0x0F128A62, + 0x0F121889, + 0x0F128081, + 0x0F128B61, + 0x0F128029, + 0x0F12E004, + 0x0F128A22, + 0x0F121889, + 0x0F128081, + 0x0F128B21, + 0x0F128029, + 0x0F12F000, + 0x0F12F982, + 0x0F1278F0, + 0x0F122800, + 0x0F12D002, + 0x0F128BE0, + 0x0F1282E8, + 0x0F12E57B, + 0x0F128BA0, + 0x0F1282E8, + 0x0F12E578, + 0x0F12B430, + 0x0F12680B, + 0x0F12684D, + 0x0F12688C, + 0x0F1268C8, + 0x0F124A5F, + 0x0F128054, + 0x0F124958, + 0x0F1278CC, + 0x0F124959, + 0x0F122C00, + 0x0F12D003, + 0x0F128A49, + 0x0F121808, + 0x0F128090, + 0x0F12E002, + 0x0F128A09, + 0x0F121808, + 0x0F128090, + 0x0F1280D3, + 0x0F128115, + 0x0F12BC30, + 0x0F124770, + 0x0F12B5F3, + 0x0F120004, + 0x0F12B081, + 0x0F129802, + 0x0F126800, + 0x0F120600, + 0x0F120E00, + 0x0F122201, + 0x0F120015, + 0x0F120021, + 0x0F123910, + 0x0F12408A, + 0x0F1240A5, + 0x0F124F4D, + 0x0F120016, + 0x0F122C10, + 0x0F12DA03, + 0x0F128839, + 0x0F1243A9, + 0x0F128039, + 0x0F12E002, + 0x0F128879, + 0x0F1243B1, + 0x0F128079, + 0x0F12F000, + 0x0F12F950, + 0x0F122C10, + 0x0F12DA03, + 0x0F128839, + 0x0F124329, + 0x0F128039, + 0x0F12E002, + 0x0F128879, + 0x0F124331, + 0x0F128079, + 0x0F124946, + 0x0F128809, + 0x0F122900, + 0x0F12D102, + 0x0F12F000, + 0x0F12F949, + 0x0F122000, + 0x0F129902, + 0x0F126008, + 0x0F12BCFE, + 0x0F12BC08, + 0x0F124718, + 0x0F12B538, + 0x0F124C40, + 0x0F1289E5, + 0x0F12F000, + 0x0F12F946, + 0x0F121FE8, + 0x0F1238FD, + 0x0F12D132, + 0x0F1289E0, + 0x0F121FC1, + 0x0F1239FF, + 0x0F12D12E, + 0x0F12483C, + 0x0F1269E1, + 0x0F126840, + 0x0F121809, + 0x0F120200, + 0x0F12F000, + 0x0F12F8BA, + 0x0F120400, + 0x0F120C00, + 0x0F124A38, + 0x0F122305, + 0x0F120011, + 0x0F123114, + 0x0F12F000, + 0x0F12F938, + 0x0F120002, + 0x0F1266E0, + 0x0F124D34, + 0x0F128CE0, + 0x0F123D14, + 0x0F1289E9, + 0x0F12F000, + 0x0F12F88A, + 0x0F12466B, + 0x0F128018, + 0x0F128A29, + 0x0F128D20, + 0x0F126EE2, + 0x0F12F000, + 0x0F12F883, + 0x0F12466B, + 0x0F128058, + 0x0F120021, + 0x0F129800, + 0x0F123170, + 0x0F12F000, + 0x0F12F92A, + 0x0F120020, + 0x0F123060, + 0x0F128A02, + 0x0F124928, + 0x0F123980, + 0x0F12808A, + 0x0F128A42, + 0x0F1280CA, + 0x0F128A80, + 0x0F128108, + 0x0F12BC38, + 0x0F12BC08, + 0x0F124718, + 0x0F12B5F8, + 0x0F120004, + 0x0F126808, + 0x0F120400, + 0x0F120C00, + 0x0F122201, + 0x0F120015, + 0x0F120021, + 0x0F123910, + 0x0F12408A, + 0x0F1240A5, + 0x0F124F17, + 0x0F120016, + 0x0F122C10, + 0x0F12DA03, + 0x0F128839, + 0x0F1243A9, + 0x0F128039, + 0x0F12E002, + 0x0F128879, + 0x0F1243B1, + 0x0F128079, + 0x0F12F000, + 0x0F12F90D, + 0x0F122C10, + 0x0F12DA03, + 0x0F128838, + 0x0F124328, + 0x0F128038, + 0x0F12E002, + 0x0F128878, + 0x0F124330, + 0x0F128078, + 0x0F12480D, + 0x0F128800, + 0x0F120400, + 0x0F12D507, + 0x0F124B12, + 0x0F127819, + 0x0F124A12, + 0x0F127810, + 0x0F127018, + 0x0F127011, + 0x0F124905, + 0x0F128188, + 0x0F12E513, + 0x0F120000, + 0x0F122FA4, + 0x0F127000, + 0x0F12235C, + 0x0F127000, + 0x0F120140, + 0x0F127000, + 0x0F1220BC, + 0x0F127000, + 0x0F122DF0, + 0x0F127000, + 0x0F1247E0, + 0x0F127000, + 0x0F121100, + 0x0F12D000, + 0x0F122EE2, + 0x0F127000, + 0x0F12F400, + 0x0F12D000, + 0x0F123200, + 0x0F12D000, + 0x0F1216DE, + 0x0F127000, + 0x0F1236F8, + 0x0F127000, + 0x0F122B90, + 0x0F127000, + 0x0F1217B4, + 0x0F127000, + 0x0F122EDD, + 0x0F127000, + 0x0F122EDE, + 0x0F127000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F1213D5, + 0x0F120001, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12A083, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12A035, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12A1D9, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F122D27, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F127D47, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F127AB1, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F127ACB, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12F004, + 0x0F12E51F, + 0x0F122630, + 0x0F120001, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12ED4D, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12EDDB, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F124EB5, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12053B, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F1249D1, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12D411, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F121E57, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F122603, + 0x0F120001, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12BC3D, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F122601, + 0x0F120001, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12BAB1, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12B89F, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12F077, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12C10D, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12C0C9, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12EAF9, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F122E61, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12E86B, + 0x0F120000, + 0x0F124778, + 0x0F1246C0, + 0x0F12C000, + 0x0F12E59F, + 0x0F12FF1C, + 0x0F12E12F, + 0x0F12B231, + 0x0F120000, + /* End of Patch Data*/ + + /* switch to firmware address bank */ + 0x0028D000, + 0x002A1000, + 0x0F120001, + /* End of factory settings*/ + + /* Switch to sw address bank */ + 0x00287000, + + 0x002A479E, + 0x0F120001, + + 0x002A1432, + 0x0F120000, + + 0x002A47EE, + 0x0F120001, + 0x0F12000A, + 0x0F120014, + 0x0F120070, + 0x0F120005, + 0x0F125A3C, + + 0x002A4780, + 0x0F120000, + 0x0F120014, + 0x0F1200D2, + 0x0F120384, + 0x0F1207D0, + 0x0F121388, + 0x0F120180, + 0x0F120196, + 0x0F120054, + 0x0F120001, + 0x0F1201CC, + 0x0F1201CC, + 0x0F1201CC, + 0x0F1201CC, + 0x0F1201CC, + + 0x002A0EF0, + 0x0F120001, + + 0x002A0EF6, + 0x0F120002, + + 0x002A1A84, + 0x0F12001C, + + 0x002A01F8, + 0x0F120000, + + 0x002A16E4, + 0x0F120100, + + 0x002A01FA, + 0x0F120003, + 0x0F120000, + + 0x002A0200, + 0x0F120061, + + 0x002A0208, + 0x0F122F0C, + 0x0F120190, + + 0x002A028E, + 0x0F120100, + 0x0F1200E3, + 0x0F120200, + 0x0F120238, + 0x0F1201C6, + 0x0F120166, + 0x0F120074, + 0x0F120132, + 0x0F120001, + + 0x002A0702, + 0x0F1200FF, + + 0x002A1600, + 0x0F120000, + + 0x002A0712, + 0x0F120001, + + 0x002A160C, + 0x0F129002, + + 0x002A1616, + 0x0F120003, + + 0x002A15A4, + 0x0F120902, + + 0x002A1618, + 0x0F120000, + + 0x002A1610, + 0x0F120003, + + 0x002A1602, + 0x0F1200E5, + 0x0F120098, + + 0x002A1598, + 0x0F120000, + 0x0F12D000, + + 0x002A165E, + 0x0F12FF95, + + 0x002A162E, + 0x0F120280, + + 0x002A163A, + 0x0F1203A0, + 0x0F120320, + + 0x002A1680, + 0x0F120030, + + 0x002A16A4, + 0x0F120060, + + 0x002A1698, + 0x0F120010, + + 0x002A161A, + 0x0F120000, + + 0x002A15AA, + 0x0F12003C, + 0x0F120018, + 0x0F12002A, + 0x0F120030, + 0x0F120036, + 0x0F12003C, + 0x0F120042, + 0x0F120048, + 0x0F12004E, + 0x0F120054, + 0x0F12005A, + 0x0F120060, + 0x0F120066, + 0x0F12006C, + 0x0F120072, + 0x0F120078, + 0x0F12007E, + 0x0F120084, + 0x0F12008A, + 0x0F120090, + 0x0F120096, + 0x0F12009C, + 0x0F1200A2, + 0x0F1200A8, + 0x0F1200AE, + 0x0F1200B4, + 0x0F1200BA, + + 0x002A16E6, + 0x0F128000, + 0x0F120006, + 0x0F123FF0, + 0x0F1203E8, + 0x0F120000, + 0x0F120080, + 0x0F120009, + 0x0F120020, + 0x0F120040, + 0x0F120080, + 0x0F1200C0, + 0x0F1200E0, + + 0x002A0286, + 0x0F120003, + + 0x002A11B4, + 0x0F12012C, + 0x0F120121, + + 0x002A1A00, + 0x0F12192E, + 0x0F127000, + + 0x002A185C, + 0x0F120004, + 0x0F1209D1, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F1209D5, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F1209D5, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F120326, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F1209D1, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F1209D5, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F120327, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F120084, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F12008D, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F1202AA, + 0x0F120000, + 0x0F120000, + 0x0F1200AA, + 0x0F1202AA, + 0x0F1203AD, + 0x0F1209CD, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202AE, + 0x0F1202DE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202BE, + 0x0F1202EE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202CE, + 0x0F1202EE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F120009, + 0x0F120095, + 0x0F1209DB, + 0x0F120000, + 0x0F120000, + 0x0F120096, + 0x0F12009B, + 0x0F1202AE, + 0x0F1202B3, + 0x0F1209D1, + 0x0F1209D6, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202AE, + 0x0F120000, + 0x0F120000, + 0x0F120009, + 0x0F120010, + 0x0F120327, + 0x0F120336, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120004, + 0x0F1205B6, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F120007, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F12024E, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F1205B6, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F12024F, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120075, + 0x0F1200CF, + 0x0F120000, + 0x0F120000, + 0x0F120075, + 0x0F1200D6, + 0x0F120000, + 0x0F120000, + 0x0F120004, + 0x0F1201F4, + 0x0F120000, + 0x0F120000, + 0x0F1200F0, + 0x0F1201F4, + 0x0F12029E, + 0x0F1205B2, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1201F8, + 0x0F120228, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120208, + 0x0F120238, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120218, + 0x0F120238, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F120009, + 0x0F1200DE, + 0x0F1205C0, + 0x0F120000, + 0x0F120000, + 0x0F1200DF, + 0x0F1200E4, + 0x0F1201F8, + 0x0F1201FD, + 0x0F1205B6, + 0x0F1205BB, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1201F8, + 0x0F120000, + 0x0F120000, + 0x0F120077, + 0x0F12007E, + 0x0F12024F, + 0x0F12025E, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x002A1836, + 0x0F120002, + 0x0F120000, + 0x0F120003, + + 0x002A183E, + 0x0F120FB0, + + 0x002A184C, + 0x0F120060, + 0x0F120060, + 0x0F1205C0, + 0x0F1205C0, + + 0x002A1A8A, + 0x0F128080, + 0x0F120080, + + 0x002A1A80, + 0x0F120000, + + 0x002A1A12, + 0x0F120000, + + 0x002A1842, + 0x0F120004, + + 0x002A1A0A, + 0x0F12009A, + + 0x002A3776, + 0x0F12024C, + + 0x002A0EB2, + 0x0F120000, + + 0x002A08C6, + 0x0F120001, + + 0x002A08A4, + 0x0F120001, + + 0x002A08E2, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124500, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x002A08E0, + 0x0F120001, + + 0x002A1456, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120202, + 0x0F120202, + 0x0F120102, + + 0x002A1448, + 0x0F12003C, + + 0x002A144E, + 0x0F12000F, + + 0x002A0580, + 0x0F123520, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F120470, + 0x0F120C00, + 0x0F120100, + 0x0F121000, + + 0x002A0538, + 0x0F120111, + 0x0F1200EF, + + 0x002A05FC, + 0x0F120000, + 0x0F120001, + 0x0F120600, + 0x0F120100, + 0x0F120001, + 0x0F120000, + 0x0F120A3C, + 0x0F120000, + 0x0F120D04, + 0x0F120000, + 0x0F124008, + 0x0F120000, + 0x0F127000, + 0x0F120000, + 0x0F129C00, + 0x0F120000, + 0x0F12AD00, + 0x0F120001, + 0x0F12F1D4, + 0x0F120002, + 0x0F12DC00, + 0x0F120005, + 0x0F12DC00, + 0x0F120005, + 0x0F120001, + 0x0F120000, + 0x0F120A3C, + 0x0F120000, + 0x0F120D05, + 0x0F120000, + 0x0F123408, + 0x0F120000, + 0x0F123408, + 0x0F120000, + 0x0F126810, + 0x0F120000, + 0x0F128214, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F120650, + 0x0F120100, + + 0x002A06AC, + 0x0F12452C, + 0x0F120004, + + 0x002A0280, + 0x0F120001, + + 0x002A05C4, + 0x0F120000, + + 0x002A0476, + 0x0F120001, + 0x0F120280, + 0x0F1201E0, + 0x0F120005, + + 0x002A01F4, + 0x0F125DC0, + + 0x002A020E, + 0x0F120002, + 0x0F120000, + 0x0F120000, + + 0x002A0216, + 0x0F123A98, + 0x0F124F1A, + 0x0F124F1A, + 0x0F124F1A, + 0x0F124F1A, + 0x0F124F1A, + + 0x002A0228, + 0x0F120001, + + 0x002A02A0, + 0x0F120280, + 0x0F1201E0, + 0x0F120005, + 0x0F124F1A, + 0x0F124F1A, + + 0x002A02AE, + 0x0F120052, + + 0x002A02B6, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + + 0x002A02AA, + 0x0F120080, + + 0x002A024C, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + + 0x002A048E, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + + 0x002A025E, + 0x0F120001, + 0x0F120001, + + 0x002A0392, + 0x0F120A00, + 0x0F120780, + 0x0F120009, + 0x0F124F1A, + 0x0F124F1A, + + 0x002A03A0, + 0x0F120002, + + 0x002A03A8, + 0x0F120001, + 0x0F120000, + 0x0F120002, + 0x0F120535, + 0x0F12029A, + + 0x002A039C, + 0x0F120080, + + 0x002A0476, + 0x0F120001, + 0x0F120280, + 0x0F1201E0, + 0x0F120005, + + 0x002A0262, + 0x0F120000, + + 0x002A0266, + 0x0F120001, + + 0x002A024A, + 0x0F120001, + + 0x002A0264, + 0x0F120001, + + 0x002A026C, + 0x0F120001, + + 0x002A023A, + 0x0F120001, + 0x0F120001, + + 0x002A0472, + 0x0F12005F, + 0x0F12005F, + + 0x002A0FE0, + 0x0F1203B8, + 0x0F1203CE, + 0x0F120350, + 0x0F1203C4, + 0x0F1202F2, + 0x0F120394, + 0x0F1202C0, + 0x0F120364, + 0x0F12029E, + 0x0F120334, + 0x0F12027C, + 0x0F120312, + 0x0F12025E, + 0x0F1202F2, + 0x0F120246, + 0x0F1202D0, + 0x0F120230, + 0x0F1202B0, + 0x0F120218, + 0x0F12029E, + 0x0F120208, + 0x0F120290, + 0x0F1201F8, + 0x0F120284, + 0x0F1201E8, + 0x0F120276, + 0x0F1201DA, + 0x0F12026A, + 0x0F1201CE, + 0x0F12025E, + 0x0F1201EC, + 0x0F12022E, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120005, + + 0x002A1034, + 0x0F120010, + + 0x002A1038, + 0x0F120126, + + 0x002A103C, + 0x0F12026C, + 0x0F12029A, + 0x0F12025C, + 0x0F1202B6, + 0x0F12024E, + 0x0F1202C0, + 0x0F120240, + 0x0F1202BE, + 0x0F12023A, + 0x0F1202B4, + 0x0F12023A, + 0x0F1202AA, + 0x0F120240, + 0x0F12029E, + 0x0F12025C, + 0x0F120294, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120004, + + 0x002A1070, + 0x0F120008, + + 0x002A1074, + 0x0F1201E2, + + 0x002A1078, + 0x0F120350, + 0x0F120422, + 0x0F1202C4, + 0x0F120452, + 0x0F120278, + 0x0F12041C, + 0x0F120230, + 0x0F1203EE, + 0x0F1201F0, + 0x0F120392, + 0x0F1201C0, + 0x0F120340, + 0x0F120194, + 0x0F120302, + 0x0F12016E, + 0x0F1202C2, + 0x0F120148, + 0x0F120286, + 0x0F12018A, + 0x0F120242, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120006, + + 0x002A10AC, + 0x0F12000A, + + 0x002A10B0, + 0x0F120106, + + 0x002A10B4, + 0x0F120380, + 0x0F120000, + 0x0F120168, + 0x0F120000, + 0x0F122D90, + 0x0F120000, + + 0x002A1428, + 0x0F120008, + 0x0F120190, + 0x0F1200A0, + + 0x002A11EC, + 0x0F1200C0, + + 0x002A11F0, + 0x0F120010, + + 0x002A11EE, + 0x0F120010, + + 0x002A11CE, + 0x0F1205D5, + + 0x002A11D2, + 0x0F120000, + 0x0F120771, + 0x0F1203A4, + 0x0F120036, + 0x0F12002A, + + 0x002A08AC, + 0x0F1200C0, + 0x0F1200DF, + 0x0F120100, + 0x0F120125, + 0x0F12015F, + 0x0F12017C, + 0x0F120194, + + 0x002A123C, + 0x0F12FEF7, + 0x0F120021, + 0x0F120E74, + 0x0F120E74, + 0x0F12018F, + 0x0F120096, + 0x0F12000E, + + 0x002A11E8, + 0x0F120032, + 0x0F12001E, + + 0x002A2ABC, + 0x0F120006, + + 0x002A1430, + 0x0F120002, + + 0x002A140A, + 0x0F1200AB, + 0x0F1200BF, + 0x0F1200D2, + 0x0F120093, + + 0x002A13F8, + 0x0F120300, + 0x0F12036E, + 0x0F1203C2, + 0x0F121015, + 0x0F1210E1, + 0x0F121154, + 0x0F1211A8, + 0x0F1211BB, + 0x0F12123B, + + 0x002A1368, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F120030, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F120030, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F120030, + 0x0F12FFE0, + 0x0F12FFE0, + 0x0F12FFC0, + 0x0F12FFC0, + 0x0F12FFA0, + 0x0F12FE36, + 0x0F12FFE0, + 0x0F12FFE0, + 0x0F12FFC0, + 0x0F12FFC0, + 0x0F12FFA0, + 0x0F12FE36, + 0x0F12FFE0, + 0x0F12FFE0, + 0x0F12FFC0, + 0x0F12FFC0, + 0x0F12FFA0, + 0x0F12FE36, + 0x0F12FFEA, + 0x0F12FFEA, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFEA, + 0x0F12FFEA, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFEA, + 0x0F12FFEA, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F12FFC8, + 0x0F120014, + 0x0F120014, + 0x0F120014, + 0x0F12FDA0, + 0x0F12FCF0, + 0x0F12FCD0, + 0x0F120014, + 0x0F120014, + 0x0F120014, + 0x0F12FDA0, + 0x0F12FCF0, + 0x0F12FCD0, + 0x0F120014, + 0x0F120014, + 0x0F120014, + 0x0F12FDA0, + 0x0F12FCF0, + 0x0F12FCD0, + + 0x002A13FE, + 0x0F121015, + 0x0F12106C, + 0x0F1210CA, + 0x0F121142, + 0x0F1211BB, + 0x0F12123B, + 0x0F1200AB, + 0x0F1200BF, + 0x0F1200D2, + 0x0F120093, + + 0x002A11CC, + 0x0F120020, + + 0x002A1412, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x002A0724, + 0x0F120001, + 0x0F120007, + 0x0F120010, + 0x0F120028, + 0x0F120062, + 0x0F1200D3, + 0x0F120130, + 0x0F120158, + 0x0F12017D, + 0x0F1201BE, + 0x0F1201F8, + 0x0F12022C, + 0x0F12025B, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + 0x0F120001, + 0x0F120007, + 0x0F120010, + 0x0F120028, + 0x0F120062, + 0x0F1200D3, + 0x0F120130, + 0x0F120158, + 0x0F12017D, + 0x0F1201BE, + 0x0F1201F8, + 0x0F12022C, + 0x0F12025B, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + 0x0F120001, + 0x0F120007, + 0x0F120010, + 0x0F120028, + 0x0F120062, + 0x0F1200D3, + 0x0F120130, + 0x0F120158, + 0x0F12017D, + 0x0F1201BE, + 0x0F1201F8, + 0x0F12022C, + 0x0F12025B, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + 0x0F120000, + 0x0F12000F, + 0x0F120020, + 0x0F120043, + 0x0F120086, + 0x0F1200ED, + 0x0F12013E, + 0x0F120163, + 0x0F120185, + 0x0F1201BF, + 0x0F1201F2, + 0x0F120221, + 0x0F12024A, + 0x0F120294, + 0x0F1202D0, + 0x0F12032A, + 0x0F12036A, + 0x0F12039F, + 0x0F1203CC, + 0x0F1203F9, + 0x0F120000, + 0x0F12000F, + 0x0F120020, + 0x0F120043, + 0x0F120086, + 0x0F1200ED, + 0x0F12013E, + 0x0F120163, + 0x0F120185, + 0x0F1201BF, + 0x0F1201F2, + 0x0F120221, + 0x0F12024A, + 0x0F120294, + 0x0F1202D0, + 0x0F12032A, + 0x0F12036A, + 0x0F12039F, + 0x0F1203CC, + 0x0F1203F9, + 0x0F120000, + 0x0F12000F, + 0x0F120020, + 0x0F120043, + 0x0F120086, + 0x0F1200ED, + 0x0F12013E, + 0x0F120163, + 0x0F120185, + 0x0F1201BF, + 0x0F1201F2, + 0x0F120221, + 0x0F12024A, + 0x0F120294, + 0x0F1202D0, + 0x0F12032A, + 0x0F12036A, + 0x0F12039F, + 0x0F1203CC, + 0x0F1203F9, + + 0x002A0896, + 0x0F1200C0, + 0x0F120100, + 0x0F120125, + 0x0F12015F, + 0x0F12017C, + 0x0F120194, + 0x0F120001, + + 0x002A0888, + 0x0F124800, + 0x0F127000, + + 0x002A4800, + 0x0F12016C, + 0x0F12FF94, + 0x0F12FFCE, + 0x0F12FF20, + 0x0F1201BF, + 0x0F12FF53, + 0x0F12003F, + 0x0F120007, + 0x0F1201DF, + 0x0F120110, + 0x0F1200DF, + 0x0F12FF47, + 0x0F120206, + 0x0F12FF7F, + 0x0F120191, + 0x0F12FF06, + 0x0F1201BA, + 0x0F120108, + 0x0F12016C, + 0x0F12FF94, + 0x0F12FFCE, + 0x0F12FF20, + 0x0F1201BF, + 0x0F12FF53, + 0x0F12003F, + 0x0F120007, + 0x0F1201DF, + 0x0F120110, + 0x0F1200DF, + 0x0F12FF47, + 0x0F120206, + 0x0F12FF7F, + 0x0F120191, + 0x0F12FF06, + 0x0F1201BA, + 0x0F120108, + 0x0F12016C, + 0x0F12FF94, + 0x0F12FFCE, + 0x0F12FF20, + 0x0F1201BF, + 0x0F12FF53, + 0x0F12003F, + 0x0F120007, + 0x0F1201DF, + 0x0F120110, + 0x0F1200DF, + 0x0F12FF47, + 0x0F120206, + 0x0F12FF7F, + 0x0F120191, + 0x0F12FF06, + 0x0F1201BA, + 0x0F120108, + 0x0F120208, + 0x0F12FFD3, + 0x0F12FFE9, + 0x0F12FF5B, + 0x0F12025A, + 0x0F12FF80, + 0x0F12FFC8, + 0x0F12FFC1, + 0x0F12013A, + 0x0F120112, + 0x0F1200EE, + 0x0F12FF99, + 0x0F12009E, + 0x0F12FF5F, + 0x0F1201A8, + 0x0F12FF75, + 0x0F120187, + 0x0F1201BF, + 0x0F120208, + 0x0F12FFD3, + 0x0F12FFE9, + 0x0F12FF5B, + 0x0F12025A, + 0x0F12FF80, + 0x0F12FFC8, + 0x0F12FFC1, + 0x0F12013A, + 0x0F120112, + 0x0F1200EE, + 0x0F12FF99, + 0x0F12009E, + 0x0F12FF5F, + 0x0F1201A8, + 0x0F12FF75, + 0x0F120187, + 0x0F1201BF, + 0x0F120208, + 0x0F12FFD3, + 0x0F12FFE9, + 0x0F12FF5B, + 0x0F12025A, + 0x0F12FF80, + 0x0F12FFC8, + 0x0F12FFC1, + 0x0F12013A, + 0x0F120112, + 0x0F1200EE, + 0x0F12FF99, + 0x0F12009E, + 0x0F12FF5F, + 0x0F1201A8, + 0x0F12FF75, + 0x0F120187, + 0x0F1201BF, + + 0x002A0890, + 0x0F1248D8, + 0x0F127000, + + 0x002A48D8, + 0x0F1201AA, + 0x0F12FFB6, + 0x0F12FFD4, + 0x0F12FF6C, + 0x0F1201E8, + 0x0F12FF79, + 0x0F120000, + 0x0F12FFF5, + 0x0F12023C, + 0x0F1200BF, + 0x0F1200E0, + 0x0F12FF5B, + 0x0F12022D, + 0x0F12FF9B, + 0x0F1201E1, + 0x0F12FF34, + 0x0F12014B, + 0x0F1201B6, + + 0x002A0924, + 0x0F120050, + 0x0F1200B0, + 0x0F120196, + 0x0F120245, + 0x0F120300, + + 0x002A0958, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120032, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120040, + 0x0F1200A0, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F123604, + 0x0F12032A, + 0x0F120403, + 0x0F121B06, + 0x0F126015, + 0x0F1200C0, + 0x0F126080, + 0x0F124080, + 0x0F120640, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120000, + 0x0F120400, + 0x0F12365A, + 0x0F12102A, + 0x0F12000B, + 0x0F120600, + 0x0F125A0F, + 0x0F120505, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123028, + 0x0F120418, + 0x0F120101, + 0x0F120800, + 0x0F121804, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120205, + 0x0F120304, + 0x0F120409, + 0x0F120306, + 0x0F120407, + 0x0F121C04, + 0x0F120214, + 0x0F121002, + 0x0F120610, + 0x0F120F02, + 0x0F124A18, + 0x0F120080, + 0x0F120040, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F122A36, + 0x0F126024, + 0x0F122A36, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F123601, + 0x0F12242A, + 0x0F123660, + 0x0F12FF2A, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120032, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F122404, + 0x0F12031B, + 0x0F120103, + 0x0F121205, + 0x0F12400D, + 0x0F120080, + 0x0F122080, + 0x0F123040, + 0x0F120630, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120300, + 0x0F12245A, + 0x0F121018, + 0x0F12000B, + 0x0F120B00, + 0x0F125A0F, + 0x0F120505, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123428, + 0x0F12041C, + 0x0F120101, + 0x0F120800, + 0x0F121004, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120205, + 0x0F120304, + 0x0F120409, + 0x0F120306, + 0x0F120407, + 0x0F121F04, + 0x0F120218, + 0x0F121102, + 0x0F120611, + 0x0F121002, + 0x0F128018, + 0x0F120080, + 0x0F120080, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F121B24, + 0x0F126024, + 0x0F121010, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F122401, + 0x0F12241B, + 0x0F121E60, + 0x0F12FF18, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120032, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F121B04, + 0x0F120312, + 0x0F120003, + 0x0F120C03, + 0x0F122806, + 0x0F120060, + 0x0F121580, + 0x0F122020, + 0x0F120620, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120300, + 0x0F12145A, + 0x0F121010, + 0x0F12000B, + 0x0F120E00, + 0x0F125A0F, + 0x0F120504, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123828, + 0x0F120428, + 0x0F120101, + 0x0F128000, + 0x0F120A04, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120207, + 0x0F120304, + 0x0F120409, + 0x0F120306, + 0x0F120407, + 0x0F122404, + 0x0F120221, + 0x0F121202, + 0x0F120613, + 0x0F121202, + 0x0F128018, + 0x0F120080, + 0x0F120080, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F12121B, + 0x0F126024, + 0x0F120C0C, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F121B01, + 0x0F122412, + 0x0F120C60, + 0x0F12FF0C, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120032, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F121504, + 0x0F12030F, + 0x0F120003, + 0x0F120902, + 0x0F122004, + 0x0F120050, + 0x0F121140, + 0x0F12201C, + 0x0F120620, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120300, + 0x0F12145A, + 0x0F121010, + 0x0F12000B, + 0x0F121000, + 0x0F125A0F, + 0x0F120503, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123C28, + 0x0F12042C, + 0x0F120101, + 0x0F12FF00, + 0x0F120904, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120206, + 0x0F120304, + 0x0F120409, + 0x0F120305, + 0x0F120406, + 0x0F122804, + 0x0F120228, + 0x0F121402, + 0x0F120618, + 0x0F121402, + 0x0F128018, + 0x0F120080, + 0x0F120080, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F120F15, + 0x0F126024, + 0x0F120A0A, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F121501, + 0x0F12240F, + 0x0F120A60, + 0x0F12FF0A, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120032, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F120F04, + 0x0F12030C, + 0x0F120003, + 0x0F120602, + 0x0F121803, + 0x0F120040, + 0x0F120E20, + 0x0F122018, + 0x0F120620, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120200, + 0x0F12145A, + 0x0F121010, + 0x0F12000B, + 0x0F121200, + 0x0F125A0F, + 0x0F120502, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F124028, + 0x0F120430, + 0x0F120101, + 0x0F12FF00, + 0x0F120804, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120205, + 0x0F120304, + 0x0F120409, + 0x0F120306, + 0x0F120407, + 0x0F122C04, + 0x0F12022C, + 0x0F121402, + 0x0F120618, + 0x0F121402, + 0x0F128018, + 0x0F120080, + 0x0F120080, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F120C0F, + 0x0F126024, + 0x0F120808, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F120F01, + 0x0F12240C, + 0x0F120860, + 0x0F12FF08, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F1223CE, + 0x0F12FDC8, + 0x0F12112E, + 0x0F1293A5, + 0x0F12FE67, + 0x0F120000, + + 0xFCFCD000, + 0x00287000, + 0x002A01A2, + 0x0F120A0A, + + 0xFCFCD000, + 0x00040001, +}; + +static const u32 s5k4ecgx_DTP_init_v1[] = { + 0x0028D000, + 0x002AB054, + 0x0F120001, + 0x00287000, +}; + +static const u32 s5k4ecgx_DTP_stop_v1[] = { + 0x0028D000, + 0x002AB054, + 0x0F120000, + 0x00287000, +}; + +static const u32 s5k4ecgx_Effect_Normal_v1[] = { + 0x002A0238, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Effect_Negative_v1[] = { + 0x002A0238, + 0x0F120003, +}; + +static const u32 s5k4ecgx_Effect_Sepia_v1[] = { + 0x002A0238, + 0x0F120004, +}; + +static const u32 s5k4ecgx_Effect_Black_White_v1[] = { + 0x002A0238, + 0x0F120001, +}; + +static const u32 s5k4ecgx_WB_Auto_v1[] = { + 0x002a04E0, + 0x0f12077F, +}; + +static const u32 s5k4ecgx_WB_Sunny_v1[] = { + 0x002a04E0, + 0x0f120777, + 0x002a04B4, + 0x0f1205E0, + 0x0f120001, + 0x0f120400, + 0x0f120001, + 0x0f120530, + 0x0f120001, + 0x0f120001, +}; + +static const u32 s5k4ecgx_WB_Cloudy_v1[] = { + 0x002a04E0, + 0x0f120777, + 0x002a04B4,/* USER RGB Gain */ + 0x0f120710,/* R */ + 0x0f120001,/* Changed */ + 0x0f120400,/* G */ + 0x0f120001, + 0x0f120420,/* B 480-reference */ + 0x0f120001, + 0x0f120001, +}; + +static const u32 s5k4ecgx_WB_Tungsten_v1[] = { + 0x002a04E0, + 0x0f120777, + 0x002a04B4, + 0x0f120390, + 0x0f120001, + 0x0f120400, + 0x0f120001, + 0x0f120920, + 0x0f120001, + 0x0f120001, +}; + +static const u32 s5k4ecgx_WB_Fluorescent_v1[] = { + 0x002a04E0, + 0x0f120777, + 0x002a04B4, + 0x0f120505, + 0x0f120001, + 0x0f120400, + 0x0f120001, + 0x0f120875, + 0x0f120001, + 0x0f120001, +}; + +static const u32 s5k4ecgx_WDR_on_v1[] = { + 0x002A1B4A, + 0x0F120000, +}; + +static const u32 s5k4ecgx_WDR_off_v1[] = { + 0x002A1B4A, + 0x0F120001, +}; + +static const u32 s5k4ecgx_ISO_Auto_v1[] = { + 0x002A4780, + 0x0F120000, + + 0x002A0EF0, + 0x0F120001, + 0x002A04E0, + 0x0F12077F, + 0x002A04CA, + 0x0F120000, + + 0x002A04CA, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x002A06B6, + 0x0F120200, +}; + +static const u32 s5k4ecgx_ISO_100_v1[] = { + 0x002A04E0, + 0x0F12065F, + 0x002A04D0, + 0x0F120000, + 0x0F120001, + + 0x002A04CA, + 0x0F120001, + 0x0F1201A0, + 0x0F120001, + 0x002A06B6, + 0x0F120100, + + 0x002A4780, + 0x0F120001, +}; + +static const u32 s5k4ecgx_ISO_200_v1[] = { + 0x002A04E0, + 0x0F12065F, + 0x002A04D0, + 0x0F120000, + 0x0F120001, + + 0x002A04CA, + 0x0F120001, + 0x0F120340, + 0x0F120001, + 0x002A06B6, + 0x0F120100, + + 0x002A4780, + 0x0F120001, +}; + +static const u32 s5k4ecgx_ISO_400_v1[] = { + 0x002A04E0, + 0x0F12065F, + 0x002A04D0, + 0x0F120000, + 0x0F120001, + + 0x002A04CA, + 0x0F120001, + 0x0F120680, + 0x0F120001, + 0x002A06B6, + 0x0F120100, + + 0x002A4780, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Metering_Matrix_v1[] = { + 0x002A1456, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, +}; + +static const u32 s5k4ecgx_Metering_Center_v1[] = { + 0x002A1456, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120202, + 0x0F120202, + 0x0F120102, +}; + +static const u32 s5k4ecgx_Metering_Spot_v1[] = { + 0x002A1456, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120101, + 0x0f120101, + 0x0f120000, + 0x0f120000, + 0x0f12010f, + 0x0f120f01, + 0x0f120000, + 0x0f120000, + 0x0f12010f, + 0x0f120f01, + 0x0f120000, + 0x0f120000, + 0x0f120101, + 0x0f120101, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, + 0x0f120000, +}; + +static const u32 s5k4ecgx_EV_Minus_4_v1[] = { + 0x002A022C, + 0x0F12FF30, +}; + +static const u32 s5k4ecgx_EV_Minus_3_v1[] = { + 0x002A022C, + 0x0F12FFA0, +}; + +static const u32 s5k4ecgx_EV_Minus_2_v1[] = { + 0x002A022C, + 0x0F12FFC8, +}; + +static const u32 s5k4ecgx_EV_Minus_1_v1[] = { + 0x002A022C, + 0x0F12FFE0, +}; + +static const u32 s5k4ecgx_EV_Default_v1[] = { + 0x002A022C, + 0x0F120000, +}; + +static const u32 s5k4ecgx_EV_Plus_1_v1[] = { + 0x002A022C, + 0x0F120020, +}; + +static const u32 s5k4ecgx_EV_Plus_2_v1[] = { + 0x002A022C, + 0x0F120038, +}; + +static const u32 s5k4ecgx_EV_Plus_3_v1[] = { + 0x002A022C, + 0x0F120060, +}; + +static const u32 s5k4ecgx_EV_Plus_4_v1[] = { + 0x002A022C, + 0x0F12007F, +}; + +static const u32 s5k4ecgx_Contrast_Minus_4_v1[] = { + 0x002A022E, + 0x0F12FF81, +}; + +static const u32 s5k4ecgx_Contrast_Minus_3_v1[] = { + 0x002A022E, + 0x0F12FFA0, +}; + +static const u32 s5k4ecgx_Contrast_Minus_2_v1[] = { + 0x002A022E, + 0x0F12FFC0, +}; + +static const u32 s5k4ecgx_Contrast_Minus_1_v1[] = { + 0x002A022E, + 0x0F12FFE0, +}; + +static const u32 s5k4ecgx_Contrast_Default_v1[] = { + 0x002A022E, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Contrast_Plus_1_v1[] = { + 0x002A022E, + 0x0F120020, +}; + +static const u32 s5k4ecgx_Contrast_Plus_2_v1[] = { + 0x002A022E, + 0x0F120040, +}; + +static const u32 s5k4ecgx_Contrast_Plus_3_v1[] = { + 0x002A022E, + 0x0F120060, +}; + +static const u32 s5k4ecgx_Contrast_Plus_4_v1[] = { + 0x002A022E, + 0x0F12007F, +}; + +static const u32 s5k4ecgx_Sharpness_Minus_3_v1[] = { + 0x002A09F4, + 0x0F120000, + 0x002A0AAA, + 0x0F120000, + 0x002A0B60, + 0x0F120000, + 0x002A0C16, + 0x0F120000, + 0x002A0CCC, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Sharpness_Minus_2_v1[] = { + 0x002A09F4, + 0x0F122010, + 0x002A0AAA, + 0x0F122010, + 0x002A0B60, + 0x0F122010, + 0x002A0C16, + 0x0F122010, + 0x002A0CCC, + 0x0F122010, +}; + +static const u32 s5k4ecgx_Sharpness_Minus_1_v1[] = { + 0x002A09F4, + 0x0F124020, + 0x002A0AAA, + 0x0F124020, + 0x002A0B60, + 0x0F124020, + 0x002A0C16, + 0x0F124020, + 0x002A0CCC, + 0x0F124020, +}; + +static const u32 s5k4ecgx_Sharpness_Default_v1[] = { + 0x002A09F4, + 0x0F126024, + 0x002A0AAA, + 0x0F126024, + 0x002A0B60, + 0x0F126024, + 0x002A0C16, + 0x0F126024, + 0x002A0CCC, + 0x0F126024, +}; + +static const u32 s5k4ecgx_Sharpness_Plus_1_v1[] = { + 0x002A09F4, + 0x0F128040, + 0x002A0AAA, + 0x0F128040, + 0x002A0B60, + 0x0F128040, + 0x002A0C16, + 0x0F128040, + 0x002A0CCC, + 0x0F128040, +}; + +static const u32 s5k4ecgx_Sharpness_Plus_2_v1[] = { + 0x002A09F4, + 0x0F12A060, + 0x002A0AAA, + 0x0F12A060, + 0x002A0B60, + 0x0F12A060, + 0x002A0C16, + 0x0F12A060, + 0x002A0CCC, + 0x0F12A060, +}; + +static const u32 s5k4ecgx_Sharpness_Plus_3_v1[] = { + 0x002A09F4, + 0x0F12C080, + 0x002A0AAA, + 0x0F12C080, + 0x002A0B60, + 0x0F12C080, + 0x002A0C16, + 0x0F12C080, + 0x002A0CCC, + 0x0F12C080, +}; + +static const u32 s5k4ecgx_Saturation_Minus_2_v1[] = { + 0x002A0230, + 0x0F12FF81, +}; + +static const u32 s5k4ecgx_Saturation_Minus_1_v1[] = { + 0x002A0230, + 0x0F12FFC0, +}; + +static const u32 s5k4ecgx_Saturation_Default_v1[] = { + 0x002A0230, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Saturation_Plus_1_v1[] = { + 0x002A0230, + 0x0F120040, +}; + +static const u32 s5k4ecgx_Saturation_Plus_2_v1[] = { + 0x002A0230, + 0x0F12007F, +}; + +static const u32 s5k4ecgx_Jpeg_Quality_High_v1[] = { + 0x002A0472, + 0x0F12005F, + 0x0F12005F, +}; + +static const u32 s5k4ecgx_Jpeg_Quality_Normal_v1[] = { + 0x002A0472, + 0x0F120050, + 0x0F120050, +}; + +static const u32 s5k4ecgx_Jpeg_Quality_Low_v1[] = { + 0x002A0472, + 0x0F12004B, + 0x0F12004B, +}; + +static const u32 s5k4ecgx_Scene_Default_v1[] = { + 0x002A1456, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120202, + 0x0F120202, + 0x0F120102, + + 0x002A4780, + 0x0F120000, + + 0x002A06AC, + 0x0F12452C, + 0x0F120004, + + 0x002A0EF0, + 0x0F120001, + 0x002A0EF6, + 0x0F120001, + 0x002A04E0, + 0x0F12077F, + 0x002A04CA, + 0x0F120000, + + 0x002A04CA, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x002A06B6, + 0x0F120200, + + 0x002a2B7E, + 0x0f120001, + + + 0x002A1448, + 0x0F12003C, + 0x002A144E, + 0x0F12000F, + 0x002A0580, + 0x0F123520, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F120470, + 0x0F120C00, + 0x0F120100, + 0x0F121000, + + 0x002A0538, + 0x0F120111, + 0x0F1200EF, + + + 0x002A05FC, + 0x0F120000, + 0x0F120001, + + 0x002A09F4, + 0x0F126024, + 0x002A0AAA, + 0x0F126024, + 0x002A0B60, + 0x0F126024, + 0x002A0C16, + 0x0F126024, + 0x002A0CCC, + 0x0F126024, + + 0x002A0230, + 0x0F120000, + + 0x002A062C, + 0x0F120001, + 0x0F120000, + 0x002A0630, + 0x0F120A3C, + 0x0F120000, + 0x002A0634, + 0x0F120D05, + 0x0F120000, + 0x002A0638, + 0x0F123408, + 0x0F120000, + 0x002A063C, + 0x0F123408, + 0x0F120000, + 0x002A0640, + 0x0F126810, + 0x0F120000, + 0x002A0644, + 0x0F128214, + 0x0F120000, + 0x002A0648, + 0x0F12C350, + 0x0F120000, + 0x002A064C, + 0x0F12C350, + 0x0F120000, + 0x002A0650, + 0x0F12C350, + 0x0F120000, + + 0x002A03AE, + 0x0F120535, + 0x0F12029A, + + + 0x002A0262, + 0x0F120000, + 0x002A0266, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0264, + 0x0F120001, + 0x002A026C, + 0x0F120001, + 0x002A023A, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Portrait_v1[] = { + 0x002A09F4, + 0x0F124020, + 0x002A0AAA, + 0x0F124020, + 0x002A0B60, + 0x0F124020, + 0x002A0C16, + 0x0F124020, + 0x002A0CCC, + 0x0F124020, +}; + +static const u32 s5k4ecgx_Scene_Nightshot_v1[] = { + 0x002A06AC, + 0x0F12FFFF, + 0x0F1200FF, + + 0x002A05FC, + 0x0F120000, + 0x0F120000, + + 0x002A0580, + 0x0F12F424, + 0x0F120001, + 0x0F12F424, + 0x0F120001, + 0x0F12F424, + 0x0F120001, + 0x0F12F424, + 0x0F120001, + 0x0F120100, + 0x0F120700, + 0x0F120100, + 0x0F122000, + + 0x002A03AE, + 0x0F121388, + 0x0F121388, + + 0x002A02BC, + 0x0F1209C4, + 0x0F12014D, + + 0x002A0262, + 0x0F120000, + + 0x002A0266, + 0x0F120001, + + 0x002A024A, + 0x0F120001, + + 0x002A0264, + 0x0F120001, + + 0x002A026C, + 0x0F120001, + + 0x002A023A, + 0x0F120001, + 0x0F120001, + + 0x002A09EA, + 0x0F121580, +}; + +static const u32 s5k4ecgx_Scene_Landscape_v1[] = { + 0x002A1456, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x0f120101, + 0x002A09F4, + 0x0F128040, + 0x002A0AAA, + 0x0F128040, + 0x002A0B60, + 0x0F128040, + 0x002A0C16, + 0x0F128040, + 0x002A0CCC, + 0x0F128040, + 0x002A0230, + 0x0F120040, +}; + +static const u32 s5k4ecgx_Scene_Sports_v1[] = { + 0x002A05FC, + + 0x0F120000, + 0x0F120000, + + 0x002A0580, + 0x0F123520, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F120200, + 0x0F120200, + 0x0F120200, + 0x0F120200, + + 0x002A0262, + 0x0F120000, + 0x002A0266, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0264, + 0x0F120001, + 0x002A026C, + 0x0F120001, + 0x002A023A, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Party_Indoor_v1[] = { + 0x002A04E0, + 0x0F12065F, + 0x002A04D0, + 0x0F120000, + 0x0F120001, + + 0x002A04CA, + 0x0F120001, + 0x0F120340, + 0x0F120001, + 0x002A06B6, + 0x0F120100, + + + 0x002A4780, + 0x0F120001, + + 0x002A0230, + 0x0F120031, +}; + +static const u32 s5k4ecgx_Scene_Beach_Snow_v1[] = { + 0x002A04E0, + 0x0F12065F, + 0x002A04D0, + 0x0F120000, + 0x0F120001, + 0x002A04CA, + 0x0F120001, + 0x0F1200D0, + 0x0F120001, + 0x002A06B6, + 0x0F120100, + + + 0x002A4780, + 0x0F120001, + + 0x002A0230, + 0x0F120031, +}; + +static const u32 s5k4ecgx_Scene_Sunset_v1[] = { + 0x002a2B7E, + 0x0f120000, + + 0x002a04B4, + 0x0f1205E0, + 0x0f120001, + 0x0f120400, + 0x0f120001, + 0x0f120520, + 0x0f120001, +}; + +static const u32 s5k4ecgx_Scene_Duskdawn_v1[] = { + 0x002a2B7E, + 0x0f120000, + + 0x002a04B4, + 0x0f120575, + 0x0f120001, + 0x0f120400, + 0x0f120001, + 0x0f120835, + 0x0f120001, +}; + +static const u32 s5k4ecgx_Scene_Fireworks_v1[] = { + 0x002A062C, + 0x0F120001, + 0x0F120000, + 0x002A0630, + 0x0F121478, + 0x0F120000, + 0x002A0634, + 0x0F121A0A, + 0x0F120000, + 0x002A0638, + 0x0F126810, + 0x0F120000, + 0x002A063C, + 0x0F126810, + 0x0F120000, + 0x002A0640, + 0x0F12D020, + 0x0F120000, + 0x002A0644, + 0x0F120428, + 0x0F120001, + 0x002A0648, + 0x0F121A80, + 0x0F120006, + 0x002A064C, + 0x0F121A80, + 0x0F120006, + 0x002A0650, + 0x0F121A80, + 0x0F120006, + + 0x002A03AE, + 0x0F122710, + 0x0F122710, + + 0x002A0262, + 0x0F120000, + 0x002A0266, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0264, + 0x0F120001, + 0x002A026C, + 0x0F120001, + 0x002A023A, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Candle_Light_v1[] = { + 0x002a04E0, + 0x0f120777, + 0x002a04B4, + 0x0f1205E0, + 0x0f120001, + 0x0f120400, + 0x0f120001, + 0x0f120530, + 0x0f120001, +}; + +static const u32 s5k4ecgx_Night_Capture_v1[] = { + 0x002A09EA, + 0x0F120AAA, + 0x002A0AA0, + 0x0F120AAA, +}; + +static const u32 s5k4ecgx_AF_Return_Macro_pos_v1[] = { + 0x002A15AC, + 0x0F120018, + 0x0F12002A, + 0x0F120030, + 0x0F120036, + 0x0F12003C, + 0x0F120042, + 0x0F120048, + 0x0F12004E, + 0x0F120054, + 0x0F12005A, + 0x0F120060, + 0x0F120066, + 0x0F12006C, + 0x0F120072, + 0x0F120078, + 0x0F12007E, + 0x0F120084, + 0x0F12008A, + 0x0F120090, + 0x0F120096, + 0x0F12009C, + 0x0F1200A2, + 0x0F1200A8, + 0x0F1200AE, + 0x0F1200B4, + 0x0F1200BA, +}; + +static const u32 s5k4ecgx_AF_Normal_mode_1_v1[] = { + 0x002A0288, + 0x0F12002A, +}; + +static const u32 s5k4ecgx_AF_Normal_mode_2_v1[] = { + 0x002A0286, + 0x0F120004, +}; + + +static const u32 s5k4ecgx_AF_Normal_mode_3_v1[] = { + 0x002A160C, + 0x0F129002, +}; + +static const u32 s5k4ecgx_AF_Macro_mode_1_v1[] = { + 0x002A0288, + 0x0F1200D0, +}; + +static const u32 s5k4ecgx_AF_Macro_mode_2_v1[] = { + 0x002A0286, + 0x0F120004, +}; + +static const u32 s5k4ecgx_AF_Macro_mode_3_v1[] = { + 0x002A160C, + 0x0F129042, + 0x002A159E, + 0x0F121800, +}; + +static const u32 s5k4ecgx_AF_Low_Light_Mode_On_v1[] = { + 0x002A1616, + 0x0F120003, + + 0x002A15A4, + 0x0F120902, + + 0x002A159E, + 0x0F120C00, + + 0x002A15AC, + 0x0F12002A, + 0x0F120033, + 0x0F12003C, + 0x0F120045, + 0x0F12004E, + 0x0F120057, + 0x0F120063, + 0x0F12006F, + 0x0F12007B, + 0x0F120087, + 0x0F120093, + 0x0F1200A2, + 0x0F1200B1, +}; + +static const u32 s5k4ecgx_AF_Low_Light_Mode_Off_v1[] = { + 0x002A1616, + 0x0F120003, + + 0x002A15A4, + 0x0F120902, + + 0x002A159E, + 0x0F121800, + + 0x002A15AC, + 0x0F120018, + 0x0F12002A, + 0x0F120030, + 0x0F120036, + 0x0F12003C, + 0x0F120042, + 0x0F120048, + 0x0F12004E, + 0x0F120054, + 0x0F12005A, + 0x0F120060, + 0x0F120066, + 0x0F12006C, + 0x0F120072, + 0x0F120078, + 0x0F12007E, + 0x0F120084, + 0x0F12008A, + 0x0F120090, + 0x0F120096, + 0x0F12009C, + 0x0F1200A2, + 0x0F1200A8, + 0x0F1200AE, + 0x0F1200B4, + 0x0F1200BA, +}; + +static const u32 s5k4ecgx_Single_AF_Start_v1[] = { + 0x002A0286, + 0x0F120005, +}; + +static const u32 s5k4ecgx_Single_AF_Off_1_v1[] = { + 0x002A0288, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Single_AF_Off_2_v1[] = { + 0x002A0286, + 0x0F120004, +}; + +static const u32 s5k4ecgx_Face_Detection_On_v1[] = { + 0x002A028E, + 0x0F120100, + 0x0F1200E3, + 0x0F120200, + 0x0F120238, + 0x0F1201C6, + 0x0F120166, + 0x0F120074, + 0x0F120132, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Face_Detection_Off_v1[] = { + 0x002A028E, + 0x0F120100, + 0x0F1200E3, + 0x0F120200, + 0x0F120238, + 0x0F1201C6, + 0x0F120166, + 0x0F120074, + 0x0F120132, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Low_Cap_On_v1[] = { + 0x002A09EA, + 0x0F120D58, + 0x002A0AA0, + 0x0F120A53, +}; + +static const u32 s5k4ecgx_Low_Cap_Off_v1[] = { + 0x002A09EA, + 0x0F120040, + 0x002A0AA0, + 0x0F120080, +}; + +/* restores crop settings to full resolution */ +static const u32 s5k4ecgx_Reset_Crop_v1[] = { + 0x002A024C, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x002A048E, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + + 0x002A025E, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Capture_Start_v1[] = { + 0x002A1A00, + 0x0F12185C, + 0x0F127000, + 0x002A023E, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0240, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Preview_Return_v1[] = { + 0x002A05C4, + 0x0F120000, + 0x002A1A00, + 0x0F12192E, + 0x0F127000, + 0x002A0952, + 0x0F120000, + 0x002A023E, + 0x0F120000, + 0x002A024A, + 0x0F120001, + 0x002A0240, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Flash_init_v1[] = { + 0x002A17DC, + 0x0F120001, /* one frame AE */ + + 0x002A17AE, + 0x0F120270, /* AWB R point */ + + 0x002A17B0, + 0x0F120210, /* AWB B point */ + + 0x002A17E2, + 0x0F120001, /* Flash AE tune start*/ + 0x0F120030, /* 0x100 for Rin output */ + 0x0F120040, + 0x0F120050, + 0x0F120060, + 0x0F120070, + 0x0F120080, + 0x0F120090, + 0x0F1200A0, + 0x0F120050, /* 0x100 for Rout output-20 */ + 0x0F120014, + 0x0F12000A, + 0x0F120008, + 0x0F120005, + 0x0F120004, + 0x0F120002, + 0x0F120001, + + 0x002A1824, + 0x0F120100, /* 0x100 for NB output */ + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + + 0x002A17B4, + 0x0F120100, + 0x0F1200A0, + 0x0F120080, + 0x0F120020, + 0x0F120001, + + 0x002A17C8, + 0x0F120025, + 0x0F120030, + 0x0F120050, + 0x0F120070, + 0x0F120080, +}; + +static const u32 s5k4ecgx_Pre_Flash_Start_v1[] = { + 0x002A057C, /* set AE speed to fast */ + 0x0F120000, + + 0x002A1F06, /* fls_afl_FlashWP_Weight_0_ Pre_Flash_Start */ + 0x0F120001, +}; + +static const u32 s5k4ecgx_Pre_Flash_End_v1[] = { + 0x002A057C, /* set AE speed to normal */ + 0x0F120002, + + 0x002A1F08, /* fls_afl_FlashWP_Weight_0_ Pre_Flash_end */ + 0x0F120001, +}; + +static const u32 s5k4ecgx_Flash_Start_v1[] = { + 0x002A17A8, + 0x0F120001, + + 0x002A047E, + 0x0F120002, + + 0x002A1448, + 0x0F120027, +}; + +static const u32 s5k4ecgx_Flash_End_v1[] = { + 0x002A17A8, + 0x0F120000, + + 0x002A047E, + 0x0F120000, + + 0x002A1448, + 0x0F12003C, +}; + +static const u32 s5k4ecgx_5M_Capture_v1[] = { /* 2560 x 1920 */ + 0x002A0392, + 0x0F120A00, + 0x0F120780, + 0x0F120009, + + 0x002A03AC, + 0x0F120002, + + 0x002A03AA, + 0x0F120000, + + 0x002A026C, + 0x0F120001, +}; + +static const u32 s5k4ecgx_3M_Capture_v1[] = { /* 2048 x 1536 */ + 0x002A0392, + 0x0F120800, + 0x0F120600, + 0x0F120009, + + 0x002A03AC, + 0x0F120002, + + 0x002A03AA, + 0x0F120000, + + 0x002A024A, + 0x0F120001, + + 0x002A026C, + 0x0F120001, +}; + +static const u32 s5k4ecgx_2M_Capture_v1[] = { /* 1600 x 1200 */ + 0x002A0392, + 0x0F120640, + 0x0F1204B0, + 0x0F120009, + + 0x002A03AC, + 0x0F120002, + + 0x002A03AA, + 0x0F120000, + + 0x002A024A, + 0x0F120001, + + 0x002A026C, + 0x0F120001, +}; + +static const u32 s5k4ecgx_1M_Capture_v1[] = { /* 1280 x 960 */ + 0x002A0392, + 0x0F120500, + 0x0F1203C0, + 0x0F120009, + + 0x002A03AC, + 0x0F120002, + + 0x002A03AA, + 0x0F120000, + + 0x002A024A, + 0x0F120001, + + 0x002A026C, + 0x0F120001, +}; + +static const u32 s5k4ecgx_VGA_Capture_v1[] = { /* 640 x 480 */ + 0x002A0392, + 0x0F120280, + 0x0F1201E0, + 0x0F120009, + + 0x002A03AC, + 0x0F120002, + + 0x002A03AA, + 0x0F120000, + + 0x002A024A, + 0x0F120001, + + 0x002A026C, + 0x0F120001, +}; + +static const u32 s5k4ecgx_720_Preview_v1[] = { /* 720 x 480 */ + 0x002A02A0, + 0x0F1202D0, + 0x0F1201E0, + 0x0F120005, + 0x002A02AE, + 0x0F120052, + 0x002A02B8, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + 0x002A02CA, + 0x0F120000, + 0x0F120000, + 0x002A0262, + 0x0F120000, + 0x002A0266, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0264, + 0x0F120001, +}; + +static const u32 s5k4ecgx_640_Preview_v1[] = { /* 640 x 480 */ + 0x002A02A0, + 0x0F120280, + 0x0F1201E0, + 0x0F120005, + 0x002A02AE, + 0x0F120052, + 0x002A02B8, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + 0x002A02CA, + 0x0F120000, + 0x0F120000, + 0x002A0262, + 0x0F120000, + 0x002A0266, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0264, + 0x0F120001, +}; + +static const u32 s5k4ecgx_352_Preview_v1[] = { /* 352 x 288 */ + 0x002A02A0, + 0x0F120160, + 0x0F120120, + 0x0F120005, + 0x002A02AE, + 0x0F120052, + 0x002A02B8, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + 0x002A02CA, + 0x0F120000, + 0x0F120000, + 0x002A0262, + 0x0F120000, + 0x002A0266, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0264, + 0x0F120001, +}; + +static const u32 s5k4ecgx_176_Preview_v1[] = { /* 176 x 144 */ + 0x002A02A0, + 0x0F1200B0, + 0x0F120090, + 0x0F120005, + 0x002A02AE, + 0x0F120052, + 0x002A02B8, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + 0x002A02CA, + 0x0F120000, + 0x0F120000, + 0x002A0262, + 0x0F120000, + 0x002A0266, + 0x0F120001, + 0x002A024A, + 0x0F120001, + 0x002A0264, + 0x0F120001, +}; + +static const u32 s5k4ecgx_AE_AWB_Lock_On_v1[] = { + 0x002A2B76, /* AE Lock On */ + 0x0F120000, + 0x002A2B7E, /* AWB Lock On */ + 0x0F120000, +}; + +static const u32 s5k4ecgx_AE_AWB_Lock_Off_v1[] = { + 0x002A2B76, /* AE Lock Off */ + 0x0F120001, + 0x002A2B7E, /* AWB Lock Off */ + 0x0F120001, +}; + +static const u32 s5k4ecgx_Get_AE_Stable_Status_v1[] = { + 0x002E2B8C, +}; + +static const u32 s5k4ecgx_Get_Light_Level_v1[] = { + 0x002C7000, + 0x002E2B30, +}; + +static const u32 s5k4ecgx_get_1st_af_search_status_v1[] = { + 0x002E2E06, +}; + +static const u32 s5k4ecgx_get_2nd_af_search_status_v1[] = { + 0x002E2167, +}; + +static const u32 s5k4ecgx_get_capture_status_v1[] = { + 0x002E1F02, +}; + +static const u32 s5k4ecgx_get_esd_status_v1[] = { + 0xFCFCD000, + 0x002CD000, + 0x002E0060, +}; + +static const u32 s5k4ecgx_get_iso_reg_v1[] = { + 0x002C7000, + 0x002E2ADC, +}; + +static const u32 s5k4ecgx_get_shutterspeed_reg_v1[] = { + 0x002C7000, + 0x002E2AD8, +}; + +#endif /* __S5K4ECGX_REGS_1_0_H__ */ diff --git a/drivers/media/video/s5k4ecgx_regs_1_1.h b/drivers/media/video/s5k4ecgx_regs_1_1.h new file mode 100755 index 0000000..4001d36 --- /dev/null +++ b/drivers/media/video/s5k4ecgx_regs_1_1.h @@ -0,0 +1,4783 @@ +/* drivers/media/video/s5k4ecgx_regs_1_1.h + * + * Driver for s5k4ecgx (5MP Camera) from SEC(LSI), firmware EVT1.1 + * + * Copyright (C) 2010, SAMSUNG ELECTRONICS + * + * 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. + */ + + +#ifndef __S5K4ECGX_REGS_1_1_H__ +#define __S5K4ECGX_REGS_1_1_H__ + +/* ARM Initiation */ +static const u32 s5k4ecgx_init_reg1[] = { + 0xFCFCD000, + 0x00100001, + 0x10300000, + 0x00140001, +}; + +static const u32 s5k4ecgx_init_reg2[] = { + /* Drive current setting */ + 0x0028D000, + 0x002A1082, + 0x0F120155, /*d0_d4_cd10, d0_d4_cd10 9:0*/ + 0x0F120155, /*d5_d9_cd10, d5_d9_cd10 9:0*/ + 0x0F120055, /*gpio_cd10, gpio_cd10*/ + 0x0F120555, /*clks_output_cd10, clks_output_cd10 11:0*/ + 0x002A100E, + 0x0F120000, /*pclk_delay_r*/ + + 0x002A007A, + 0x0F120000, + + /* ISP FE(ADLC) */ + 0x002AE406, + 0x0F120092, + 0x002AE410, + 0x0F123804, + 0x002AE41A, + 0x0F120010, /*101022 ADD adlcptune_total */ + 0x002AE420, + 0x0F120003, + 0x0F120060, + 0x002AE42E, + 0x0F120004, + 0x002AF400, + 0x0F125A3C, + 0x0F120023, + 0x0F128080, + 0x0F1203AF, + 0x0F12000A, + 0x0F12AA54, + 0x0F120040, + 0x0F12464E, + 0x0F120240, + 0x0F120240, + 0x0F120040, + 0x0F121000, + 0x0F12555C, + 0x0F12D000, + 0x0F120010, + 0x0F120202, + 0x0F120401, + 0x0F120022, + 0x0F120088, + 0x0F12009F, + 0x0F120000, + 0x0F121800, + 0x0F120088, + 0x0F120000, + 0x0F122428, + 0x0F120000, + 0x0F1203EE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x002AF552, + 0x0F120708, + 0x0F12080C, + + /* For subsampling Size */ + 0x00287000, + 0x002A18BC, + 0x0F120004, + 0x0F1205B6, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F120007, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F12024E, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F1205B6, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F1205BA, + 0x0F120000, + 0x0F120000, + 0x0F1201F4, + 0x0F12024F, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120075, + 0x0F1200CF, + 0x0F120000, + 0x0F120000, + 0x0F120075, + 0x0F1200D6, + 0x0F120000, + 0x0F120000, + 0x0F120004, + 0x0F1201F4, + 0x0F120000, + 0x0F120000, + 0x0F1200F0, + 0x0F1201F4, + 0x0F12029E, + 0x0F1205B2, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1201F8, + 0x0F120228, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120208, + 0x0F120238, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120218, + 0x0F120238, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F120009, + 0x0F1200DE, + 0x0F1205C0, + 0x0F120000, + 0x0F120000, + 0x0F1200DF, + 0x0F1200E4, + 0x0F1201F8, + 0x0F1201FD, + 0x0F1205B6, + 0x0F1205BB, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1201F8, + 0x0F120000, + 0x0F120000, + 0x0F120077, + 0x0F12007E, + 0x0F12024F, + 0x0F12025E, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + /* For Capture */ + 0x0F120004, + 0x0F1209D1, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F1209D5, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F1209D5, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F120326, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F1209D1, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F1209D5, + 0x0F120000, + 0x0F120000, + 0x0F1202AA, + 0x0F120327, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F120084, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F12008D, + 0x0F120000, + 0x0F120000, + 0x0F120008, + 0x0F1202AA, + 0x0F120000, + 0x0F120000, + 0x0F1200AA, + 0x0F1202AA, + 0x0F1203AD, + 0x0F1209CD, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202AE, + 0x0F1202DE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202BE, + 0x0F1202EE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202CE, + 0x0F1202EE, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x0F120009, + 0x0F120095, + 0x0F1209DB, + 0x0F120000, + 0x0F120000, + 0x0F120096, + 0x0F12009B, + 0x0F1202AE, + 0x0F1202B3, + 0x0F1209D1, + 0x0F1209D6, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1202AE, + 0x0F120000, + 0x0F120000, + 0x0F120009, + 0x0F120010, + 0x0F120327, + 0x0F120336, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x002A1AF8, + 0x0F125A3C, /*#senHal_TuneStr_AngTuneData1_2_D000F400 + register at subsampling*/ + + 0x002A1896, + 0x0F120002, /*#senHal_SamplingType 0002 03EE: PLA setting*/ + 0x0F120000, /*#senHal_SamplingMode 0 : 2 PLA / 1 : 4PLA*/ + 0x0F120003, /*#senHal_PLAOption + [0] VPLA enable , [1] HPLA enable*/ + + 0x002A189E, + 0x0F120FB0, /*#senHal_ExpMinPixels*/ + + 0x002A18AC, + 0x0F120060, /*#senHal_uAddColsBin*/ + 0x0F120060, /*#senHal_uAddColsNoBin*/ + 0x0F1205C0, /*#senHal_uMinColsBin*/ + 0x0F1205C0, /*#senHal_uMinColsNoBin*/ + + 0x002A1AEA, + 0x0F128080, /*#senHal_SubF404Tune*/ + 0x0F120080, /*#senHal_FullF404Tune*/ + 0x002A1AE0, + 0x0F120000, /*#senHal_bSenAAC*/ + + 0x002A1A72, + 0x0F120000, /*#senHal_bSRX SRX off*/ + 0x002A18A2, + 0x0F120004, /*#senHal_NExpLinesCheckFine, + extend Forbidden area line*/ + 0x002A1A6A, + 0x0F12009A, /*#senHal_usForbiddenRightOfs, + extend right Forbidden area line*/ + 0x002A385E, + 0x0F12024C, /*#Mon_Sen_uExpPixelsOfs*/ + + 0x002A0EE6, + 0x0F120000, /*#setot_bUseDigitalHbin*/ + 0x002A1B2A, + 0x0F120300, /*#senHal_TuneStr2_usAngTuneGainTh 2 70001B2A*/ + 0x0F1200D6, /*#senHal_TuneStr2_AngTuneF4CA_0_ 2 70001B2C*/ + 0x0F12008D, /*#senHal_TuneStr2_AngTuneF4CA_1_ 2 70001B2E*/ + 0x0F1200CF, /*#senHal_TuneStr2_AngTuneF4C2_0_ 2 70001B30*/ + 0x0F120084, /*#senHal_TuneStr2_AngTuneF4C2_1_ 2 70001B32*/ + + /* OTP setting */ + + 0x002A0722, + 0x0F120100, /*#skl_OTP_usWaitTime, + This register should be positioned in + front of D0001000*/ + 0x002A0726, + 0x0F120001, /*#skl_bUseOTPfunc, This is OTP on/off function*/ + 0x002A08D6, + 0x0F120001, /*#ash_bUseOTPData*/ + 0x002A146E, + 0x0F120000, /*#awbb_otp_disable*/ + 0x002A08DC, + 0x0F120001, /*#ash_bUseGasAlphaOTP*/ + + /* TnP setting */ + /* Start of Patch data */ + 0x002A3AF8, /* TnP */ + 0x0F12B570, /* 70003AF8 */ + 0x0F124B36, /* 70003AFA */ + 0x0F12216F, /* 70003AFC */ + 0x0F124836, /* 70003AFE */ + 0x0F128C80, /* 70003B00 */ + 0x0F122200, /* 70003B02 */ + 0x0F12C008, /* 70003B04 */ + 0x0F126001, /* 70003B06 */ + 0x0F124934, /* 70003B08 */ + 0x0F124835, /* 70003B0A */ + 0x0F122501, /* 70003B0C */ + 0x0F12F000, /* 70003B0E */ + 0x0F12FB77, /* 70003B10 */ + 0x0F124934, /* 70003B12 */ + 0x0F124834, /* 70003B14 */ + 0x0F122402, /* 70003B16 */ + 0x0F12002A, /* 70003B18 */ + 0x0F12F000, /* 70003B1A */ + 0x0F12FB71, /* 70003B1C */ + 0x0F124833, /* 70003B1E */ + 0x0F120221, /* 70003B20 */ + 0x0F128001, /* 70003B22 */ + 0x0F122100, /* 70003B24 */ + 0x0F128041, /* 70003B26 */ + 0x0F124931, /* 70003B28 */ + 0x0F124832, /* 70003B2A */ + 0x0F126041, /* 70003B2C */ + 0x0F124932, /* 70003B2E */ + 0x0F124832, /* 70003B30 */ + 0x0F120022, /* 70003B32 */ + 0x0F122503, /* 70003B34 */ + 0x0F12F000, /* 70003B36 */ + 0x0F12FB63, /* 70003B38 */ + 0x0F12482E, /* 70003B3A */ + 0x0F124930, /* 70003B3C */ + 0x0F1230C0, /* 70003B3E */ + 0x0F1263C1, /* 70003B40 */ + 0x0F12492C, /* 70003B42 */ + 0x0F12482F, /* 70003B44 */ + 0x0F123980, /* 70003B46 */ + 0x0F126408, /* 70003B48 */ + 0x0F12482F, /* 70003B4A */ + 0x0F12492F, /* 70003B4C */ + 0x0F126388, /* 70003B4E */ + 0x0F12492F, /* 70003B50 */ + 0x0F124830, /* 70003B52 */ + 0x0F122404, /* 70003B54 */ + 0x0F12002A, /* 70003B56 */ + 0x0F12F000, /* 70003B58 */ + 0x0F12FB52, /* 70003B5A */ + 0x0F12492E, /* 70003B5C */ + 0x0F12482F, /* 70003B5E */ + 0x0F120022, /* 70003B60 */ + 0x0F122505, /* 70003B62 */ + 0x0F12F000, /* 70003B64 */ + 0x0F12F876, /* 70003B66 */ + 0x0F12482C, /* 70003B68 */ + 0x0F12492D, /* 70003B6A */ + 0x0F122406, /* 70003B6C */ + 0x0F12002A, /* 70003B6E */ + 0x0F121D80, /* 70003B70 */ + 0x0F12F000, /* 70003B72 */ + 0x0F12F86F, /* 70003B74 */ + 0x0F124829, /* 70003B76 */ + 0x0F12492A, /* 70003B78 */ + 0x0F120022, /* 70003B7A */ + 0x0F122507, /* 70003B7C */ + 0x0F12300C, /* 70003B7E */ + 0x0F12F000, /* 70003B80 */ + 0x0F12F868, /* 70003B82 */ + 0x0F124825, /* 70003B84 */ + 0x0F124928, /* 70003B86 */ + 0x0F122408, /* 70003B88 */ + 0x0F12002A, /* 70003B8A */ + 0x0F123010, /* 70003B8C */ + 0x0F12F000, /* 70003B8E */ + 0x0F12F861, /* 70003B90 */ + 0x0F124926, /* 70003B92 */ + 0x0F124826, /* 70003B94 */ + 0x0F120022, /* 70003B96 */ + 0x0F122509, /* 70003B98 */ + 0x0F12F000, /* 70003B9A */ + 0x0F12FB31, /* 70003B9C */ + 0x0F124925, /* 70003B9E */ + 0x0F124825, /* 70003BA0 */ + 0x0F12240A, /* 70003BA2 */ + 0x0F12002A, /* 70003BA4 */ + 0x0F12F000, /* 70003BA6 */ + 0x0F12FB2B, /* 70003BA8 */ + 0x0F124924, /* 70003BAA */ + 0x0F124824, /* 70003BAC */ + 0x0F12250B, /* 70003BAE */ + 0x0F120022, /* 70003BB0 */ + 0x0F12F000, /* 70003BB2 */ + 0x0F12FB25, /* 70003BB4 */ + 0x0F124923, /* 70003BB6 */ + 0x0F124823, /* 70003BB8 */ + 0x0F12002A, /* 70003BBA */ + 0x0F12240C, /* 70003BBC */ + 0x0F12F000, /* 70003BBE */ + 0x0F12FB1F, /* 70003BC0 */ + 0x0F124922, /* 70003BC2 */ + 0x0F124822, /* 70003BC4 */ + 0x0F120022, /* 70003BC6 */ + 0x0F12F000, /* 70003BC8 */ + 0x0F12FB1A, /* 70003BCA */ + 0x0F12BC70, /* 70003BCC */ + 0x0F12BC08, /* 70003BCE */ + 0x0F124718, /* 70003BD0 */ + 0x0F120000, /* 70003BD2 */ + 0x0F120185, /* 70003BD4 */ + 0x0F124EC2, /* 70003BD6 */ + 0x0F121F6C, /* 70003BD8 */ + 0x0F127000, /* 70003BDA */ + 0x0F123C6D, /* 70003BDC */ + 0x0F127000, /* 70003BDE */ + 0x0F12E38B, /* 70003BE0 */ + 0x0F120000, /* 70003BE2 */ + 0x0F123CA5, /* 70003BE4 */ + 0x0F127000, /* 70003BE6 */ + 0x0F12C3B1, /* 70003BE8 */ + 0x0F120000, /* 70003BEA */ + 0x0F124780, /* 70003BEC */ + 0x0F127000, /* 70003BEE */ + 0x0F123D03, /* 70003BF0 */ + 0x0F127000, /* 70003BF2 */ + 0x0F120080, /* 70003BF4 */ + 0x0F127000, /* 70003BF6 */ + 0x0F123D3F, /* 70003BF8 */ + 0x0F127000, /* 70003BFA */ + 0x0F12B49D, /* 70003BFC */ + 0x0F120000, /* 70003BFE */ + 0x0F123DEB, /* 70003C00 */ + 0x0F127000, /* 70003C02 */ + 0x0F123D9F, /* 70003C04 */ + 0x0F127000, /* 70003C06 */ + 0x0F12FFFF, /* 70003C08 */ + 0x0F1200FF, /* 70003C0A */ + 0x0F1217E0, /* 70003C0C */ + 0x0F127000, /* 70003C0E */ + 0x0F123F67, /* 70003C10 */ + 0x0F127000, /* 70003C12 */ + 0x0F12053D, /* 70003C14 */ + 0x0F120000, /* 70003C16 */ + 0x0F120000, /* 70003C18 */ + 0x0F120A89, /* 70003C1A */ + 0x0F126CD2, /* 70003C1C */ + 0x0F120000, /* 70003C1E */ + 0x0F1202C9, /* 70003C20 */ + 0x0F120000, /* 70003C22 */ + 0x0F120000, /* 70003C24 */ + 0x0F120A9A, /* 70003C26 */ + 0x0F120000, /* 70003C28 */ + 0x0F1202D2, /* 70003C2A */ + 0x0F123FB5, /* 70003C2C */ + 0x0F127000, /* 70003C2E */ + 0x0F129E65, /* 70003C30 */ + 0x0F120000, /* 70003C32 */ + 0x0F124029, /* 70003C34 */ + 0x0F127000, /* 70003C36 */ + 0x0F127C49, /* 70003C38 */ + 0x0F120000, /* 70003C3A */ + 0x0F12409D, /* 70003C3C */ + 0x0F127000, /* 70003C3E */ + 0x0F127C63, /* 70003C40 */ + 0x0F120000, /* 70003C42 */ + 0x0F1240B9, /* 70003C44 */ + 0x0F127000, /* 70003C46 */ + 0x0F128F01, /* 70003C48 */ + 0x0F120000, /* 70003C4A */ + 0x0F12415B, /* 70003C4C */ + 0x0F127000, /* 70003C4E */ + 0x0F127F3F, /* 70003C50 */ + 0x0F120000, /* 70003C52 */ + 0x0F12B570, /* 70003C54 */ + 0x0F12000C, /* 70003C56 */ + 0x0F120015, /* 70003C58 */ + 0x0F120029, /* 70003C5A */ + 0x0F12F000, /* 70003C5C */ + 0x0F12FAD8, /* 70003C5E */ + 0x0F1249F8, /* 70003C60 */ + 0x0F1200A8, /* 70003C62 */ + 0x0F12500C, /* 70003C64 */ + 0x0F12BC70, /* 70003C66 */ + 0x0F12BC08, /* 70003C68 */ + 0x0F124718, /* 70003C6A */ + 0x0F126808, /* 70003C6C */ + 0x0F120400, /* 70003C6E */ + 0x0F120C00, /* 70003C70 */ + 0x0F126849, /* 70003C72 */ + 0x0F120409, /* 70003C74 */ + 0x0F120C09, /* 70003C76 */ + 0x0F124AF3, /* 70003C78 */ + 0x0F128992, /* 70003C7A */ + 0x0F122A00, /* 70003C7C */ + 0x0F12D00D, /* 70003C7E */ + 0x0F122300, /* 70003C80 */ + 0x0F121A89, /* 70003C82 */ + 0x0F12D400, /* 70003C84 */ + 0x0F12000B, /* 70003C86 */ + 0x0F120419, /* 70003C88 */ + 0x0F120C09, /* 70003C8A */ + 0x0F1223FF, /* 70003C8C */ + 0x0F1233C1, /* 70003C8E */ + 0x0F121810, /* 70003C90 */ + 0x0F124298, /* 70003C92 */ + 0x0F12D800, /* 70003C94 */ + 0x0F120003, /* 70003C96 */ + 0x0F120418, /* 70003C98 */ + 0x0F120C00, /* 70003C9A */ + 0x0F124AEB, /* 70003C9C */ + 0x0F128150, /* 70003C9E */ + 0x0F128191, /* 70003CA0 */ + 0x0F124770, /* 70003CA2 */ + 0x0F12B5F3, /* 70003CA4 */ + 0x0F120004, /* 70003CA6 */ + 0x0F12B081, /* 70003CA8 */ + 0x0F129802, /* 70003CAA */ + 0x0F126800, /* 70003CAC */ + 0x0F120600, /* 70003CAE */ + 0x0F120E00, /* 70003CB0 */ + 0x0F122201, /* 70003CB2 */ + 0x0F120015, /* 70003CB4 */ + 0x0F120021, /* 70003CB6 */ + 0x0F123910, /* 70003CB8 */ + 0x0F12408A, /* 70003CBA */ + 0x0F1240A5, /* 70003CBC */ + 0x0F124FE4, /* 70003CBE */ + 0x0F120016, /* 70003CC0 */ + 0x0F122C10, /* 70003CC2 */ + 0x0F12DA03, /* 70003CC4 */ + 0x0F128839, /* 70003CC6 */ + 0x0F1243A9, /* 70003CC8 */ + 0x0F128039, /* 70003CCA */ + 0x0F12E002, /* 70003CCC */ + 0x0F128879, /* 70003CCE */ + 0x0F1243B1, /* 70003CD0 */ + 0x0F128079, /* 70003CD2 */ + 0x0F12F000, /* 70003CD4 */ + 0x0F12FAA4, /* 70003CD6 */ + 0x0F122C10, /* 70003CD8 */ + 0x0F12DA03, /* 70003CDA */ + 0x0F128839, /* 70003CDC */ + 0x0F124329, /* 70003CDE */ + 0x0F128039, /* 70003CE0 */ + 0x0F12E002, /* 70003CE2 */ + 0x0F128879, /* 70003CE4 */ + 0x0F124331, /* 70003CE6 */ + 0x0F128079, /* 70003CE8 */ + 0x0F1249DA, /* 70003CEA */ + 0x0F128809, /* 70003CEC */ + 0x0F122900, /* 70003CEE */ + 0x0F12D102, /* 70003CF0 */ + 0x0F12F000, /* 70003CF2 */ + 0x0F12FA9D, /* 70003CF4 */ + 0x0F122000, /* 70003CF6 */ + 0x0F129902, /* 70003CF8 */ + 0x0F126008, /* 70003CFA */ + 0x0F12BCFE, /* 70003CFC */ + 0x0F12BC08, /* 70003CFE */ + 0x0F124718, /* 70003D00 */ + 0x0F12B538, /* 70003D02 */ + 0x0F129C04, /* 70003D04 */ + 0x0F120015, /* 70003D06 */ + 0x0F12002A, /* 70003D08 */ + 0x0F129400, /* 70003D0A */ + 0x0F12F000, /* 70003D0C */ + 0x0F12FA98, /* 70003D0E */ + 0x0F124AD1, /* 70003D10 */ + 0x0F128811, /* 70003D12 */ + 0x0F122900, /* 70003D14 */ + 0x0F12D00F, /* 70003D16 */ + 0x0F128820, /* 70003D18 */ + 0x0F124281, /* 70003D1A */ + 0x0F12D20C, /* 70003D1C */ + 0x0F128861, /* 70003D1E */ + 0x0F128853, /* 70003D20 */ + 0x0F124299, /* 70003D22 */ + 0x0F12D200, /* 70003D24 */ + 0x0F121E40, /* 70003D26 */ + 0x0F120400, /* 70003D28 */ + 0x0F120C00, /* 70003D2A */ + 0x0F128020, /* 70003D2C */ + 0x0F128851, /* 70003D2E */ + 0x0F128061, /* 70003D30 */ + 0x0F124368, /* 70003D32 */ + 0x0F121840, /* 70003D34 */ + 0x0F126060, /* 70003D36 */ + 0x0F12BC38, /* 70003D38 */ + 0x0F12BC08, /* 70003D3A */ + 0x0F124718, /* 70003D3C */ + 0x0F12B5F8, /* 70003D3E */ + 0x0F120004, /* 70003D40 */ + 0x0F126808, /* 70003D42 */ + 0x0F120400, /* 70003D44 */ + 0x0F120C00, /* 70003D46 */ + 0x0F122201, /* 70003D48 */ + 0x0F120015, /* 70003D4A */ + 0x0F120021, /* 70003D4C */ + 0x0F123910, /* 70003D4E */ + 0x0F12408A, /* 70003D50 */ + 0x0F1240A5, /* 70003D52 */ + 0x0F124FBE, /* 70003D54 */ + 0x0F120016, /* 70003D56 */ + 0x0F122C10, /* 70003D58 */ + 0x0F12DA03, /* 70003D5A */ + 0x0F128839, /* 70003D5C */ + 0x0F1243A9, /* 70003D5E */ + 0x0F128039, /* 70003D60 */ + 0x0F12E002, /* 70003D62 */ + 0x0F128879, /* 70003D64 */ + 0x0F1243B1, /* 70003D66 */ + 0x0F128079, /* 70003D68 */ + 0x0F12F000, /* 70003D6A */ + 0x0F12FA71, /* 70003D6C */ + 0x0F122C10, /* 70003D6E */ + 0x0F12DA03, /* 70003D70 */ + 0x0F128838, /* 70003D72 */ + 0x0F124328, /* 70003D74 */ + 0x0F128038, /* 70003D76 */ + 0x0F12E002, /* 70003D78 */ + 0x0F128878, /* 70003D7A */ + 0x0F124330, /* 70003D7C */ + 0x0F128078, /* 70003D7E */ + 0x0F1248B6, /* 70003D80 */ + 0x0F128800, /* 70003D82 */ + 0x0F120400, /* 70003D84 */ + 0x0F12D507, /* 70003D86 */ + 0x0F124BB5, /* 70003D88 */ + 0x0F127819, /* 70003D8A */ + 0x0F124AB5, /* 70003D8C */ + 0x0F127810, /* 70003D8E */ + 0x0F127018, /* 70003D90 */ + 0x0F127011, /* 70003D92 */ + 0x0F1249B4, /* 70003D94 */ + 0x0F128188, /* 70003D96 */ + 0x0F12BCF8, /* 70003D98 */ + 0x0F12BC08, /* 70003D9A */ + 0x0F124718, /* 70003D9C */ + 0x0F12B538, /* 70003D9E */ + 0x0F1248B2, /* 70003DA0 */ + 0x0F124669, /* 70003DA2 */ + 0x0F12F000, /* 70003DA4 */ + 0x0F12FA5C, /* 70003DA6 */ + 0x0F1248B1, /* 70003DA8 */ + 0x0F1249B0, /* 70003DAA */ + 0x0F1269C2, /* 70003DAC */ + 0x0F122400, /* 70003DAE */ + 0x0F1231A8, /* 70003DB0 */ + 0x0F122A00, /* 70003DB2 */ + 0x0F12D008, /* 70003DB4 */ + 0x0F1261C4, /* 70003DB6 */ + 0x0F12684A, /* 70003DB8 */ + 0x0F126242, /* 70003DBA */ + 0x0F126282, /* 70003DBC */ + 0x0F12466B, /* 70003DBE */ + 0x0F12881A, /* 70003DC0 */ + 0x0F126302, /* 70003DC2 */ + 0x0F12885A, /* 70003DC4 */ + 0x0F126342, /* 70003DC6 */ + 0x0F126A02, /* 70003DC8 */ + 0x0F122A00, /* 70003DCA */ + 0x0F12D00A, /* 70003DCC */ + 0x0F126204, /* 70003DCE */ + 0x0F126849, /* 70003DD0 */ + 0x0F126281, /* 70003DD2 */ + 0x0F12466B, /* 70003DD4 */ + 0x0F128819, /* 70003DD6 */ + 0x0F126301, /* 70003DD8 */ + 0x0F128859, /* 70003DDA */ + 0x0F126341, /* 70003DDC */ + 0x0F1249A5, /* 70003DDE */ + 0x0F1288C9, /* 70003DE0 */ + 0x0F1263C1, /* 70003DE2 */ + 0x0F12F000, /* 70003DE4 */ + 0x0F12FA44, /* 70003DE6 */ + 0x0F12E7A6, /* 70003DE8 */ + 0x0F12B5F0, /* 70003DEA */ + 0x0F12B08B, /* 70003DEC */ + 0x0F1220FF, /* 70003DEE */ + 0x0F121C40, /* 70003DF0 */ + 0x0F1249A1, /* 70003DF2 */ + 0x0F1289CC, /* 70003DF4 */ + 0x0F124E9E, /* 70003DF6 */ + 0x0F126AB1, /* 70003DF8 */ + 0x0F124284, /* 70003DFA */ + 0x0F12D101, /* 70003DFC */ + 0x0F12489F, /* 70003DFE */ + 0x0F126081, /* 70003E00 */ + 0x0F126A70, /* 70003E02 */ + 0x0F120200, /* 70003E04 */ + 0x0F12F000, /* 70003E06 */ + 0x0F12FA3B, /* 70003E08 */ + 0x0F120400, /* 70003E0A */ + 0x0F120C00, /* 70003E0C */ + 0x0F124A96, /* 70003E0E */ + 0x0F128A11, /* 70003E10 */ + 0x0F129109, /* 70003E12 */ + 0x0F122101, /* 70003E14 */ + 0x0F120349, /* 70003E16 */ + 0x0F124288, /* 70003E18 */ + 0x0F12D200, /* 70003E1A */ + 0x0F120001, /* 70003E1C */ + 0x0F124A92, /* 70003E1E */ + 0x0F128211, /* 70003E20 */ + 0x0F124D97, /* 70003E22 */ + 0x0F128829, /* 70003E24 */ + 0x0F129108, /* 70003E26 */ + 0x0F124A8B, /* 70003E28 */ + 0x0F122303, /* 70003E2A */ + 0x0F123222, /* 70003E2C */ + 0x0F121F91, /* 70003E2E */ + 0x0F12F000, /* 70003E30 */ + 0x0F12FA2C, /* 70003E32 */ + 0x0F128028, /* 70003E34 */ + 0x0F12488E, /* 70003E36 */ + 0x0F124987, /* 70003E38 */ + 0x0F126BC2, /* 70003E3A */ + 0x0F126AC0, /* 70003E3C */ + 0x0F124282, /* 70003E3E */ + 0x0F12D201, /* 70003E40 */ + 0x0F128CC8, /* 70003E42 */ + 0x0F128028, /* 70003E44 */ + 0x0F1288E8, /* 70003E46 */ + 0x0F129007, /* 70003E48 */ + 0x0F122240, /* 70003E4A */ + 0x0F124310, /* 70003E4C */ + 0x0F1280E8, /* 70003E4E */ + 0x0F122000, /* 70003E50 */ + 0x0F120041, /* 70003E52 */ + 0x0F12194B, /* 70003E54 */ + 0x0F12001E, /* 70003E56 */ + 0x0F123680, /* 70003E58 */ + 0x0F128BB2, /* 70003E5A */ + 0x0F12AF04, /* 70003E5C */ + 0x0F12527A, /* 70003E5E */ + 0x0F124A7D, /* 70003E60 */ + 0x0F12188A, /* 70003E62 */ + 0x0F128897, /* 70003E64 */ + 0x0F1283B7, /* 70003E66 */ + 0x0F1233A0, /* 70003E68 */ + 0x0F12891F, /* 70003E6A */ + 0x0F12AE01, /* 70003E6C */ + 0x0F125277, /* 70003E6E */ + 0x0F128A11, /* 70003E70 */ + 0x0F128119, /* 70003E72 */ + 0x0F121C40, /* 70003E74 */ + 0x0F120400, /* 70003E76 */ + 0x0F120C00, /* 70003E78 */ + 0x0F122806, /* 70003E7A */ + 0x0F12D3E9, /* 70003E7C */ + 0x0F12F000, /* 70003E7E */ + 0x0F12FA0D, /* 70003E80 */ + 0x0F12F000, /* 70003E82 */ + 0x0F12FA13, /* 70003E84 */ + 0x0F124F79, /* 70003E86 */ + 0x0F1237A8, /* 70003E88 */ + 0x0F122800, /* 70003E8A */ + 0x0F12D10A, /* 70003E8C */ + 0x0F121FE0, /* 70003E8E */ + 0x0F1238FD, /* 70003E90 */ + 0x0F12D001, /* 70003E92 */ + 0x0F121CC0, /* 70003E94 */ + 0x0F12D105, /* 70003E96 */ + 0x0F124874, /* 70003E98 */ + 0x0F128829, /* 70003E9A */ + 0x0F123818, /* 70003E9C */ + 0x0F126840, /* 70003E9E */ + 0x0F124348, /* 70003EA0 */ + 0x0F126078, /* 70003EA2 */ + 0x0F124972, /* 70003EA4 */ + 0x0F126878, /* 70003EA6 */ + 0x0F126B89, /* 70003EA8 */ + 0x0F124288, /* 70003EAA */ + 0x0F12D300, /* 70003EAC */ + 0x0F120008, /* 70003EAE */ + 0x0F126078, /* 70003EB0 */ + 0x0F122000, /* 70003EB2 */ + 0x0F120041, /* 70003EB4 */ + 0x0F12AA04, /* 70003EB6 */ + 0x0F125A53, /* 70003EB8 */ + 0x0F12194A, /* 70003EBA */ + 0x0F12269C, /* 70003EBC */ + 0x0F1252B3, /* 70003EBE */ + 0x0F12AB01, /* 70003EC0 */ + 0x0F125A59, /* 70003EC2 */ + 0x0F1232A0, /* 70003EC4 */ + 0x0F128111, /* 70003EC6 */ + 0x0F121C40, /* 70003EC8 */ + 0x0F120400, /* 70003ECA */ + 0x0F120C00, /* 70003ECC */ + 0x0F122806, /* 70003ECE */ + 0x0F12D3F0, /* 70003ED0 */ + 0x0F124965, /* 70003ED2 */ + 0x0F129809, /* 70003ED4 */ + 0x0F128208, /* 70003ED6 */ + 0x0F129808, /* 70003ED8 */ + 0x0F128028, /* 70003EDA */ + 0x0F129807, /* 70003EDC */ + 0x0F1280E8, /* 70003EDE */ + 0x0F121FE0, /* 70003EE0 */ + 0x0F1238FD, /* 70003EE2 */ + 0x0F12D13B, /* 70003EE4 */ + 0x0F124D64, /* 70003EE6 */ + 0x0F1289E8, /* 70003EE8 */ + 0x0F121FC1, /* 70003EEA */ + 0x0F1239FF, /* 70003EEC */ + 0x0F12D136, /* 70003EEE */ + 0x0F124C5F, /* 70003EF0 */ + 0x0F128AE0, /* 70003EF2 */ + 0x0F12F000, /* 70003EF4 */ + 0x0F12F9E2, /* 70003EF6 */ + 0x0F120006, /* 70003EF8 */ + 0x0F128B20, /* 70003EFA */ + 0x0F12F000, /* 70003EFC */ + 0x0F12F9E6, /* 70003EFE */ + 0x0F129000, /* 70003F00 */ + 0x0F126AA1, /* 70003F02 */ + 0x0F126878, /* 70003F04 */ + 0x0F121809, /* 70003F06 */ + 0x0F120200, /* 70003F08 */ + 0x0F12F000, /* 70003F0A */ + 0x0F12F9B9, /* 70003F0C */ + 0x0F120400, /* 70003F0E */ + 0x0F120C00, /* 70003F10 */ + 0x0F120022, /* 70003F12 */ + 0x0F123246, /* 70003F14 */ + 0x0F120011, /* 70003F16 */ + 0x0F12310A, /* 70003F18 */ + 0x0F122305, /* 70003F1A */ + 0x0F12F000, /* 70003F1C */ + 0x0F12F9B6, /* 70003F1E */ + 0x0F1266E8, /* 70003F20 */ + 0x0F126B23, /* 70003F22 */ + 0x0F120002, /* 70003F24 */ + 0x0F120031, /* 70003F26 */ + 0x0F120018, /* 70003F28 */ + 0x0F12F000, /* 70003F2A */ + 0x0F12F9D7, /* 70003F2C */ + 0x0F12466B, /* 70003F2E */ + 0x0F128518, /* 70003F30 */ + 0x0F126EEA, /* 70003F32 */ + 0x0F126B60, /* 70003F34 */ + 0x0F129900, /* 70003F36 */ + 0x0F12F000, /* 70003F38 */ + 0x0F12F9D0, /* 70003F3A */ + 0x0F12466B, /* 70003F3C */ + 0x0F128558, /* 70003F3E */ + 0x0F120029, /* 70003F40 */ + 0x0F12980A, /* 70003F42 */ + 0x0F123170, /* 70003F44 */ + 0x0F12F000, /* 70003F46 */ + 0x0F12F9D1, /* 70003F48 */ + 0x0F120028, /* 70003F4A */ + 0x0F123060, /* 70003F4C */ + 0x0F128A02, /* 70003F4E */ + 0x0F124946, /* 70003F50 */ + 0x0F123128, /* 70003F52 */ + 0x0F12808A, /* 70003F54 */ + 0x0F128A42, /* 70003F56 */ + 0x0F1280CA, /* 70003F58 */ + 0x0F128A80, /* 70003F5A */ + 0x0F128108, /* 70003F5C */ + 0x0F12B00B, /* 70003F5E */ + 0x0F12BCF0, /* 70003F60 */ + 0x0F12BC08, /* 70003F62 */ + 0x0F124718, /* 70003F64 */ + 0x0F12B570, /* 70003F66 */ + 0x0F122400, /* 70003F68 */ + 0x0F124D46, /* 70003F6A */ + 0x0F124846, /* 70003F6C */ + 0x0F128881, /* 70003F6E */ + 0x0F124846, /* 70003F70 */ + 0x0F128041, /* 70003F72 */ + 0x0F122101, /* 70003F74 */ + 0x0F128001, /* 70003F76 */ + 0x0F12F000, /* 70003F78 */ + 0x0F12F9C0, /* 70003F7A */ + 0x0F124842, /* 70003F7C */ + 0x0F123820, /* 70003F7E */ + 0x0F128BC0, /* 70003F80 */ + 0x0F12F000, /* 70003F82 */ + 0x0F12F9C3, /* 70003F84 */ + 0x0F124B42, /* 70003F86 */ + 0x0F12220D, /* 70003F88 */ + 0x0F120712, /* 70003F8A */ + 0x0F1218A8, /* 70003F8C */ + 0x0F128806, /* 70003F8E */ + 0x0F1200E1, /* 70003F90 */ + 0x0F1218C9, /* 70003F92 */ + 0x0F1281CE, /* 70003F94 */ + 0x0F128846, /* 70003F96 */ + 0x0F12818E, /* 70003F98 */ + 0x0F128886, /* 70003F9A */ + 0x0F12824E, /* 70003F9C */ + 0x0F1288C0, /* 70003F9E */ + 0x0F128208, /* 70003FA0 */ + 0x0F123508, /* 70003FA2 */ + 0x0F12042D, /* 70003FA4 */ + 0x0F120C2D, /* 70003FA6 */ + 0x0F121C64, /* 70003FA8 */ + 0x0F120424, /* 70003FAA */ + 0x0F120C24, /* 70003FAC */ + 0x0F122C07, /* 70003FAE */ + 0x0F12D3EC, /* 70003FB0 */ + 0x0F12E658, /* 70003FB2 */ + 0x0F12B510, /* 70003FB4 */ + 0x0F124834, /* 70003FB6 */ + 0x0F124C34, /* 70003FB8 */ + 0x0F1288C0, /* 70003FBA */ + 0x0F128060, /* 70003FBC */ + 0x0F122001, /* 70003FBE */ + 0x0F128020, /* 70003FC0 */ + 0x0F124831, /* 70003FC2 */ + 0x0F123820, /* 70003FC4 */ + 0x0F128BC0, /* 70003FC6 */ + 0x0F12F000, /* 70003FC8 */ + 0x0F12F9A0, /* 70003FCA */ + 0x0F1288E0, /* 70003FCC */ + 0x0F124A31, /* 70003FCE */ + 0x0F122800, /* 70003FD0 */ + 0x0F12D003, /* 70003FD2 */ + 0x0F124930, /* 70003FD4 */ + 0x0F128849, /* 70003FD6 */ + 0x0F122900, /* 70003FD8 */ + 0x0F12D009, /* 70003FDA */ + 0x0F122001, /* 70003FDC */ + 0x0F1203C0, /* 70003FDE */ + 0x0F128050, /* 70003FE0 */ + 0x0F1280D0, /* 70003FE2 */ + 0x0F122000, /* 70003FE4 */ + 0x0F128090, /* 70003FE6 */ + 0x0F128110, /* 70003FE8 */ + 0x0F12BC10, /* 70003FEA */ + 0x0F12BC08, /* 70003FEC */ + 0x0F124718, /* 70003FEE */ + 0x0F128050, /* 70003FF0 */ + 0x0F128920, /* 70003FF2 */ + 0x0F1280D0, /* 70003FF4 */ + 0x0F128960, /* 70003FF6 */ + 0x0F120400, /* 70003FF8 */ + 0x0F121400, /* 70003FFA */ + 0x0F128090, /* 70003FFC */ + 0x0F1289A1, /* 70003FFE */ + 0x0F120409, /* 70004000 */ + 0x0F121409, /* 70004002 */ + 0x0F128111, /* 70004004 */ + 0x0F1289E3, /* 70004006 */ + 0x0F128A24, /* 70004008 */ + 0x0F122B00, /* 7000400A */ + 0x0F12D104, /* 7000400C */ + 0x0F1217C3, /* 7000400E */ + 0x0F120F5B, /* 70004010 */ + 0x0F121818, /* 70004012 */ + 0x0F1210C0, /* 70004014 */ + 0x0F128090, /* 70004016 */ + 0x0F122C00, /* 70004018 */ + 0x0F12D1E6, /* 7000401A */ + 0x0F1217C8, /* 7000401C */ + 0x0F120F40, /* 7000401E */ + 0x0F121840, /* 70004020 */ + 0x0F1210C0, /* 70004022 */ + 0x0F128110, /* 70004024 */ + 0x0F12E7E0, /* 70004026 */ + 0x0F12B510, /* 70004028 */ + 0x0F12000C, /* 7000402A */ + 0x0F124919, /* 7000402C */ + 0x0F122204, /* 7000402E */ + 0x0F126820, /* 70004030 */ + 0x0F125E8A, /* 70004032 */ + 0x0F120140, /* 70004034 */ + 0x0F121A80, /* 70004036 */ + 0x0F120280, /* 70004038 */ + 0x0F128849, /* 7000403A */ + 0x0F12F000, /* 7000403C */ + 0x0F12F96E, /* 7000403E */ + 0x0F126020, /* 70004040 */ + 0x0F12E7D2, /* 70004042 */ + 0x0F1238D4, /* 70004044 */ + 0x0F127000, /* 70004046 */ + 0x0F1217D0, /* 70004048 */ + 0x0F127000, /* 7000404A */ + 0x0F125000, /* 7000404C */ + 0x0F12D000, /* 7000404E */ + 0x0F121100, /* 70004050 */ + 0x0F12D000, /* 70004052 */ + 0x0F12171A, /* 70004054 */ + 0x0F127000, /* 70004056 */ + 0x0F124780, /* 70004058 */ + 0x0F127000, /* 7000405A */ + 0x0F122FCA, /* 7000405C */ + 0x0F127000, /* 7000405E */ + 0x0F122FC5, /* 70004060 */ + 0x0F127000, /* 70004062 */ + 0x0F122FC6, /* 70004064 */ + 0x0F127000, /* 70004066 */ + 0x0F122ED8, /* 70004068 */ + 0x0F127000, /* 7000406A */ + 0x0F122BD0, /* 7000406C */ + 0x0F127000, /* 7000406E */ + 0x0F1217E0, /* 70004070 */ + 0x0F127000, /* 70004072 */ + 0x0F122DE8, /* 70004074 */ + 0x0F127000, /* 70004076 */ + 0x0F1237E0, /* 70004078 */ + 0x0F127000, /* 7000407A */ + 0x0F12210C, /* 7000407C */ + 0x0F127000, /* 7000407E */ + 0x0F121484, /* 70004080 */ + 0x0F127000, /* 70004082 */ + 0x0F12A006, /* 70004084 */ + 0x0F120000, /* 70004086 */ + 0x0F120724, /* 70004088 */ + 0x0F127000, /* 7000408A */ + 0x0F12A000, /* 7000408C */ + 0x0F12D000, /* 7000408E */ + 0x0F122270, /* 70004090 */ + 0x0F127000, /* 70004092 */ + 0x0F122558, /* 70004094 */ + 0x0F127000, /* 70004096 */ + 0x0F12146C, /* 70004098 */ + 0x0F127000, /* 7000409A */ + 0x0F12B510, /* 7000409C */ + 0x0F12000C, /* 7000409E */ + 0x0F124951, /* 700040A0 */ + 0x0F122208, /* 700040A2 */ + 0x0F126820, /* 700040A4 */ + 0x0F125E8A, /* 700040A6 */ + 0x0F120140, /* 700040A8 */ + 0x0F121A80, /* 700040AA */ + 0x0F120280, /* 700040AC */ + 0x0F1288C9, /* 700040AE */ + 0x0F12F000, /* 700040B0 */ + 0x0F12F934, /* 700040B2 */ + 0x0F126020, /* 700040B4 */ + 0x0F12E798, /* 700040B6 */ + 0x0F12B5FE, /* 700040B8 */ + 0x0F12000C, /* 700040BA */ + 0x0F126825, /* 700040BC */ + 0x0F126866, /* 700040BE */ + 0x0F1268A0, /* 700040C0 */ + 0x0F129001, /* 700040C2 */ + 0x0F1268E7, /* 700040C4 */ + 0x0F121BA8, /* 700040C6 */ + 0x0F1242B5, /* 700040C8 */ + 0x0F12DA00, /* 700040CA */ + 0x0F121B70, /* 700040CC */ + 0x0F129000, /* 700040CE */ + 0x0F124945, /* 700040D0 */ + 0x0F124846, /* 700040D2 */ + 0x0F12884A, /* 700040D4 */ + 0x0F128843, /* 700040D6 */ + 0x0F12435A, /* 700040D8 */ + 0x0F122304, /* 700040DA */ + 0x0F125ECB, /* 700040DC */ + 0x0F120A92, /* 700040DE */ + 0x0F1218D2, /* 700040E0 */ + 0x0F1202D2, /* 700040E2 */ + 0x0F120C12, /* 700040E4 */ + 0x0F1288CB, /* 700040E6 */ + 0x0F128880, /* 700040E8 */ + 0x0F124343, /* 700040EA */ + 0x0F120A98, /* 700040EC */ + 0x0F122308, /* 700040EE */ + 0x0F125ECB, /* 700040F0 */ + 0x0F1218C0, /* 700040F2 */ + 0x0F1202C0, /* 700040F4 */ + 0x0F120C00, /* 700040F6 */ + 0x0F120411, /* 700040F8 */ + 0x0F120400, /* 700040FA */ + 0x0F121409, /* 700040FC */ + 0x0F121400, /* 700040FE */ + 0x0F121A08, /* 70004100 */ + 0x0F12493A, /* 70004102 */ + 0x0F1239E0, /* 70004104 */ + 0x0F126148, /* 70004106 */ + 0x0F129801, /* 70004108 */ + 0x0F123040, /* 7000410A */ + 0x0F127880, /* 7000410C */ + 0x0F122800, /* 7000410E */ + 0x0F12D103, /* 70004110 */ + 0x0F129801, /* 70004112 */ + 0x0F120029, /* 70004114 */ + 0x0F12F000, /* 70004116 */ + 0x0F12F907, /* 70004118 */ + 0x0F128839, /* 7000411A */ + 0x0F129800, /* 7000411C */ + 0x0F124281, /* 7000411E */ + 0x0F12D814, /* 70004120 */ + 0x0F128879, /* 70004122 */ + 0x0F129800, /* 70004124 */ + 0x0F124281, /* 70004126 */ + 0x0F12D20C, /* 70004128 */ + 0x0F129801, /* 7000412A */ + 0x0F120029, /* 7000412C */ + 0x0F12F000, /* 7000412E */ + 0x0F12F903, /* 70004130 */ + 0x0F129801, /* 70004132 */ + 0x0F120029, /* 70004134 */ + 0x0F12F000, /* 70004136 */ + 0x0F12F8FF, /* 70004138 */ + 0x0F129801, /* 7000413A */ + 0x0F120029, /* 7000413C */ + 0x0F12F000, /* 7000413E */ + 0x0F12F8FB, /* 70004140 */ + 0x0F12E003, /* 70004142 */ + 0x0F129801, /* 70004144 */ + 0x0F120029, /* 70004146 */ + 0x0F12F000, /* 70004148 */ + 0x0F12F8F6, /* 7000414A */ + 0x0F129801, /* 7000414C */ + 0x0F120032, /* 7000414E */ + 0x0F120039, /* 70004150 */ + 0x0F12F000, /* 70004152 */ + 0x0F12F8F9, /* 70004154 */ + 0x0F126020, /* 70004156 */ + 0x0F12E5D0, /* 70004158 */ + 0x0F12B57C, /* 7000415A */ + 0x0F124824, /* 7000415C */ + 0x0F12A901, /* 7000415E */ + 0x0F120004, /* 70004160 */ + 0x0F12F000, /* 70004162 */ + 0x0F12F87D, /* 70004164 */ + 0x0F12466B, /* 70004166 */ + 0x0F1288D9, /* 70004168 */ + 0x0F128898, /* 7000416A */ + 0x0F124B1F, /* 7000416C */ + 0x0F123346, /* 7000416E */ + 0x0F121E9A, /* 70004170 */ + 0x0F12F000, /* 70004172 */ + 0x0F12F8F1, /* 70004174 */ + 0x0F12481E, /* 70004176 */ + 0x0F12491C, /* 70004178 */ + 0x0F123812, /* 7000417A */ + 0x0F123140, /* 7000417C */ + 0x0F128A42, /* 7000417E */ + 0x0F12888B, /* 70004180 */ + 0x0F1218D2, /* 70004182 */ + 0x0F128242, /* 70004184 */ + 0x0F128AC2, /* 70004186 */ + 0x0F1288C9, /* 70004188 */ + 0x0F121851, /* 7000418A */ + 0x0F1282C1, /* 7000418C */ + 0x0F120020, /* 7000418E */ + 0x0F124669, /* 70004190 */ + 0x0F12F000, /* 70004192 */ + 0x0F12F865, /* 70004194 */ + 0x0F124817, /* 70004196 */ + 0x0F12214D, /* 70004198 */ + 0x0F128301, /* 7000419A */ + 0x0F122196, /* 7000419C */ + 0x0F128381, /* 7000419E */ + 0x0F12211D, /* 700041A0 */ + 0x0F123020, /* 700041A2 */ + 0x0F128001, /* 700041A4 */ + 0x0F12F000, /* 700041A6 */ + 0x0F12F8DF, /* 700041A8 */ + 0x0F12F000, /* 700041AA */ + 0x0F12F8E5, /* 700041AC */ + 0x0F124812, /* 700041AE */ + 0x0F124C12, /* 700041B0 */ + 0x0F126E00, /* 700041B2 */ + 0x0F1260E0, /* 700041B4 */ + 0x0F12466B, /* 700041B6 */ + 0x0F128818, /* 700041B8 */ + 0x0F128859, /* 700041BA */ + 0x0F120025, /* 700041BC */ + 0x0F121A40, /* 700041BE */ + 0x0F123540, /* 700041C0 */ + 0x0F1261A8, /* 700041C2 */ + 0x0F124809, /* 700041C4 */ + 0x0F129900, /* 700041C6 */ + 0x0F123060, /* 700041C8 */ + 0x0F12F000, /* 700041CA */ + 0x0F12F8DD, /* 700041CC */ + 0x0F12466B, /* 700041CE */ + 0x0F128819, /* 700041D0 */ + 0x0F121DE0, /* 700041D2 */ + 0x0F1230F9, /* 700041D4 */ + 0x0F128741, /* 700041D6 */ + 0x0F128859, /* 700041D8 */ + 0x0F128781, /* 700041DA */ + 0x0F122000, /* 700041DC */ + 0x0F1271A0, /* 700041DE */ + 0x0F1274A8, /* 700041E0 */ + 0x0F12BC7C, /* 700041E2 */ + 0x0F12BC08, /* 700041E4 */ + 0x0F124718, /* 700041E6 */ + 0x0F122558, /* 700041E8 */ + 0x0F127000, /* 700041EA */ + 0x0F122AB8, /* 700041EC */ + 0x0F127000, /* 700041EE */ + 0x0F12145E, /* 700041F0 */ + 0x0F127000, /* 700041F2 */ + 0x0F122698, /* 700041F4 */ + 0x0F127000, /* 700041F6 */ + 0x0F122BB8, /* 700041F8 */ + 0x0F127000, /* 700041FA */ + 0x0F122998, /* 700041FC */ + 0x0F127000, /* 700041FE */ + 0x0F124778, /* 70004200 */ + 0x0F1246C0, /* 70004202 */ + 0x0F12C000, /* 70004204 */ + 0x0F12E59F, /* 70004206 */ + 0x0F12FF1C, /* 70004208 */ + 0x0F12E12F, /* 7000420A */ + 0x0F121789, /* 7000420C */ + 0x0F120001, /* 7000420E */ + 0x0F124778, /* 70004210 */ + 0x0F1246C0, /* 70004212 */ + 0x0F12C000, /* 70004214 */ + 0x0F12E59F, /* 70004216 */ + 0x0F12FF1C, /* 70004218 */ + 0x0F12E12F, /* 7000421A */ + 0x0F1216F1, /* 7000421C */ + 0x0F120001, /* 7000421E */ + 0x0F124778, /* 70004220 */ + 0x0F1246C0, /* 70004222 */ + 0x0F12C000, /* 70004224 */ + 0x0F12E59F, /* 70004226 */ + 0x0F12FF1C, /* 70004228 */ + 0x0F12E12F, /* 7000422A */ + 0x0F12C3B1, /* 7000422C */ + 0x0F120000, /* 7000422E */ + 0x0F124778, /* 70004230 */ + 0x0F1246C0, /* 70004232 */ + 0x0F12C000, /* 70004234 */ + 0x0F12E59F, /* 70004236 */ + 0x0F12FF1C, /* 70004238 */ + 0x0F12E12F, /* 7000423A */ + 0x0F12C36D, /* 7000423C */ + 0x0F120000, /* 7000423E */ + 0x0F124778, /* 70004240 */ + 0x0F1246C0, /* 70004242 */ + 0x0F12C000, /* 70004244 */ + 0x0F12E59F, /* 70004246 */ + 0x0F12FF1C, /* 70004248 */ + 0x0F12E12F, /* 7000424A */ + 0x0F12F6D7, /* 7000424C */ + 0x0F120000, /* 7000424E */ + 0x0F124778, /* 70004250 */ + 0x0F1246C0, /* 70004252 */ + 0x0F12C000, /* 70004254 */ + 0x0F12E59F, /* 70004256 */ + 0x0F12FF1C, /* 70004258 */ + 0x0F12E12F, /* 7000425A */ + 0x0F12B49D, /* 7000425C */ + 0x0F120000, /* 7000425E */ + 0x0F124778, /* 70004260 */ + 0x0F1246C0, /* 70004262 */ + 0x0F12C000, /* 70004264 */ + 0x0F12E59F, /* 70004266 */ + 0x0F12FF1C, /* 70004268 */ + 0x0F12E12F, /* 7000426A */ + 0x0F127EDF, /* 7000426C */ + 0x0F120000, /* 7000426E */ + 0x0F124778, /* 70004270 */ + 0x0F1246C0, /* 70004272 */ + 0x0F12C000, /* 70004274 */ + 0x0F12E59F, /* 70004276 */ + 0x0F12FF1C, /* 70004278 */ + 0x0F12E12F, /* 7000427A */ + 0x0F12448D, /* 7000427C */ + 0x0F120000, /* 7000427E */ + 0x0F124778, /* 70004280 */ + 0x0F1246C0, /* 70004282 */ + 0x0F12F004, /* 70004284 */ + 0x0F12E51F, /* 70004286 */ + 0x0F1229EC, /* 70004288 */ + 0x0F120001, /* 7000428A */ + 0x0F124778, /* 7000428C */ + 0x0F1246C0, /* 7000428E */ + 0x0F12C000, /* 70004290 */ + 0x0F12E59F, /* 70004292 */ + 0x0F12FF1C, /* 70004294 */ + 0x0F12E12F, /* 70004296 */ + 0x0F122EF1, /* 70004298 */ + 0x0F120000, /* 7000429A */ + 0x0F124778, /* 7000429C */ + 0x0F1246C0, /* 7000429E */ + 0x0F12C000, /* 700042A0 */ + 0x0F12E59F, /* 700042A2 */ + 0x0F12FF1C, /* 700042A4 */ + 0x0F12E12F, /* 700042A6 */ + 0x0F12EE03, /* 700042A8 */ + 0x0F120000, /* 700042AA */ + 0x0F124778, /* 700042AC */ + 0x0F1246C0, /* 700042AE */ + 0x0F12C000, /* 700042B0 */ + 0x0F12E59F, /* 700042B2 */ + 0x0F12FF1C, /* 700042B4 */ + 0x0F12E12F, /* 700042B6 */ + 0x0F12A58B, /* 700042B8 */ + 0x0F120000, /* 700042BA */ + 0x0F124778, /* 700042BC */ + 0x0F1246C0, /* 700042BE */ + 0x0F12C000, /* 700042C0 */ + 0x0F12E59F, /* 700042C2 */ + 0x0F12FF1C, /* 700042C4 */ + 0x0F12E12F, /* 700042C6 */ + 0x0F127C49, /* 700042C8 */ + 0x0F120000, /* 700042CA */ + 0x0F124778, /* 700042CC */ + 0x0F1246C0, /* 700042CE */ + 0x0F12C000, /* 700042D0 */ + 0x0F12E59F, /* 700042D2 */ + 0x0F12FF1C, /* 700042D4 */ + 0x0F12E12F, /* 700042D6 */ + 0x0F127C63, /* 700042D8 */ + 0x0F120000, /* 700042DA */ + 0x0F124778, /* 700042DC */ + 0x0F1246C0, /* 700042DE */ + 0x0F12C000, /* 700042E0 */ + 0x0F12E59F, /* 700042E2 */ + 0x0F12FF1C, /* 700042E4 */ + 0x0F12E12F, /* 700042E6 */ + 0x0F122DB7, /* 700042E8 */ + 0x0F120000, /* 700042EA */ + 0x0F124778, /* 700042EC */ + 0x0F1246C0, /* 700042EE */ + 0x0F12C000, /* 700042F0 */ + 0x0F12E59F, /* 700042F2 */ + 0x0F12FF1C, /* 700042F4 */ + 0x0F12E12F, /* 700042F6 */ + 0x0F12EB3D, /* 700042F8 */ + 0x0F120000, /* 700042FA */ + 0x0F124778, /* 700042FC */ + 0x0F1246C0, /* 700042FE */ + 0x0F12C000, /* 70004300 */ + 0x0F12E59F, /* 70004302 */ + 0x0F12FF1C, /* 70004304 */ + 0x0F12E12F, /* 70004306 */ + 0x0F12F061, /* 70004308 */ + 0x0F120000, /* 7000430A */ + 0x0F124778, /* 7000430C */ + 0x0F1246C0, /* 7000430E */ + 0x0F12C000, /* 70004310 */ + 0x0F12E59F, /* 70004312 */ + 0x0F12FF1C, /* 70004314 */ + 0x0F12E12F, /* 70004316 */ + 0x0F12F0EF, /* 70004318 */ + 0x0F120000, /* 7000431A */ + 0x0F124778, /* 7000431C */ + 0x0F1246C0, /* 7000431E */ + 0x0F12F004, /* 70004320 */ + 0x0F12E51F, /* 70004322 */ + 0x0F122824, /* 70004324 */ + 0x0F120001, /* 70004326 */ + 0x0F124778, /* 70004328 */ + 0x0F1246C0, /* 7000432A */ + 0x0F12C000, /* 7000432C */ + 0x0F12E59F, /* 7000432E */ + 0x0F12FF1C, /* 70004330 */ + 0x0F12E12F, /* 70004332 */ + 0x0F128EDD, /* 70004334 */ + 0x0F120000, /* 70004336 */ + 0x0F124778, /* 70004338 */ + 0x0F1246C0, /* 7000433A */ + 0x0F12C000, /* 7000433C */ + 0x0F12E59F, /* 7000433E */ + 0x0F12FF1C, /* 70004340 */ + 0x0F12E12F, /* 70004342 */ + 0x0F128DCB, /* 70004344 */ + 0x0F120000, /* 70004346 */ + 0x0F124778, /* 70004348 */ + 0x0F1246C0, /* 7000434A */ + 0x0F12C000, /* 7000434C */ + 0x0F12E59F, /* 7000434E */ + 0x0F12FF1C, /* 70004350 */ + 0x0F12E12F, /* 70004352 */ + 0x0F128E17, /* 70004354 */ + 0x0F120000, /* 70004356 */ + 0x0F124778, /* 70004358 */ + 0x0F1246C0, /* 7000435A */ + 0x0F12C000, /* 7000435C */ + 0x0F12E59F, /* 7000435E */ + 0x0F12FF1C, /* 70004360 */ + 0x0F12E12F, /* 70004362 */ + 0x0F1298C5, /* 70004364 */ + 0x0F120000, /* 70004366 */ + 0x0F124778, /* 70004368 */ + 0x0F1246C0, /* 7000436A */ + 0x0F12C000, /* 7000436C */ + 0x0F12E59F, /* 7000436E */ + 0x0F12FF1C, /* 70004370 */ + 0x0F12E12F, /* 70004372 */ + 0x0F127C7D, /* 70004374 */ + 0x0F120000, /* 70004376 */ + 0x0F124778, /* 70004378 */ + 0x0F1246C0, /* 7000437A */ + 0x0F12C000, /* 7000437C */ + 0x0F12E59F, /* 7000437E */ + 0x0F12FF1C, /* 70004380 */ + 0x0F12E12F, /* 70004382 */ + 0x0F127E31, /* 70004384 */ + 0x0F120000, /* 70004386 */ + 0x0F124778, /* 70004388 */ + 0x0F1246C0, /* 7000438A */ + 0x0F12C000, /* 7000438C */ + 0x0F12E59F, /* 7000438E */ + 0x0F12FF1C, /* 70004390 */ + 0x0F12E12F, /* 70004392 */ + 0x0F127EAB, /* 70004394 */ + 0x0F120000, /* 70004396 */ + /* End of Patch Data(Last : 70004396h)*/ + /* Total Size 2208 (08A0) */ + /* Addr : 3AF8 , Size : 2206(89Eh) */ + + /*#define TNP_USER_MBCV_CONTROL */ + /*#define TNP_4EC_MBR_TUNE */ + /*#define TNP_4EC_FORBIDDEN_TUNE */ + /*#define TNP_AF_FINESEARCH_DRIVEBACK */ + /*#define TNP_FLASH_ALG */ + /*#define TNP_GAS_ALPHA_OTP */ + /*#define TNP_AWB_MODUL_COMP */ + /*#define TNP_AWB_INIT_QUEUE */ + + /*TNP_Regs_usCintrTh 2 70004780 */ + /*TNP_Regs_usFixedCintc 2 70004782 */ + /*TNP_Regs_FlsWeightRIn_0_ 2 70004784 */ + /*TNP_Regs_FlsWeightRIn_1_ 2 70004786 */ + /*TNP_Regs_FlsWeightRIn_2_ 2 70004788 */ + /*TNP_Regs_FlsWeightRIn_3_ 2 7000478A */ + /*TNP_Regs_FlsWeightRIn_4_ 2 7000478C */ + /*TNP_Regs_FlsWeightRIn_5_ 2 7000478E */ + /*TNP_Regs_FlsWeightROut_0_ 2 70004790 */ + /*TNP_Regs_FlsWeightROut_1_ 2 70004792 */ + /*TNP_Regs_FlsWeightROut_2_ 2 70004794 */ + /*TNP_Regs_FlsWeightROut_3_ 2 70004796 */ + /*TNP_Regs_FlsWeightROut_4_ 2 70004798 */ + /*TNP_Regs_FlsWeightROut_5_ 2 7000479A */ + + /*TNP_Regs_FlBRIn_0_ 2 7000479C */ + /*TNP_Regs_FlBRIn_1_ 2 7000479E */ + /*TNP_Regs_FlBRIn_2_ 2 700047A0 */ + /*TNP_Regs_FlBRInOut_0_ 2 700047A2 */ + /*TNP_Regs_FlBRInOut_1_ 2 700047A4 */ + /*TNP_Regs_FlBRInOut_2_ 2 700047A6 */ + + 0x0028D000, + 0x002A1000, + 0x0F120001, + + /* AF setting */ + 0x00287000, + 0x002A01FC, + 0x0F120001, /* #REG_TC_IPRM_LedGpio */ + 0x002A1720, + 0x0F120100, + 0x002A01FE, + 0x0F120003, + 0x0F120000, + 0x002A0204, + 0x0F120061, + 0x002A020C, + 0x0F122F0C, + 0x0F120190, + 0x002A0294, + 0x0F120100, + 0x0F1200E3, + 0x0F120200, + 0x0F120238, + 0x0F1201C6, + 0x0F120166, + 0x0F120074, + 0x0F120132, + 0x0F120001, + + 0x002A070E, + 0x0F1200C0, + 0x002A071E, + 0x0F120001, + 0x002A163C, + 0x0F120000, + 0x002A1648, + 0x0F129002, + 0x002A1652, + 0x0F120002, + 0x0F120000, + 0x002A15E0, + 0x0F120902, + + 0x002A164C, + 0x0F120003, + 0x002A163E, + 0x0F1200D5, + 0x0F120098, + 0x002A15D4, + 0x0F120000, + 0x0F12D000, + 0x002A169A, + 0x0F12FF95, + 0x002A166A, + 0x0F120280, + 0x002A1676, + 0x0F1203A0, + 0x0F120320, + 0x002A16BC, + 0x0F120030, + 0x002A16E0, + 0x0F120060, + 0x002A16D4, + 0x0F120010, + 0x002A1656, + 0x0F120000, + 0x002A15E6, + 0x0F12003C, + + 0x0F120018, /*#af_pos_usTableLastInd*/ + 0x0F12002A, + 0x0F120030, + 0x0F120036, + 0x0F12003C, + 0x0F120042, + 0x0F120048, + 0x0F12004E, + 0x0F120054, + 0x0F12005A, + 0x0F120060, + 0x0F120066, + 0x0F12006C, + 0x0F120072, + 0x0F120078, + 0x0F12007E, + 0x0F120084, + 0x0F12008A, + 0x0F120090, + 0x0F120096, + 0x0F12009C, + 0x0F1200A2, + 0x0F1200A8, + 0x0F1200AE, + 0x0F1200B4, + 0x0F1200BA, /*#af_pos_usTable_24_*/ + + 0x002A1722, + 0x0F128000, + 0x0F120006, + 0x0F123FF0, + 0x0F1203E8, + 0x0F120000, + 0x0F120020, + 0x0F120010, + 0x0F120008, + 0x0F120040, + 0x0F120080, + 0x0F1200C0, + 0x0F1200E0, + + 0x002A028C, + 0x0F120003, /*#REG_TC_AF_AfCmd*/ + + /* GAS TBL setting */ + 0x002A08B4, + 0x0F120001, /*#wbt_bUseOutdoorASH*/ + + /*TVAR_ash_AwbAshCord, Refer Mon_AWB_RotGain*/ + 0x002A08BC, + 0x0F1200C0, /*#TVAR_ash_AwbAshCord_0_ 2300K*/ + 0x0F1200DF, /*#TVAR_ash_AwbAshCord_1_ 2750K*/ + 0x0F120100, /*#TVAR_ash_AwbAshCord_2_ 3300K*/ + 0x0F120125, /*#TVAR_ash_AwbAshCord_3_ 4150K*/ + 0x0F12015F, /*#TVAR_ash_AwbAshCord_4_ 5250K*/ + 0x0F12017C, /*#TVAR_ash_AwbAshCord_5_ 6400K*/ + 0x0F120194, /*#TVAR_ash_AwbAshCord_6_ 7500K*/ + + + 0x002A08F6, + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x0F124000, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x0F124500, + 0x0F124000, + 0x0F124000, + 0x0F124000, + + 0x002A08F4, + 0x0F120001, /*#ash_bUseGasAlpha*/ + + /* AE START */ + + /*AE WEIGHT */ + 0x002A1492, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120202, + 0x0F120202, + 0x0F120102, + + 0x002A1484, + 0x0F12003C, /*#TVAR_ae_BrAve*/ + 0x002A148A, + 0x0F12000F, /*#ae_StatMode*/ + 0x002A058C, + 0x0F123520, + 0x0F120000, /*#lt_uMaxExp1*/ + 0x0F12C350, + 0x0F120000, /*#lt_uMaxExp2*/ + 0x0F123520, + 0x0F120000, /*#lt_uCapMaxExp1*/ + 0x0F12C350, + 0x0F120000, /*#lt_uCapMaxExp2*/ + 0x0F120470, /*#lt_uMaxAnGain1*/ + 0x0F120C00, /*#lt_uMaxAnGain2*/ + 0x0F120100, /*#lt_uMaxDigGain*/ + 0x0F121000, /*#lt_uMaxTotGain*/ + + 0x002A0544, + 0x0F120111, /*#lt_uLimitHigh*/ + 0x0F1200EF, /*#lt_uLimitLow*/ + + 0x002A0F2A, + 0x0F120001, /*#AFC_Default60Hz*/ + 0x002A0F30, + 0x0F120002, /*#AFC_D_ConvAccelerPower*/ + + 0x002A0588, /*#lt_uInitPostToleranceCnt*/ + 0x0F120000, /*AE Speed-up*/ + + 0x002A0600, /*#lt_uleiInit*/ + 0x0F12D000, + + 0x002A0608, + 0x0F120001, /*#lt_ExpGain_uSubsamplingmode*/ + 0x0F120001, /*#lt_ExpGain_uNonSubsampling*/ + 0x0F120C00, /*#lt_ExpGain_ExpCurveGainMaxStr*/ + 0x0F120100, /*#lt_ExpGain_ExpCurveGainMaxStr_0__uMaxDigGain*/ + 0x0F120001, + 0x0F120000, /*#lt_ExpGain_ExpCurveGainMaxStr_0__ulExpIn_0_*/ + 0x0F120A3C, + 0x0F120000, + 0x0F120D04, + 0x0F120000, + 0x0F124008, + 0x0F120000, + 0x0F127000, + 0x0F120000, + 0x0F129C00, + 0x0F120000, + 0x0F12AD00, + 0x0F120001, + 0x0F12F1D4, + 0x0F120002, + 0x0F12DC00, + 0x0F120005, + 0x0F12DC00, + 0x0F120005, + 0x0F120001, + 0x0F120000, /*#lt_ExpGain_ExpCurveGainMaxStr_0__ulExpOut_0_*/ + 0x0F120A3C, + 0x0F120000, + 0x0F120D05, + 0x0F120000, + 0x0F123408, + 0x0F120000, + 0x0F123408, + 0x0F120000, + 0x0F126810, + 0x0F120000, + 0x0F128214, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F120650, /*#lt_ExpGain_ExpCurveGainMaxStr_1_*/ + 0x0F120100, /*#lt_ExpGain_ExpCurveGainMaxStr_1__uMaxDigGain*/ + + 0x002A06B8, + 0x0F12452C, + 0x0F12000C, /*#lt_uMaxLei*/ + + 0x002A05D0, + 0x0F120000, /*#lt_mbr_Peak_behind*/ + + /* AWB init Start point */ + 0x002A145E, + 0x0F120470, /* 0400 */ + 0x0F120400, /* 0428 */ + 0x0F1209F0, /* 9B3 */ + + /* AWB Init */ + /*White Locus */ + 0x002A11F0, + 0x0F12012C, /*#awbb_IntcR*/ + 0x0F120121, /*#awbb_IntcB*/ + + /* IndoorZone*/ + 0x002A101C, + 0x0F12039A, + 0x0F1203E8, + 0x0F12033C, + 0x0F1203AE, + 0x0F1202DE, + 0x0F120376, + 0x0F12029C, + 0x0F12033C, + 0x0F12027E, + 0x0F120312, + 0x0F12025E, + 0x0F1202F6, + 0x0F12023E, + 0x0F1202DA, + 0x0F12022A, + 0x0F1202BC, + 0x0F120214, + 0x0F1202A2, + 0x0F1201FE, + 0x0F120292, + 0x0F1201F0, + 0x0F120284, + 0x0F1201E0, + 0x0F120276, + 0x0F1201D2, + 0x0F120266, + 0x0F1201C4, + 0x0F120258, + 0x0F1201D8, + 0x0F120216, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x0F120005, /*#awbb_IndoorGrZones_m_GridStep*/ + 0x002A1070, + 0x0F12000F, /*#awbb_IndoorGrZones_ZInfo_m_GridSz*/ + 0x002A1074, + 0x0F12013C, /*#awbb_IndoorGrZones_m_Boffs*/ + + /*Outdoor Zone*/ + 0x002A1078, + 0x0F120254, + 0x0F120296, + 0x0F120246, + 0x0F1202B4, + 0x0F120238, + 0x0F1202B8, + 0x0F12022A, + 0x0F1202B0, + 0x0F12021C, + 0x0F1202A6, + 0x0F12021A, + 0x0F12029C, + 0x0F12021A, + 0x0F120292, + 0x0F120220, + 0x0F120288, + 0x0F120226, + 0x0F12027E, + 0x0F120244, + 0x0F120274, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x0F120004, /*#awbb_OutdoorGrZones_m_GridStep*/ + 0x002A10AC, + 0x0F12000A, /*#awbb_OutdoorGrZones_ZInfo_m_GridSz*/ + 0x002A10B0, + 0x0F1201EE, /*#awbb_OutdoorGrZones_m_Boffs*/ + + /*LowBR Zone*/ + 0x002A10B4, + 0x0F120350, + 0x0F120422, + 0x0F1202C4, + 0x0F120452, + 0x0F120278, + 0x0F12041C, + 0x0F120230, + 0x0F1203EE, + 0x0F1201F0, + 0x0F120392, + 0x0F1201C0, + 0x0F120340, + 0x0F120194, + 0x0F120302, + 0x0F12016E, + 0x0F1202C2, + 0x0F120148, + 0x0F120286, + 0x0F12018A, + 0x0F120242, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + + 0x0F120006, /*#awbb_LowBrGrZones_m_GridStep*/ + 0x002A10E8, + 0x0F12000A, /*#awbb_LowBrGrZones_ZInfo_m_GridSz*/ + 0x002A10EC, + 0x0F120106, /*#awbb_LowBrGrZones_m_Boffs*/ + + /*LowTemp Zone*/ + 0x002A10F0, + 0x0F120380, + 0x0F120000, /*#awbb_CrclLowT_R_c*/ + 0x0F120168, + 0x0F120000, /*#awbb_CrclLowT_B_c*/ + 0x0F122D90, + 0x0F120000, /*#awbb_CrclLowT_Rad_c*/ + + /*AWB Convergence Speed*/ + 0x002A1464, + 0x0F120008, + 0x0F120190, + 0x0F1200A0, + + 0x002A1228, + 0x0F1200C0, + 0x002A122C, + 0x0F120010, + 0x002A122A, + 0x0F120010, + + 0x002A120A, + 0x0F1205D5, /*#awbb_MvEq_RBthresh*/ + 0x002A120E, + 0x0F120000, + + 0x0F120771, + 0x0F1203A4, + 0x0F120036, + 0x0F12002A, + + 0x002A1278, + 0x0F12FEF7, + 0x0F120021, + 0x0F120E74, + 0x0F120E74, + 0x0F12018F, + 0x0F120096, + 0x0F12000E, + 0x002A1224, + 0x0F120032, + 0x0F12001E, + 0x0F1200C0, + 0x0F120010, + 0x0F120002, /*awbb_YThreshLow_Low */ + 0x002A2BA4, + 0x0F120006, /*#Mon_AWB_ByPassMode*/ + + 0x002A146C, + 0x0F120002, /*#awbb_GridEnable*/ + + /*Grid*/ + 0x002A1434, + 0x0F120300, /* awbb_GridConst_1 */ + 0x0F12036E, /* awbb_GridConst_1_1_ */ + 0x0F1203C2, /* awbb_GridConst_1_2_ */ + 0x0F121074, /* awbb_GridConst_2 */ + 0x0F1210C2, /* awbb_GridConst_2_1_ */ + 0x0F121104, /* awbb_GridConst_2_2_ */ + 0x0F121142, /* awbb_GridConst_2_3_ */ + 0x0F1211BB, /* awbb_GridConst_2_4_ */ + 0x0F12123B, /* awbb_GridConst_2_5_ */ + 0x0F1200AB, /* awbb_GridCoeff_R_1 */ + 0x0F1200BF, /* awbb_GridCoeff_B_1 */ + 0x0F1200D2, /* awbb_GridCoeff_R_2 */ + 0x0F120093, /* awbb_GridCoeff_B_2 */ + + /*Indoor Grid Offset*/ + 0x002A13A4, + 0x0F120000, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F120000, + 0x0F120008, + 0x0F120018, + 0x0F120000, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F120000, + 0x0F120008, + 0x0F120018, + 0x0F120000, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F120000, + 0x0F120008, + 0x0F120018, + 0x0F12FFE0, + 0x0F12FFE0, + 0x0F12FFC0, + 0x0F12FFC0, + 0x0F12FFB0, + 0x0F12FFB0, + 0x0F12FFE0, + 0x0F12FFE0, + 0x0F12FFC0, + 0x0F12FFC0, + 0x0F12FFB0, + 0x0F12FFB0, + 0x0F12FFE0, + 0x0F12FFE0, + 0x0F12FFC0, + 0x0F12FFC0, + 0x0F12FFB0, + 0x0F12FFB0, + + /*Outdoor Grid Offset*/ + 0x0F12FFB0, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F120000, + 0x0F120000, + 0x0F12FFB0, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F120000, + 0x0F120000, + 0x0F12FFB0, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F12FFD0, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F12FFC8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F120000, + 0x0F12FFC8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F120000, + 0x0F12FFC8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F12FFB8, + 0x0F12FFB8, + + 0x002A1208, + 0x0F120020, + + 0x002A144E, + 0x0F120000, /*#awbb_RGainOff*/ + 0x0F120000, /*#awbb_BGainOff*/ + 0x0F120000, /*#awbb_GGainOff*/ + + /*RGB Indoor Gamma*/ + 0x002A0734, + 0x0F120001, + 0x0F120007, + 0x0F120011, + 0x0F12002D, + 0x0F12006B, + 0x0F1200DC, + 0x0F12013B, + 0x0F120166, + 0x0F12018D, + 0x0F1201CD, + 0x0F120204, + 0x0F120235, + 0x0F120260, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + 0x0F120001, + 0x0F120007, + 0x0F120011, + 0x0F12002D, + 0x0F12006B, + 0x0F1200DC, + 0x0F12013B, + 0x0F120166, + 0x0F12018D, + 0x0F1201CD, + 0x0F120204, + 0x0F120235, + 0x0F120260, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + 0x0F120001, + 0x0F120007, + 0x0F120011, + 0x0F12002D, + 0x0F12006B, + 0x0F1200DC, + 0x0F12013B, + 0x0F120166, + 0x0F12018D, + 0x0F1201CD, + 0x0F120204, + 0x0F120235, + 0x0F120260, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + + /*RGB Outdoor Gamma*/ + 0x0F120001, + 0x0F120007, + 0x0F120011, + 0x0F12002D, + 0x0F12006B, + 0x0F1200DC, + 0x0F12013B, + 0x0F120166, + 0x0F12018D, + 0x0F1201CD, + 0x0F120204, + 0x0F120235, + 0x0F120260, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + 0x0F120001, + 0x0F120007, + 0x0F120011, + 0x0F12002D, + 0x0F12006B, + 0x0F1200DC, + 0x0F12013B, + 0x0F120166, + 0x0F12018D, + 0x0F1201CD, + 0x0F120204, + 0x0F120235, + 0x0F120260, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + 0x0F120001, + 0x0F120007, + 0x0F120011, + 0x0F12002D, + 0x0F12006B, + 0x0F1200DC, + 0x0F12013B, + 0x0F120166, + 0x0F12018D, + 0x0F1201CD, + 0x0F120204, + 0x0F120235, + 0x0F120260, + 0x0F1202AA, + 0x0F1202EC, + 0x0F12034E, + 0x0F120396, + 0x0F1203C6, + 0x0F1203E9, + 0x0F1203F9, + + /*CCM*/ + 0x002A08A6, + 0x0F1200C0, + 0x0F1200D0, + 0x0F1200E0, + 0x0F120110, + 0x0F12017C, + 0x0F120194, + + 0x0F120001, + + 0x002A0898, + 0x0F124800, + 0x0F127000, + 0x002A08A0, + 0x0F1248D8, + 0x0F127000, + + 0x002A4800, + 0x0F12010F, /*hor*/ + 0x0F12FF90, + 0x0F12FF7D, + 0x0F12FEF1, + 0x0F120137, + 0x0F12FF68, + 0x0F12FFEE, + 0x0F12FF8A, + 0x0F12013A, + 0x0F12006E, + 0x0F120089, + 0x0F12FEFE, + 0x0F120175, + 0x0F12FF4A, + 0x0F1200D6, + 0x0F12FEFE, + 0x0F120113, + 0x0F1200E6, + 0x0F12010F, /*incaA*/ + 0x0F12FF90, + 0x0F12FF7D, + 0x0F12FEF1, + 0x0F120137, + 0x0F12FF68, + 0x0F12FFEE, + 0x0F12FF8A, + 0x0F12013A, + 0x0F12006E, + 0x0F120089, + 0x0F12FEFE, + 0x0F120175, + 0x0F12FF4A, + 0x0F1200D6, + 0x0F12FEFE, + 0x0F120113, + 0x0F1200E6, + 0x0F12010F, /*WW*/ + 0x0F12FF90, + 0x0F12FF7D, + 0x0F12FEF1, + 0x0F120137, + 0x0F12FF68, + 0x0F12FFEE, + 0x0F12FF8A, + 0x0F12013A, + 0x0F12006E, + 0x0F120089, + 0x0F12FEFE, + 0x0F120175, + 0x0F12FF4A, + 0x0F1200D6, + 0x0F12FEFE, + 0x0F120113, + 0x0F1200E6, + 0x0F12017B, /*CW*/ + 0x0F12FFB5, + 0x0F12FFF9, + 0x0F12FF5E, + 0x0F12019D, + 0x0F12FFA2, + 0x0F12FFD9, + 0x0F12FFCB, + 0x0F12012C, + 0x0F1200C9, + 0x0F1200B0, + 0x0F12FF2F, + 0x0F1200CA, + 0x0F12FF91, + 0x0F12015E, + 0x0F12FF47, + 0x0F120129, + 0x0F120125, + 0x0F1201AF, /*D50*/ + 0x0F12FFBA, + 0x0F12FFF1, + 0x0F12FF27, + 0x0F1201DE, + 0x0F12FF77, + 0x0F12FFCB, + 0x0F12FFC5, + 0x0F120136, + 0x0F120110, + 0x0F1200EF, + 0x0F12FFA0, + 0x0F1200A3, + 0x0F12FF7B, + 0x0F12018C, + 0x0F12FF1D, + 0x0F120138, + 0x0F120138, + 0x0F1201AF, /*D65*/ + 0x0F12FFBA, + 0x0F12FFF1, + 0x0F12FF27, + 0x0F1201DE, + 0x0F12FF77, + 0x0F12FFCB, + 0x0F12FFC5, + 0x0F120136, + 0x0F120110, + 0x0F1200EF, + 0x0F12FFA0, + 0x0F1200A3, + 0x0F12FF7B, + 0x0F12018C, + 0x0F12FF1D, + 0x0F120138, + 0x0F120138, + + 0x0F12019F, /*#TVAR_wbt_pOutdoorCcm[0]*/ + 0x0F12FFBF, + 0x0F12FFFD, + 0x0F12FF10, + 0x0F1201D4, + 0x0F12FFA4, + 0x0F12FFE8, + 0x0F12FFE0, + 0x0F1201C2, + 0x0F120087, + 0x0F1200A5, + 0x0F12FF17, + 0x0F1201DD, + 0x0F12FF0E, + 0x0F12010B, + 0x0F12FF24, + 0x0F1200F0, + 0x0F1201DB, + + + /*System Setting*/ + 0x002A01F8, + 0x0F125DC0, /*#REG_TC_IPRM_InClockLSBs, MCLK: 24Mhz*/ + 0x002A0212, + 0x0F120002, /*#REG_TC_IPRM_UseNPviClocks*/ + 0x0F120000, /*#REG_TC_IPRM_UseNMipiClocks*/ + 0x0F120000, /*#REG_TC_IPRM_NumberOfMipiLanes*/ + 0x002A021A, + 0x0F123A98, /*#REG_TC_IPRM_OpClk4KHz_0, SCLK: 60Mhz*/ + 0x0F124F1A, /*#REG_TC_IPRM_MinOutRate4KHz_0 PCLK Min : 81Mhz*/ + 0x0F124F1A, /*#REG_TC_IPRM_MaxOutRate4KHz_0 PCLK Max : 81Mhz*/ + 0x0F124F1A, /*#REG_TC_IPRM_OpClk4KHz_1 SCLK : 81Mhz*/ + 0x0F124F1A, /*#REG_TC_IPRM_MinOutRate4KHz_1 PCLK Min : 81Mhz*/ + 0x0F124F1A, /*#REG_TC_IPRM_MaxOutRate4KHz_1 PCLK Max : 81Mhz*/ + 0x002A022C, + 0x0F120001, /*#REG_TC_IPRM_InitParamsUpdated*/ + + /*ETC.. Setting*/ + 0x002A0478, + 0x0F12005F, /*#REG_TC_BRC_usPrevQuality*/ + 0x0F12005F, /*#REG_TC_BRC_usCaptureQuality*/ + + 0x0F120001, /*#REG_TC_THUMB_Thumb_bActive*/ + 0x0F120280, /*#REG_TC_THUMB_Thumb_uWidth*/ + 0x0F1201E0, /*#REG_TC_THUMB_Thumb_uHeight*/ + 0x0F120005, /*#REG_TC_THUMB_Thumb_Format*/ + + 0x002A17DC, + 0x0F120054, /*#jpeg_ManualMBCV*/ + 0x002A1AE4, + 0x0F12001C, /*#senHal_bExtraAddLine*/ + 0x002A0284, + 0x0F120001, /*#REG_TC_GP_bBypassScalerJpg*/ + 0x002A028A, + 0x0F120001, /*#REG_TC_GP_bUse1FrameCaptureMode*/ + /*0 : Continuous mode,1 : Single frame mode*/ + + /*Configuration Setting*/ + 0x002A02A6, + 0x0F120280, /*#REG_0TC_PCFG_usWidth : 640*/ + 0x0F1201E0, /*#REG_0TC_PCFG_usHeight : 480*/ + 0x0F120005, /*#REG_0TC_PCFG_Format 5 : YUV 7 : Raw 9 : JPG*/ + 0x0F124F1A, /*#REG_0TC_PCFG_usMaxOut4KHzRate*/ + 0x0F124F1A, /*#REG_0TC_PCFG_usMinOut4KHzRate*/ + 0x0F120100, /*#REG_0TC_PCFG_OutClkPerPix88*/ + 0x0F120300, /*#REG_0TC_PCFG_uBpp88*/ + 0x0F120052, /*#REG_0TC_PCFG_PVIMask*/ + 0x0F120000, /*#REG_0TC_PCFG_OIFMask*/ + 0x0F1201E0, /*#REG_0TC_PCFG_usJpegPacketSize*/ + 0x0F120000, /*#REG_0TC_PCFG_usJpegTotalPackets*/ + 0x0F120000, /*#REG_0TC_PCFG_uClockInd*/ + 0x0F120000, /*#REG_0TC_PCFG_usFrTimeType*/ + 0x0F120001, /*#REG_0TC_PCFG_FrRateQualityType*/ + 0x0F12029A, /*#REG_0TC_PCFG_usMaxFrTimeMsecMult10*/ + 0x0F12014A, /*#REG_0TC_PCFG_usMinFrTimeMsecMult10*/ + 0x002A02D0, + 0x0F120000, /*#REG_0TC_PCFG_uPrevMirror*/ + 0x0F120000, /*#REG_0TC_PCFG_uCaptureMirror*/ + 0x0F120000, /*#REG_0TC_PCFG_uRotation*/ + + 0x002A0396, + 0x0F120000, /*#REG_0TC_CCFG_uCaptureMode*/ + 0x0F120A00, /*#REG_0TC_CCFG_usWidth*/ + 0x0F120780, /*#REG_0TC_CCFG_usHeight*/ + 0x0F120009, /*#REG_0TC_CCFG_Format*/ + 0x0F124F1A, /*#REG_0TC_CCFG_usMaxOut4KHzRate*/ + 0x0F124F1A, /*#REG_0TC_CCFG_usMinOut4KHzRate*/ + 0x0F120100, /*#REG_0TC_CCFG_OutClkPerPix88*/ + 0x0F120300, /*#REG_0TC_CCFG_uBpp88*/ + 0x0F120042, /*#REG_0TC_CCFG_PVIMask*/ + 0x0F120000, /*#REG_0TC_CCFG_OIFMask*/ + 0x0F1201E0, /*#REG_0TC_CCFG_usJpegPacketSize*/ + 0x0F120000, /*#REG_0TC_CCFG_usJpegTotalPackets*/ + 0x0F120001, /*#REG_0TC_CCFG_uClockInd*/ + 0x0F120000, /*#REG_0TC_CCFG_usFrTimeType*/ + 0x0F120002, /*#REG_0TC_CCFG_FrRateQualityType*/ + 0x0F120535, /*#REG_0TC_CCFG_usMaxFrTimeMsecMult10*/ + 0x0F12029A, /*#REG_0TC_CCFG_usMinFrTimeMsecMult10*/ + + 0x002A0250, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x002A0494, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + + 0x002A0262, + 0x0F120001, + 0x0F120001, + 0x0F120000, /*#REG_TC_GP_ActivePrevConfig*/ + 0x002A026A, + 0x0F120001, /*#REG_TC_GP_PrevOpenAfterChange*/ + 0x002A024E, + 0x0F120001, /*#REG_TC_GP_NewConfigSync*/ + 0x002A0268, + 0x0F120001, /*#REG_TC_GP_PrevConfigChanged*/ + 0x002A0270, + 0x0F120001, /*#REG_TC_GP_CapConfigChanged*/ + 0x002A023E, + 0x0F120001, /*#REG_TC_GP_EnablePreview*/ + 0x0F120001, /*#REG_TC_GP_EnablePreviewChanged*/ + + + /*AFIT*/ + 0x002A0944, + 0x0F120050, /*#afit_uNoiseIndInDoor_0_*/ + 0x0F120103, /*#afit_uNoiseIndInDoor_1_*/ + 0x0F120196, /*#afit_uNoiseIndInDoor_2_*/ + 0x0F120245, /*#afit_uNoiseIndInDoor_3_*/ + 0x0F120300, /*#afit_uNoiseIndInDoor_4_*/ + + 0x002A097A, + 0x0F120001, /*#afit_bUseSenBpr*/ + 0x0F1201CC, /*#afit_usBprThr_0_*/ + 0x0F1201CC, /*#afit_usBprThr_1_*/ + 0x0F1201CC, /*#afit_usBprThr_2_*/ + 0x0F1201CC, /*#afit_usBprThr_3_*/ + 0x0F1201CC, /*#afit_usBprThr_4_*/ + 0x0F120180, /*#afit_NIContrastAFITValue*/ + 0x0F120196, /*#afit_NIContrastTh*/ + + 0x002A0976, + 0x0F120070, + 0x0F120005, + + 0x002A0938, + 0x0F120000, + 0x0F120014, /*#SARR_uNormBrInDoor_0_*/ + 0x0F1200D2, /*#SARR_uNormBrInDoor_1_*/ + 0x0F120384, /*#SARR_uNormBrInDoor_2_*/ + 0x0F1207D0, /*#SARR_uNormBrInDoor_3_*/ + 0x0F121388, /*#SARR_uNormBrInDoor_4_*/ + + 0x002A098C, + 0x0F120000, /*AFIT 0*/ + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F12005F, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120040, + 0x0F1200A0, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F123604, + 0x0F12032A, + 0x0F120403, + 0x0F121B06, + 0x0F126015, + 0x0F1200C0, + 0x0F126080, + 0x0F124080, + 0x0F120640, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120000, + 0x0F120400, + 0x0F12365A, + 0x0F12102A, + 0x0F12000B, + 0x0F120600, + 0x0F125A0F, + 0x0F120505, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123028, + 0x0F120418, + 0x0F120101, + 0x0F120800, + 0x0F121804, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120705, + 0x0F120206, + 0x0F120304, + 0x0F120309, + 0x0F120305, + 0x0F122006, + 0x0F121320, + 0x0F121014, + 0x0F121010, + 0x0F120C10, + 0x0F121A0C, + 0x0F124A18, + 0x0F120080, + 0x0F120050, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F122A36, + 0x0F126024, + 0x0F122A36, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F123601, + 0x0F12242A, + 0x0F123660, + 0x0F12FF2A, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, /*AFIT 1*/ + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120051, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F122404, + 0x0F12031B, + 0x0F120103, + 0x0F121205, + 0x0F12400D, + 0x0F120080, + 0x0F121980, + 0x0F12272E, + 0x0F120629, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120300, + 0x0F12245A, + 0x0F121018, + 0x0F12000B, + 0x0F120B00, + 0x0F125A0F, + 0x0F120505, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123828, + 0x0F120425, + 0x0F120101, + 0x0F120800, + 0x0F121004, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120205, + 0x0F120304, + 0x0F120409, + 0x0F120306, + 0x0F120407, + 0x0F122204, + 0x0F12021C, + 0x0F121102, + 0x0F120611, + 0x0F121A02, + 0x0F128018, + 0x0F120080, + 0x0F120074, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F12141D, + 0x0F126024, + 0x0F121217, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F122401, + 0x0F12241B, + 0x0F121E60, + 0x0F12FF18, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, /*AFIT 2*/ + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120043, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F121B04, + 0x0F120312, + 0x0F120003, + 0x0F120C03, + 0x0F122806, + 0x0F120060, + 0x0F121580, + 0x0F122020, + 0x0F120620, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120300, + 0x0F12145A, + 0x0F121010, + 0x0F12000B, + 0x0F120E00, + 0x0F125A0F, + 0x0F120504, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123828, + 0x0F120428, + 0x0F120101, + 0x0F128000, + 0x0F120A04, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120207, + 0x0F120304, + 0x0F120409, + 0x0F120306, + 0x0F120407, + 0x0F122404, + 0x0F120221, + 0x0F121202, + 0x0F120613, + 0x0F121A02, + 0x0F128018, + 0x0F120080, + 0x0F120080, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F12121B, + 0x0F126024, + 0x0F120C0C, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F121B01, + 0x0F122412, + 0x0F120C60, + 0x0F12FF0C, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, /*AFIT 3*/ + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120032, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F121504, + 0x0F12030F, + 0x0F120003, + 0x0F120902, + 0x0F122004, + 0x0F120050, + 0x0F121140, + 0x0F12201C, + 0x0F120620, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120300, + 0x0F12145A, + 0x0F121010, + 0x0F12000B, + 0x0F121000, + 0x0F125A0F, + 0x0F120503, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F123C28, + 0x0F12042C, + 0x0F120101, + 0x0F12FF00, + 0x0F120904, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120206, + 0x0F120304, + 0x0F120409, + 0x0F120305, + 0x0F120406, + 0x0F122804, + 0x0F120228, + 0x0F121402, + 0x0F120618, + 0x0F121A02, + 0x0F128018, + 0x0F120080, + 0x0F120080, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F120F15, + 0x0F126024, + 0x0F120A0A, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F121501, + 0x0F12240F, + 0x0F120A60, + 0x0F12FF0A, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F120000, /*AFIT 4*/ + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F1200C0, + 0x0F120064, + 0x0F120384, + 0x0F120032, + 0x0F1201F4, + 0x0F120070, + 0x0F120040, + 0x0F1200A0, + 0x0F120100, + 0x0F120010, + 0x0F120060, + 0x0F120100, + 0x0F121430, + 0x0F120201, + 0x0F120204, + 0x0F120F04, + 0x0F12030C, + 0x0F120003, + 0x0F120602, + 0x0F121803, + 0x0F120040, + 0x0F120E20, + 0x0F122018, + 0x0F120620, + 0x0F120306, + 0x0F122003, + 0x0F12FF01, + 0x0F120404, + 0x0F120200, + 0x0F12145A, + 0x0F121010, + 0x0F12000B, + 0x0F121200, + 0x0F125A0F, + 0x0F120502, + 0x0F121802, + 0x0F120000, + 0x0F122006, + 0x0F124028, + 0x0F120430, + 0x0F120101, + 0x0F12FF00, + 0x0F120804, + 0x0F124008, + 0x0F120540, + 0x0F128006, + 0x0F120020, + 0x0F120000, + 0x0F121800, + 0x0F120000, + 0x0F121E10, + 0x0F12000B, + 0x0F120607, + 0x0F120005, + 0x0F120607, + 0x0F120405, + 0x0F120205, + 0x0F120304, + 0x0F120409, + 0x0F120306, + 0x0F120407, + 0x0F122C04, + 0x0F12022C, + 0x0F121402, + 0x0F120618, + 0x0F121A02, + 0x0F128018, + 0x0F120080, + 0x0F120080, + 0x0F120180, + 0x0F120A0A, + 0x0F120101, + 0x0F120C0F, + 0x0F126024, + 0x0F120808, + 0x0F12FFFF, + 0x0F120808, + 0x0F120A01, + 0x0F12010A, + 0x0F120F01, + 0x0F12240C, + 0x0F120860, + 0x0F12FF08, + 0x0F1208FF, + 0x0F120008, + 0x0F120001, + 0x0F1223CE, + 0x0F12FDC8, + 0x0F12112E, + 0x0F1283A5, + 0x0F12FE67, + 0x0F120000, + + 0x002A0588, /*lt_uInitPostToleranceCnt*/ + 0x0F120002, /*AE Speed Normal*/ + +}; + +static const u32 s5k4ecgx_DTP_init[] = { + 0x0028D000, + 0x002AB054, + 0x0F120001, + 0x00287000, +}; + +static const u32 s5k4ecgx_DTP_stop[] = { + 0x0028D000, + 0x002AB054, + 0x0F120000, + 0x00287000, +}; + +static const u32 s5k4ecgx_FPS_Auto[] = { + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014A, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, +}; + +static const u32 s5k4ecgx_FPS_5[] = { + +}; + +static const u32 s5k4ecgx_FPS_7[] = { + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F120535, + 0x0F120535, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, +}; + +static const u32 s5k4ecgx_FPS_10[] = { + +}; + +static const u32 s5k4ecgx_FPS_15[] = { + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12029A, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, +}; + +static const u32 s5k4ecgx_FPS_30[] = { + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F12014D, + 0x0F12014D, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, +}; + +static const u32 s5k4ecgx_FPS_60[] = { + +}; + +static const u32 s5k4ecgx_FPS_120[] = { + +}; + +static const u32 s5k4ecgx_Effect_Normal[] = { + 0x002A023C, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Effect_Solarization[] = { + 0x002A023C, + 0x0F120002, +}; + +static const u32 s5k4ecgx_Effect_Negative[] = { + 0x002A023C, + 0x0F120003, +}; + +static const u32 s5k4ecgx_Effect_Sepia[] = { + 0x002A023C, + 0x0F120004, +}; + +static const u32 s5k4ecgx_Effect_Black_White[] = { + 0x002A023C, + 0x0F120001, +}; + + +static const u32 s5k4ecgx_WB_Auto[] = { + 0x002A04E6, + 0x0F12077F, +}; + +static const u32 s5k4ecgx_WB_Sunny[] = { + 0x002A04E6, + 0x0F120777, + 0x002A04BA, + 0x0F1205E0, + 0x0F120001, + 0x0F120400, + 0x0F120001, + 0x0F120530, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_WB_Cloudy[] = { + 0x002A04E6, + 0x0F120777, + 0x002A04BA, + 0x0F120710, + 0x0F120001, + 0x0F120400, + 0x0F120001, + 0x0F120420, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_WB_Tungsten[] = { + 0x002A04E6, + 0x0F120777, + 0x002A04BA, + 0x0F120390, + 0x0F120001, + 0x0F120400, + 0x0F120001, + 0x0F120920, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_WB_Fluorescent[] = { + 0x002A04E6, + 0x0F120777, + 0x002A04BA, + 0x0F120505, + 0x0F120001, + 0x0F120400, + 0x0F120001, + 0x0F120875, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_WDR_on[] = { + 0x002A1BEA, + 0x0F120000, +}; + +static const u32 s5k4ecgx_WDR_off[] = { + 0x002A1BEA, + 0x0F120001, +}; + +static const u32 s5k4ecgx_ISO_Auto[] = { + 0x002A0938, + 0x0F120000, + + 0x002A0F2A, + 0x0F120001, + 0x002A04E6, + 0x0F12077F, + + 0x002A04D0, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x002A06C2, + 0x0F120200, +}; + +static const u32 s5k4ecgx_ISO_100[] = { + 0x002A04E6, + 0x0F12065F, + 0x002A04D6, + 0x0F120000, + 0x0F120001, + + 0x002A04D0, + 0x0F120001, + 0x0F1201A0, + 0x0F120001, + 0x002A06C2, + 0x0F120100, + + 0x002A0938, + 0x0F120001, +}; + +static const u32 s5k4ecgx_ISO_200[] = { + 0x002A04E6, + 0x0F12065F, + 0x002A04D6, + 0x0F120000, + 0x0F120001, + + 0x002A04D0, + 0x0F120001, + 0x0F120340, + 0x0F120001, + 0x002A06C2, + 0x0F120100, + + 0x002A0938, + 0x0F120001, +}; + +static const u32 s5k4ecgx_ISO_400[] = { + 0x002A04E6, + 0x0F12065F, + 0x002A04D6, + 0x0F120000, + 0x0F120001, + + 0x002A04D0, + 0x0F120001, + 0x0F120680, + 0x0F120001, + 0x002A06C2, + 0x0F120100, + + 0x002A0938, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Metering_Matrix[] = { + 0x002A1492, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, +}; + +static const u32 s5k4ecgx_Metering_Center[] = { + 0x002A1492, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120202, + 0x0F120202, + 0x0F120102, +}; + +static const u32 s5k4ecgx_Metering_Spot[] = { + 0x002A1492, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120000, + 0x0F12010F, + 0x0F120F01, + 0x0F120000, + 0x0F120000, + 0x0F12010F, + 0x0F120F01, + 0x0F120000, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, +}; + +static const u32 s5k4ecgx_EV_Minus_4[] = { + 0x002A0230, + 0x0F12FF30, +}; + +static const u32 s5k4ecgx_EV_Minus_3[] = { + 0x002A0230, + 0x0F12FFA0, +}; + +static const u32 s5k4ecgx_EV_Minus_2[] = { + 0x002A0230, + 0x0F12FFC8, +}; + +static const u32 s5k4ecgx_EV_Minus_1[] = { + 0x002A0230, + 0x0F12FFE0, +}; + +static const u32 s5k4ecgx_EV_Default[] = { + 0x002A0230, + 0x0F120000, +}; + +static const u32 s5k4ecgx_EV_Plus_1[] = { + 0x002A0230, + 0x0F120020, +}; + +static const u32 s5k4ecgx_EV_Plus_2[] = { + 0x002A0230, + 0x0F120038, +}; + +static const u32 s5k4ecgx_EV_Plus_3[] = { + 0x002A0230, + 0x0F120060, +}; + +static const u32 s5k4ecgx_EV_Plus_4[] = { + 0x002A0230, + 0x0F12007F, +}; + +static const u32 s5k4ecgx_Contrast_Minus_4[] = { + 0x002A0232, + 0x0F12FF81, +}; + +static const u32 s5k4ecgx_Contrast_Minus_3[] = { + 0x002A0232, + 0x0F12FFA0, +}; + +static const u32 s5k4ecgx_Contrast_Minus_2[] = { + 0x002A0232, + 0x0F12FFC0, +}; + +static const u32 s5k4ecgx_Contrast_Minus_1[] = { + 0x002A0232, + 0x0F12FFE0, +}; + +static const u32 s5k4ecgx_Contrast_Default[] = { + 0x002A0232, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Contrast_Plus_1[] = { + 0x002A0232, + 0x0F120020, +}; + +static const u32 s5k4ecgx_Contrast_Plus_2[] = { + 0x002A0232, + 0x0F120040, +}; + +static const u32 s5k4ecgx_Contrast_Plus_3[] = { + 0x002A0232, + 0x0F120060, +}; + +static const u32 s5k4ecgx_Contrast_Plus_4[] = { + 0x002A0232, + 0x0F12007F, +}; + +static const u32 s5k4ecgx_Sharpness_Minus_3[] = { + 0x002A0A28, + 0x0F120000, + 0x002A0ADE, + 0x0F120000, + 0x002A0B94, + 0x0F120000, + 0x002A0C4A, + 0x0F120000, + 0x002A0D00, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Sharpness_Minus_2[] = { + 0x002A0A28, + 0x0F122010, + 0x002A0ADE, + 0x0F122010, + 0x002A0B94, + 0x0F122010, + 0x002A0C4A, + 0x0F122010, + 0x002A0D00, + 0x0F122010, +}; + +static const u32 s5k4ecgx_Sharpness_Minus_1[] = { + 0x002A0A28, + 0x0F124020, + 0x002A0ADE, + 0x0F124020, + 0x002A0B94, + 0x0F124020, + 0x002A0C4A, + 0x0F124020, + 0x002A0D00, + 0x0F124020, +}; + +static const u32 s5k4ecgx_Sharpness_Default[] = { + 0x002A0A28, + 0x0F126024, + 0x002A0ADE, + 0x0F126024, + 0x002A0B94, + 0x0F126024, + 0x002A0C4A, + 0x0F126024, + 0x002A0D00, + 0x0F126024, +}; + +static const u32 s5k4ecgx_Sharpness_Plus_1[] = { + 0x002A0A28, + 0x0F128040, + 0x002A0ADE, + 0x0F128040, + 0x002A0B94, + 0x0F128040, + 0x002A0C4A, + 0x0F128040, + 0x002A0D00, + 0x0F128040, +}; + +static const u32 s5k4ecgx_Sharpness_Plus_2[] = { + 0x002A0A28, + 0x0F12A060, + 0x002A0ADE, + 0x0F12A060, + 0x002A0B94, + 0x0F12A060, + 0x002A0C4A, + 0x0F12A060, + 0x002A0D00, + 0x0F12A060, +}; + +static const u32 s5k4ecgx_Sharpness_Plus_3[] = { + 0x002A0A28, + 0x0F12C080, + 0x002A0ADE, + 0x0F12C080, + 0x002A0B94, + 0x0F12C080, + 0x002A0C4A, + 0x0F12C080, + 0x002A0D00, + 0x0F12C080, +}; + +static const u32 s5k4ecgx_Saturation_Minus_2[] = { + 0x002A0234, + 0x0F12FF81, +}; + +static const u32 s5k4ecgx_Saturation_Minus_1[] = { + 0x002A0234, + 0x0F12FFC0, +}; + +static const u32 s5k4ecgx_Saturation_Default[] = { + 0x002A0234, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Saturation_Plus_1[] = { + 0x002A0234, + 0x0F120040, +}; + +static const u32 s5k4ecgx_Saturation_Plus_2[] = { + 0x002A0234, + 0x0F12007F, +}; + +static const u32 s5k4ecgx_Jpeg_Quality_High[] = { + 0x002A0478, + 0x0F12005F, + 0x0F12005F, +}; + +static const u32 s5k4ecgx_Jpeg_Quality_Normal[] = { + 0x002A0478, + 0x0F12005A, + 0x0F12005A, +}; + +static const u32 s5k4ecgx_Jpeg_Quality_Low[] = { + 0x002A0478, + 0x0F120054, + 0x0F120054, +}; + +static const u32 s5k4ecgx_Scene_Default[] = { + 0x002A1492, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120403, + 0x0F120304, + 0x0F120102, + 0x0F120201, + 0x0F120303, + 0x0F120303, + 0x0F120102, + 0x0F120201, + 0x0F120202, + 0x0F120202, + 0x0F120102, + + 0x002A0938, + 0x0F120000, + + 0x002A06B8, + 0x0F12452C, + 0x0F12000C, + + 0x002A0F2A, + 0x0F120001, + 0x002A0F30, + 0x0F120001, + 0x002A04E6, + 0x0F12077F, + + 0x002A04D0, + 0x0F120000, + 0x0F120000, + 0x0F120001, + 0x002A06C2, + 0x0F120200, + + 0x002A2C66, + 0x0F120001, + + 0x002A1484, + 0x0F12003C, + 0x002A148A, + 0x0F12000F, + 0x002A058C, + 0x0F123520, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F12C350, + 0x0F120000, + 0x0F120470, + 0x0F120C00, + 0x0F120100, + 0x0F121000, + + 0x002A0544, + 0x0F120111, + 0x0F1200EF, + + 0x002A0608, + 0x0F120001, + 0x0F120001, + + 0x002A0A28, + 0x0F126024, + 0x002A0ADE, + 0x0F126024, + 0x002A0B94, + 0x0F126024, + 0x002A0C4A, + 0x0F126024, + 0x002A0D00, + 0x0F126024, + + 0x002A0234, + 0x0F120000, + + 0x002A0638, + 0x0F120001, + 0x0F120000, + 0x002A063C, + 0x0F120A3C, + 0x0F120000, + 0x002A0640, + 0x0F120D05, + 0x0F120000, + 0x002A0644, + 0x0F123408, + 0x0F120000, + 0x002A0648, + 0x0F123408, + 0x0F120000, + 0x002A064C, + 0x0F126810, + 0x0F120000, + 0x002A0650, + 0x0F128214, + 0x0F120000, + 0x002A0654, + 0x0F12C350, + 0x0F120000, + 0x002A0658, + 0x0F12C350, + 0x0F120000, + 0x002A065C, + 0x0F12C350, + 0x0F120000, + + 0x002A02C2, + 0x0F12029A, /*#REG_0TC_PCFG_usMaxFrTimeMsecMult10*/ + 0x0F12014A, /*#REG_0TC_PCFG_usMinFrTimeMsecMult10*/ + + 0x002A03B4, + 0x0F120535, + 0x0F12029A, + + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, + 0x002A0270, + 0x0F120001, + 0x002A023E, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Portrait[] = { + 0x002A0A28, + 0x0F122010, + 0x002A0ADE, + 0x0F122010, + 0x002A0B94, + 0x0F122010, + 0x002A0C4A, + 0x0F122010, + 0x002A0D00, + 0x0F122010, +}; + +static const u32 s5k4ecgx_Scene_Nightshot[] = { + 0x002A06B8, + 0x0F12FFFF, + 0x0F1200FF, + + 0x002A0608, + 0x0F120001, /*#lt_ExpGain_uSubsamplingmode*/ + 0x0F120001, /*#lt_ExpGain_uNonSubsampling*/ + 0x0F120900, /*#lt_ExpGain_ExpCurveGainMaxStr*/ + + 0x002A0658, + 0x0F12D090, + 0x0F120007, + 0x0F12D090, + 0x0F120007, + + 0x002A03B4, + 0x0F121388, + 0x0F121388, + 0x002A02C2, + 0x0F1209C4, + 0x0F12014A, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, + 0x002A0270, + 0x0F120001, + 0x002A023E, + 0x0F120001, + 0x0F120001, + + 0x002A0A1E, + 0x0F121580, +}; + +static const u32 s5k4ecgx_Scene_Backlight[] = { + 0x002A1492, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120000, + 0x0F12010F, + 0x0F120F01, + 0x0F120000, + 0x0F120000, + 0x0F12010F, + 0x0F120F01, + 0x0F120000, + 0x0F120000, + 0x0F120101, + 0x0F120101, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Scene_Landscape[] = { + 0x002A1492, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x0F120101, + 0x002A0A28, + 0x0F12E082, + 0x002A0ADE, + 0x0F12E082, + 0x002A0B94, + 0x0F12E082, + 0x002A0C4A, + 0x0F12E082, + 0x002A0D00, + 0x0F12E082, + 0x002A0234, + 0x0F120030, +}; + +static const u32 s5k4ecgx_Scene_Sports[] = { + 0x002A0608, + 0x0F120000, + 0x0F120000, + + 0x002A058C, + 0x0F123520, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F123520, + 0x0F120000, + 0x0F120200, + 0x0F120200, + 0x0F120200, + 0x0F120200, + + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, + 0x002A0270, + 0x0F120001, + 0x002A023E, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Party_Indoor[] = { + 0x002A04E6, + 0x0F12065F, + 0x002A04D6, + 0x0F120000, + 0x0F120001, + + 0x002A04D0, + 0x0F120001, + 0x0F120340, + 0x0F120001, + 0x002A06C2, + 0x0F120100, + + 0x002A0938, + 0x0F120001, + + 0x002A0234, + 0x0F120030, +}; + +static const u32 s5k4ecgx_Scene_Beach_Snow[] = { + 0x002A1484, + 0x0F120045, /*#TVAR_ae_BrAve*/ + 0x002A04E6, + 0x0F12065F, + 0x002A04D6, + 0x0F120000, + 0x0F120001, + 0x002A04D0, + 0x0F120001, + 0x0F1200D0, + 0x0F120001, + 0x002A06C2, + 0x0F120100, + + 0x002A0938, + 0x0F120001, + + 0x002A0234, + 0x0F120030, +}; + +static const u32 s5k4ecgx_Scene_Sunset[] = { + 0x002A04E6, + 0x0F120777, + + 0x002A04BA, + 0x0F1205E0, + 0x0F120001, + 0x0F120400, + 0x0F120001, + 0x0F120530, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Duskdawn[] = { + 0x002A04E6, + 0x0F120777, + 0x002A04BA, + 0x0F120505, + 0x0F120001, + 0x0F120400, + 0x0F120001, + 0x0F120875, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Fall_Color[] = { + 0x002A0234, + 0x0F120060, +}; + +static const u32 s5k4ecgx_Scene_Fireworks[] = { + 0x002A0638, + 0x0F120001, + 0x0F120000, + 0x002A063C, + 0x0F121478, + 0x0F120000, + 0x002A0640, + 0x0F121A0A, + 0x0F120000, + 0x002A0644, + 0x0F126810, + 0x0F120000, + 0x002A0648, + 0x0F126810, + 0x0F120000, + 0x002A064C, + 0x0F12D020, + 0x0F120000, + 0x002A0650, + 0x0F120428, + 0x0F120001, + 0x002A0654, + 0x0F121A80, + 0x0F120006, + 0x002A0658, + 0x0F121A80, + 0x0F120006, + 0x002A065C, + 0x0F121A80, + 0x0F120006, + + 0x002A03B4, + 0x0F122710, + 0x0F122710, + + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, + 0x002A0268, + 0x0F120001, + 0x002A0270, + 0x0F120001, + 0x002A023E, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Scene_Text[] = { + 0x002A0A28, + 0x0F12A060, + 0x002A0ADE, + 0x0F12A060, + 0x002A0B94, + 0x0F12A060, + 0x002A0C4A, + 0x0F12A060, + 0x002A0D00, + 0x0F12A060, +}; + +static const u32 s5k4ecgx_Scene_Candle_Light[] = { + 0x002A04E6, + 0x0F120777, + 0x002A04BA, + 0x0F1205E0, + 0x0F120001, + 0x0F120400, + 0x0F120001, + 0x0F120530, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Night_Capture[] = { + 0x002A0608, + 0x0F120001, /*#lt_ExpGain_uSubsamplingmode*/ + 0x0F120001, /*#lt_ExpGain_uNonSubsampling*/ + 0x0F120900, /*#lt_ExpGain_ExpCurveGainMaxStr*/ +}; + +static const u32 s5k4ecgx_AF_Return_Macro_pos[] = { + 0x002A15E8, + 0x0F120018, + 0x0F12002A, + 0x0F120030, + 0x0F120036, + 0x0F12003C, + 0x0F120042, + 0x0F120048, + 0x0F12004E, + 0x0F120054, + 0x0F12005A, + 0x0F120060, + 0x0F120066, + 0x0F12006C, + 0x0F120072, + 0x0F120078, + 0x0F12007E, + 0x0F120084, + 0x0F12008A, + 0x0F120090, + 0x0F120096, + 0x0F12009C, + 0x0F1200A2, + 0x0F1200A8, + 0x0F1200AE, + 0x0F1200B4, + 0x0F1200BA, +}; + +static const u32 s5k4ecgx_AF_Normal_mode_1[] = { + 0x002A028E, + 0x0F120000, +}; + +static const u32 s5k4ecgx_AF_Normal_mode_2[] = { + 0x002A028C, + 0x0F120004, +}; + +static const u32 s5k4ecgx_AF_Normal_mode_3[] = { + 0x002A1648, + 0x0F129002, +}; + +static const u32 s5k4ecgx_AF_Macro_mode_1[] = { + 0x002A028E, + 0x0F1200D0, +}; + +static const u32 s5k4ecgx_AF_Macro_mode_2[] = { + 0x002A028C, + 0x0F120004, +}; + +static const u32 s5k4ecgx_AF_Macro_mode_3[] = { + 0x002A1648, + 0x0F129042, + 0x002A15DA, + 0x0F121800, +}; + +static const u32 s5k4ecgx_AF_Low_Light_Mode_On[] = { + 0x002A15DA, + 0x0F120C00, + + 0x002A15E8, + 0x0F12000C, + 0x0F12002A, + 0x0F120033, + 0x0F12003C, + 0x0F120045, + 0x0F12004E, + 0x0F120057, + 0x0F120063, + 0x0F12006F, + 0x0F12007B, + 0x0F120087, + 0x0F120093, + 0x0F1200A2, + 0x0F1200B1, +}; + +static const u32 s5k4ecgx_AF_Low_Light_Mode_Off[] = { + 0x002A15DA, + 0x0F121800, + + 0x002A15E8, + 0x0F120018, + 0x0F12002A, + 0x0F120030, + 0x0F120036, + 0x0F12003C, + 0x0F120042, + 0x0F120048, + 0x0F12004E, + 0x0F120054, + 0x0F12005A, + 0x0F120060, + 0x0F120066, + 0x0F12006C, + 0x0F120072, + 0x0F120078, + 0x0F12007E, + 0x0F120084, + 0x0F12008A, + 0x0F120090, + 0x0F120096, + 0x0F12009C, + 0x0F1200A2, + 0x0F1200A8, + 0x0F1200AE, + 0x0F1200B4, + 0x0F1200BA, +}; + +static const u32 s5k4ecgx_Single_AF_Start[] = { + 0x002A028C, + 0x0F120005, +}; + +static const u32 s5k4ecgx_Single_AF_Off_1[] = { + 0x002A028E, + 0x0F120000, +}; + +static const u32 s5k4ecgx_Single_AF_Off_2[] = { + 0x002A028C, + 0x0F120004, +}; + +static const u32 s5k4ecgx_Single_AF_Off_3[] = { + +}; + + +static const u32 s5k4ecgx_Face_Detection_On[] = { + 0x002A0294, + 0x0F120100, + 0x0F1200E3, + 0x0F120200, + 0x0F120238, + 0x0F1201C6, + 0x0F120166, + 0x0F120074, + 0x0F120132, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Face_Detection_Off[] = { + 0x002A0294, + 0x0F120100, + 0x0F1200E3, + 0x0F120200, + 0x0F120238, + 0x0F1201C6, + 0x0F120166, + 0x0F120074, + 0x0F120132, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Low_Cap_On[] = { + 0x002A06B8, + 0x0F12FFFF, + 0x0F1200FF, /*#lt_uMaxLei*/ + + 0x002A0A1A, + 0x0F124A18, /*#Gamma linearity*/ + + + 0x002A0608, + 0x0F120001, /*#lt_ExpGain_uSubsamplingmode*/ + 0x0F120001, /*#lt_ExpGain_uNonSubsampling*/ + 0x0F120850, /*#lt_ExpGain_ExpCurveGainMaxStr*/ + + 0x002A0938, + 0x0F120001, + 0x0F120012, /*#SARR_uNormBrInDoor_0_*/ + 0x0F120022, /*#SARR_uNormBrInDoor_1_*/ + 0x0F120384, /*#SARR_uNormBrInDoor_2_*/ + 0x0F1207D0, /*#SARR_uNormBrInDoor_3_*/ + 0x0F121388, /*#SARR_uNormBrInDoor_4_*/ +}; + +static const u32 s5k4ecgx_Low_Cap_Off[] = { + 0x002A06B8, + 0x0F12452C, + 0x0F12000C, /*#lt_uMaxLei*/ + + 0x002A0A1A, + 0x0F128F18, /*#Gamma linearity*/ + + + 0x002A0608, + 0x0F120001, /*#lt_ExpGain_uSubsamplingmode*/ + 0x0F120001, /*#lt_ExpGain_uNonSubsampling*/ + 0x0F120C00, /*#lt_ExpGain_ExpCurveGainMaxStr*/ + + 0x002A0938, + 0x0F120000, + 0x0F120014, /*#SARR_uNormBrInDoor_0_*/ + 0x0F1200D2, /*#SARR_uNormBrInDoor_1_*/ + 0x0F120384, /*#SARR_uNormBrInDoor_2_*/ + 0x0F1207D0, /*#SARR_uNormBrInDoor_3_*/ + 0x0F121388, /*#SARR_uNormBrInDoor_4_*/ +}; + +/* restores crop settings to full resolution */ +static const u32 s5k4ecgx_Reset_Crop[] = { + 0x002A0250, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x002A0494, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + + 0x002A0262, + 0x0F120001, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Capture_Start[] = { + 0x002A0A1E, + 0x0F120050, + + 0x002A0AD4, + 0x0F120074, + + 0x002A0608, + 0x0F120001, /*#lt_ExpGain_uSubsamplingmode*/ + 0x0F120001, /*#lt_ExpGain_uNonSubsampling*/ + 0x0F120850, /*#lt_ExpGain_ExpCurveGainMaxStr*/ + + 0x002A0242, + 0x0F120001, + + 0x002A024E, + 0x0F120001, + + 0x002A0244, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Preview_Return[] = { + 0x002A0A1E, + 0x0F120028, + + 0x002A0AD4, + 0x0F12003C, + + 0x002A0608, + 0x0F120001, /*#lt_ExpGain_uSubsamplingmode*/ + 0x0F120001, /*#lt_ExpGain_uNonSubsampling*/ + 0x0F120C00, /*#lt_ExpGain_ExpCurveGainMaxStr*/ + + 0x002A05D0, + 0x0F120000, + + 0x002A0972, + 0x0F120000, + + 0x002A0242, + 0x0F120000, + + 0x002A024E, + 0x0F120001, + + 0x002A0244, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Flash_init[] = { + 0x002A0484, + 0x0F120002, /* capture flash on */ + + 0x002A183A, + 0x0F120001, /* one frame AE*/ + + 0x002A17F6, + 0x0F120258, /* AWB R point */ + 0x0F120248, /* AWB B point */ + + 0x002A1840, + 0x0F120001, /* Fls AE tune start */ + + 0x0F120100, /* fls_afl_FlsAFIn Rin */ + 0x0F120120, + 0x0F120180, + 0x0F120200, + 0x0F120400, + 0x0F120800, + 0x0F120A00, + 0x0F121000, + + 0x0F120100, /* fls_afl_FlsAFOut Rout */ + 0x0F1200A0, + 0x0F120090, + 0x0F120080, + 0x0F120070, + 0x0F120045, + 0x0F120030, + 0x0F120010, + + 0x002A1884, + 0x0F120100, /* fls_afl_FlsNBOut flash NB default */ + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + 0x0F120100, + + 0x002A1826, + + 0x0F120100, /* fls_afl_FlashWP_Weight flash NB default */ + 0x0F1200C0, + 0x0F120080, + 0x0F12000A, + 0x0F120000, + + 0x0F120030, /* fls_afl_FlashWP_Weight flash NB default */ + 0x0F120040, + 0x0F120048, + 0x0F120050, + 0x0F120060, + + 0x002A4784, + 0x0F1200A0, /* TNP_Regs_FlsWeightRIn weight tune start in*/ + 0x0F1200C0, + 0x0F1200D0, + 0x0F120100, + 0x0F120200, + 0x0F120300, + + 0x0F120088, /* TNP_Regs_FlsWeightROut weight tune start out*/ + 0x0F1200B0, + 0x0F1200C0, + 0x0F120100, + 0x0F120200, + 0x0F120300, + + 0x002A479C, + + 0x0F120120, /*Fls BRIn */ + 0x0F120150, + 0x0F120200, + + 0x0F12003C, /* Fls BROut*/ + 0x0F12003B, + 0x0F120030, + +}; + +static const u32 s5k4ecgx_Pre_Flash_Start[] = { + 0x002A0588, /* set AE speed to fast */ + 0x0F120000, + + 0x002A17FC, /* fls_afl_FlashWP_Weight_0_ Pre_Flash_Start */ + 0x0F120001, +}; + +static const u32 s5k4ecgx_Pre_Flash_End[] = { + 0x002A0588, /* set AE speed to normal */ + 0x0F120002, + + 0x002A1800, /* fls_afl_FlashWP_Weight_0_ Pre_Flash_end */ + 0x0F120001, +}; + +static const u32 s5k4ecgx_Flash_Start[] = { + 0x002A17E8, /* fls_afl_FlashMode : Flash alg start */ + 0x0F120001, + + 0x002A180C, /* fls_afl_FlashWP_Weight_4_ flash br avg */ + 0x0F120027, +}; + +static const u32 s5k4ecgx_Flash_End[] = { + 0x002A17E8, /* fls_afl_FlashMode Flash alg end */ + 0x0F120000, +}; + +/* 2560 x 1920 */ +static const u32 s5k4ecgx_5M_Capture[] = { + 0x002A0398, + 0x0F120A00, /* #REG_0TC_CCFG_usWidth */ + 0x0F120780, /* #REG_0TC_CCFG_usHeight */ + 0x0F120009, + + 0x002A03B2, + 0x0F120002, + 0x002A03B0, + 0x0F120002, + 0x002A0270, + 0x0F120001, +}; +/* 2048 x 1536 */ +static const u32 s5k4ecgx_3M_Capture[] = { + 0x002A0398, + 0x0F120800, /* REG_0TC_CCFG_usWidth */ + 0x0F120600, /* REG_0TC_CCFG_usWidth */ + 0x0F120009, /* REG_0TC_CCFG_Format */ + + 0x002A03B2, + 0x0F120002, /* REG_0TC_CCFG_FrRateQualityType */ + 0x002A03B0, + 0x0F120002, /* REG_0TC_CCFG_usFrTimeType */ + 0x002A024E, + 0x0F120001, /* REG_TC_GP_NewConfigSync */ + 0x002A0270, + 0x0F120001, /* REG_TC_GP_CapConfigChanged */ +}; +/* 1600 x 1200 */ +static const u32 s5k4ecgx_2M_Capture[] = { + 0x002A0398, + 0x0F120640, /* #REG_0TC_CCFG_usWidth */ + 0x0F1204B0, /* #REG_0TC_CCFG_usHeight */ + 0x0F120009, + 0x002A03B2, + 0x0F120002, + 0x002A03B0, + 0x0F120002, + 0x002A024E, + 0x0F120001, + 0x002A0270, + 0x0F120001, +}; +/* 1280 x 960 */ +static const u32 s5k4ecgx_1M_Capture[] = { + 0x002A0398, + 0x0F120500, /* #REG_0TC_CCFG_usWidth */ + 0x0F1203C0, /* #REG_0TC_CCFG_usHeight */ + 0x0F120009, + 0x002A03B2, + 0x0F120002, + 0x002A03B0, + 0x0F120002, + 0x002A024E, + 0x0F120001, + 0x002A0270, + 0x0F120001, +}; +/* 640 x 480 */ +static const u32 s5k4ecgx_VGA_Capture[] = { + 0x002A0398, + 0x0F120280, /* #REG_0TC_CCFG_usWidth */ + 0x0F1201E0, /* #REG_0TC_CCFG_usHeight */ + 0x0F120009, + 0x002A03B2, + 0x0F120002, + 0x002A03B0, + 0x0F120002, + 0x002A024E, + 0x0F120001, + 0x002A0270, + 0x0F120001, +}; +/* 720 x 480 */ +static const u32 s5k4ecgx_720_Preview[] = { + 0x002A0250, + 0x0F120A00, + 0x0F1206A8, + 0x0F120010, + 0x0F120078, + 0x0F120A00, + 0x0F1206A8, + 0x0F120010, + 0x0F120078, + 0x002A0494, + 0x0F120A00, + 0x0F1206A8, + 0x0F120000, + 0x0F120000, + 0x0F120A00, + 0x0F1206A8, + 0x0F120000, + 0x0F120000, + + 0x002A0262, + 0x0F120001, /* #REG_TC_GP_bUseReqInputInPre */ + 0x002A0A1E, + 0x0F120028, + 0x002A0AD4, + 0x0F12003C, + + 0x002A02A6, + 0x0F1202D0, + 0x0F1201E0, + 0x0F120005, + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, /* #REG_TC_GP_NewConfigSync */ + 0x002A0268, + 0x0F120001, /* #REG_TC_GP_CapConfigChanged */ +}; +/* 640 x 480 */ +static const u32 s5k4ecgx_640_Preview[] = { + 0x002A0250, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x0F120A00, + 0x0F120780, + 0x0F120010, + 0x0F12000C, + 0x002A0494, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + 0x0F120A00, + 0x0F120780, + 0x0F120000, + 0x0F120000, + + 0x002A0262, + 0x0F120001, /* #REG_TC_GP_bUseReqInputInPre */ + 0x002A0A1E, + 0x0F120028, + 0x002A0AD4, + 0x0F12003C, + + 0x002A02A6, + 0x0F120280, + 0x0F1201E0, + 0x0F120005, + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014A, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, /* #REG_TC_GP_NewConfigSync */ + 0x002A0268, + 0x0F120001, /* #REG_TC_GP_CapConfigChanged */ +}; +/* 352 x 288 */ +static const u32 s5k4ecgx_352_Preview[] = { + 0x002A0250, + 0x0F120928, + 0x0F120780, + 0x0F12007C, + 0x0F12000C, + 0x0F120928, + 0x0F120780, + 0x0F12007C, + 0x0F12000C, + 0x002A0494, + 0x0F120928, + 0x0F120780, + 0x0F120000, + 0x0F120000, + 0x0F120928, + 0x0F120780, + 0x0F120000, + 0x0F120000, + + 0x002A0262, + 0x0F120001, /* #REG_TC_GP_bUseReqInputInPre */ + 0x002A0A1E, + 0x0F120028, + 0x002A0AD4, + 0x0F12003C, + + 0x002A02A6, + 0x0F120160, + 0x0F120120, + 0x0F120005, + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, /* #REG_TC_GP_NewConfigSync */ + 0x002A0268, + 0x0F120001, /* #REG_TC_GP_CapConfigChanged */ +}; +/* 176 x 144 */ +static const u32 s5k4ecgx_176_Preview[] = { + 0x002A0250, + 0x0F120928, + 0x0F120780, + 0x0F12007C, + 0x0F12000C, + 0x0F120928, + 0x0F120780, + 0x0F12007C, + 0x0F12000C, + 0x002A0494, + 0x0F120928, + 0x0F120780, + 0x0F120000, + 0x0F120000, + 0x0F120928, + 0x0F120780, + 0x0F120000, + 0x0F120000, + + 0x002A0262, + 0x0F120001, /* #REG_TC_GP_bUseReqInputInPre */ + 0x002A0A1E, + 0x0F120028, + 0x002A0AD4, + 0x0F12003C, + + 0x002A02A6, + 0x0F1200B0, + 0x0F120090, + 0x0F120005, + 0x002A02B4, + 0x0F120052, + 0x002A02BE, + 0x0F120000, + 0x0F120001, + 0x0F12029A, + 0x0F12014D, + 0x002A02D0, + 0x0F120000, + 0x0F120000, + 0x002A0266, + 0x0F120000, + 0x002A026A, + 0x0F120001, + 0x002A024E, + 0x0F120001, /* #REG_TC_GP_NewConfigSync */ + 0x002A0268, + 0x0F120001, /* #REG_TC_GP_CapConfigChanged */ +}; + +static const u32 s5k4ecgx_AE_AWB_Lock_On[] = { + 0x002A2C5E, + 0x0F120000, +}; + +static const u32 s5k4ecgx_AE_AWB_Lock_Off[] = { + 0x002A2C5E, + 0x0F120001, +}; + +static const u32 s5k4ecgx_Get_AE_Stable_Status[] = { + 0x002E2C74, +}; + +static const u32 s5k4ecgx_Get_Light_Level[] = { + 0x002C7000, + 0x002E2C18, +}; + +static const u32 s5k4ecgx_get_1st_af_search_status[] = { + 0x002E2EEE, +}; + +static const u32 s5k4ecgx_get_2nd_af_search_status[] = { + 0x002E2207, +}; + +static const u32 s5k4ecgx_get_capture_status[] = { + 0x002E0530, +}; + +static const u32 s5k4ecgx_get_esd_status[] = { + 0xFCFCD000, + 0x002CD000, + 0x002E0060, +}; + +static const u32 s5k4ecgx_get_iso_reg[] = { + 0x002C7000, + 0x002E2BC4, +}; + +static const u32 s5k4ecgx_get_shutterspeed_reg[] = { + 0x002C7000, + 0x002E2BC0, +}; + +#endif /* __S5K4ECGX_REGS_1_0_H__ */ diff --git a/drivers/media/video/s5ka3dfx.c b/drivers/media/video/s5ka3dfx.c new file mode 100755 index 0000000..e4ca5f0 --- /dev/null +++ b/drivers/media/video/s5ka3dfx.c @@ -0,0 +1,1229 @@ +/* + * Driver for S5KA3DFX (UXGA camera) from Samsung Electronics + * + * 1/4" 2.0Mp CMOS Image Sensor SoC with an Embedded Image Processor + * + * Copyright (C) 2009, Jinsung Yang <jsgood.yang@samsung.com> + * + * 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/version.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/s5ka3dfx_platform.h> + +#ifdef CONFIG_VIDEO_SAMSUNG_V4L2 +#include <linux/videodev2_samsung.h> +#endif + +#include "s5ka3dfx.h" + +#define S5KA3DFX_DRIVER_NAME "S5KA3DFX" + +/* #define VGA_CAM_DEBUG */ + +#ifdef VGA_CAM_DEBUG +#define dev_dbg dev_err +#endif + +/* Default resolution & pixelformat. plz ref s5ka3dfx_platform.h */ +#define DEFAULT_RESOLUTION WVGA /* Index of resoultion */ +#define DEFAUT_FPS_INDEX S5KA3DFX_15FPS +#define DEFUALT_MCLK 24000000 /* 24MHz default */ +#define DEFAULT_FMT V4L2_PIX_FMT_UYVY /* YUV422 */ +#define POLL_TIME_MS 10 + +/* + * Specification + * Parallel : ITU-R. 656/601 YUV422, RGB565, RGB888 (Up to VGA), RAW10 + * Serial : MIPI CSI2 (single lane) YUV422, RGB565, RGB888 (Up to VGA), RAW10 + * Resolution : 1280 (H) x 1024 (V) + * Image control : Brightness, Contrast, Saturation, Sharpness, Glamour + * Effect : Mono, Negative, Sepia, Aqua, Sketch + * FPS : 15fps @full resolution, 30fps @VGA, 24fps @720p + * Max. pixel clock frequency : 48MHz(upto) + * Internal PLL (6MHz to 27MHz input frequency) + */ + +static int s5ka3dfx_init(struct v4l2_subdev *sd, u32 val); + +/* Camera functional setting values configured by user concept */ +struct s5ka3dfx_userset { + 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 s5ka3dfx_state { + struct s5ka3dfx_platform_data *pdata; + struct v4l2_subdev sd; + struct v4l2_pix_format pix; + struct v4l2_fract timeperframe; + struct s5ka3dfx_userset userset; + struct v4l2_streamparm strm; + int framesize_index; + int freq; /* MCLK in KHz */ + int is_mipi; + int isize; + int ver; + int fps; + int vt_mode; /*For VT camera */ + int check_dataline; + int check_previewdata; +}; + +enum { + S5KA3DFX_PREVIEW_QCIF, + S5KA3DFX_PREVIEW_QVGA, + S5KA3DFX_PREVIEW_VGA, +}; + +struct s5ka3dfx_enum_framesize { + unsigned int index; + unsigned int width; + unsigned int height; +}; + +struct s5ka3dfx_enum_framesize s5ka3dfx_framesize_list[] = { + { S5KA3DFX_PREVIEW_QCIF, 176, 144 }, + { S5KA3DFX_PREVIEW_QVGA, 320, 240 }, + { S5KA3DFX_PREVIEW_VGA, 640, 480 } +}; + +static inline struct s5ka3dfx_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct s5ka3dfx_state, sd); +} + +struct s5ka3dfx_regset_table { + struct s5ka3dfx_reg *regset; + int array_size; +}; + +#define S5KA3DFX_REGSET_TABLE_ELEMENT(x, y) \ + [(x)] = { \ + .regset = (y), \ + .array_size = ARRAY_SIZE((y)), \ + } + +static struct s5ka3dfx_regset_table brightness_vt[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_4, s5ka3dfx_ev_vt_m4), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_3, s5ka3dfx_ev_vt_m3), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_2, s5ka3dfx_ev_vt_m2), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_1, s5ka3dfx_ev_vt_m1), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_DEFAULT, s5ka3dfx_ev_vt_default), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_1, s5ka3dfx_ev_vt_p1), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_2, s5ka3dfx_ev_vt_p2), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_3, s5ka3dfx_ev_vt_p3), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_4, s5ka3dfx_ev_vt_p4), +}; + +static struct s5ka3dfx_regset_table brightness[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_4, s5ka3dfx_ev_m4), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_3, s5ka3dfx_ev_m3), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_2, s5ka3dfx_ev_m2), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_MINUS_1, s5ka3dfx_ev_m1), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_DEFAULT, s5ka3dfx_ev_default), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_1, s5ka3dfx_ev_p1), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_2, s5ka3dfx_ev_p2), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_3, s5ka3dfx_ev_p3), + S5KA3DFX_REGSET_TABLE_ELEMENT(EV_PLUS_4, s5ka3dfx_ev_p4), +}; + +static struct s5ka3dfx_regset_table white_balance[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(WHITE_BALANCE_AUTO, + s5ka3dfx_wb_auto), + S5KA3DFX_REGSET_TABLE_ELEMENT(WHITE_BALANCE_SUNNY, + s5ka3dfx_wb_sunny), + S5KA3DFX_REGSET_TABLE_ELEMENT(WHITE_BALANCE_CLOUDY, + s5ka3dfx_wb_cloudy), + S5KA3DFX_REGSET_TABLE_ELEMENT(WHITE_BALANCE_TUNGSTEN, + s5ka3dfx_wb_tungsten), + S5KA3DFX_REGSET_TABLE_ELEMENT(WHITE_BALANCE_FLUORESCENT, + s5ka3dfx_wb_fluorescent), +}; + +static struct s5ka3dfx_regset_table effects[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(IMAGE_EFFECT_NONE, + s5ka3dfx_effect_none), + S5KA3DFX_REGSET_TABLE_ELEMENT(IMAGE_EFFECT_BNW, + s5ka3dfx_effect_gray), + S5KA3DFX_REGSET_TABLE_ELEMENT(IMAGE_EFFECT_SEPIA, + s5ka3dfx_effect_sepia), + S5KA3DFX_REGSET_TABLE_ELEMENT(IMAGE_EFFECT_NEGATIVE, + s5ka3dfx_effect_negative), +}; + +static struct s5ka3dfx_regset_table fps_vt_table[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(0, s5ka3dfx_vt_fps_7), + S5KA3DFX_REGSET_TABLE_ELEMENT(1, s5ka3dfx_vt_fps_10), + S5KA3DFX_REGSET_TABLE_ELEMENT(2, s5ka3dfx_vt_fps_15), +}; + +static struct s5ka3dfx_regset_table fps_table[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(0, s5ka3dfx_fps_7), + S5KA3DFX_REGSET_TABLE_ELEMENT(1, s5ka3dfx_fps_10), + S5KA3DFX_REGSET_TABLE_ELEMENT(2, s5ka3dfx_fps_15), + S5KA3DFX_REGSET_TABLE_ELEMENT(3, s5ka3dfx_fps_auto), +}; + +static struct s5ka3dfx_regset_table blur_vt[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_0, s5ka3dfx_blur_vt_none), + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_1, s5ka3dfx_blur_vt_p1), + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_2, s5ka3dfx_blur_vt_p2), + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_3, s5ka3dfx_blur_vt_p3), +}; + +static struct s5ka3dfx_regset_table blur[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_0, s5ka3dfx_blur_none), + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_1, s5ka3dfx_blur_p1), + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_2, s5ka3dfx_blur_p2), + S5KA3DFX_REGSET_TABLE_ELEMENT(BLUR_LEVEL_3, s5ka3dfx_blur_p3), +}; + +static struct s5ka3dfx_regset_table dataline[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(0, s5ka3dfx_dataline), +}; + +static struct s5ka3dfx_regset_table dataline_stop[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(0, s5ka3dfx_dataline_stop), +}; + +static struct s5ka3dfx_regset_table init_reg[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(0, s5ka3dfx_init_reg), +}; + +static struct s5ka3dfx_regset_table init_vt_reg[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(0, s5ka3dfx_init_vt_reg), +}; + +static struct s5ka3dfx_regset_table frame_size[] = { + S5KA3DFX_REGSET_TABLE_ELEMENT(0, s5ka3dfx_QCIF), + S5KA3DFX_REGSET_TABLE_ELEMENT(1, s5ka3dfx_QVGA), + S5KA3DFX_REGSET_TABLE_ELEMENT(2, s5ka3dfx_Return_VGA), +}; +static int s5ka3dfx_reset(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_platform_data *pdata; + + pdata = client->dev.platform_data; + + if (pdata->cam_power) { + pdata->cam_power(0); + msleep(5); + pdata->cam_power(1); + msleep(5); + s5ka3dfx_init(sd, 0); + } + + return 0; +} + +static int s5ka3dfx_i2c_write_multi(struct i2c_client *client, + unsigned short addr, unsigned int w_data) +{ + int retry_count = 4; + unsigned char buf[2]; + struct i2c_msg msg = { client->addr, 0, 2, buf }; + int ret; + + buf[0] = addr; + buf[1] = w_data; + +#ifdef VGA_CAM_DEBUG + int i; + for (i = 0; i < 2; i++) { + dev_err(&client->dev, "buf[%d] = %x ", i, buf[i]); + if (i == 1) + dev_err(&client->dev, "\n"); + } +#endif + + do { + ret = i2c_transfer(client->adapter, &msg, 1); + if (likely(ret == 1)) + break; + msleep(POLL_TIME_MS); + } while (retry_count--); + + if (ret != 1) + dev_err(&client->dev, "I2C is not working.\n"); + + return (ret == 1) ? 0 : -EIO; +} + +static int s5ka3dfx_write_regs(struct v4l2_subdev *sd, + struct s5ka3dfx_reg regs[], int size) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int i, err; + + for (i = 0; i < size; i++) { + err = s5ka3dfx_i2c_write_multi(client, + regs[i].addr, regs[i].val); + if (err < 0) { + v4l_info(client, "%s: register set failed\n", __func__); + break; + } + } + if (err < 0) + return -EIO; + + return 0; +} + +static int s5ka3dfx_write_regset_table(struct v4l2_subdev *sd, + const struct s5ka3dfx_regset_table *regset_table) +{ + int err; + + if (regset_table->regset) + err = s5ka3dfx_write_regs(sd, regset_table->regset, + regset_table->array_size); + else + err = -EINVAL; + + return err; +} + +static int s5ka3dfx_set_from_table(struct v4l2_subdev *sd, + const char *setting_name, + const struct s5ka3dfx_regset_table *table, + int table_size, int index) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + dev_dbg(&client->dev, "%s: set %s index %d\n", + __func__, setting_name, index); + + if ((index < 0) || (index >= table_size)) { + dev_err(&client->dev, + "%s: index(%d) out of range[0:%d] for table for %s\n", + __func__, index, table_size, setting_name); + return -EINVAL; + } + table += index; + if (table == NULL) + return -EINVAL; + return s5ka3dfx_write_regset_table(sd, table); +} + +static int s5ka3dfx_set_parameter(struct v4l2_subdev *sd, + int *current_value_ptr, + int new_value, + const char *setting_name, + const struct s5ka3dfx_regset_table *table, + int table_size) +{ + int err; + + if (*current_value_ptr == new_value) + return 0; + + err = s5ka3dfx_set_from_table(sd, setting_name, table, + table_size, new_value); + + if (!err) + *current_value_ptr = new_value; + + return err; +} +static int s5ka3dfx_set_preview_start(struct v4l2_subdev *sd) +{ + int err; + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!state->pix.width || !state->pix.height) + return -EINVAL; + + err = s5ka3dfx_set_from_table(sd, "frame_size", frame_size, + ARRAY_SIZE(frame_size), state->framesize_index); + if (err < 0) { + dev_err(&client->dev, + "%s: failed: Could not set preview size\n", + __func__); + return -EIO; + } + + return 0; +} +static struct v4l2_queryctrl s5ka3dfx_controls[] = { + /* Add here if needed */ +}; + +const char * const *s5ka3dfx_ctrl_get_menu(u32 id) +{ + pr_debug("%s is called... id : %d\n", __func__, id); + + switch (id) { + default: + return v4l2_ctrl_get_menu(id); + } +} + +static inline struct v4l2_queryctrl const *s5ka3dfx_find_qctrl(int id) +{ + int i; + + pr_debug("%s is called... id : %d\n", __func__, id); + + for (i = 0; i < ARRAY_SIZE(s5ka3dfx_controls); i++) + if (s5ka3dfx_controls[i].id == id) + return &s5ka3dfx_controls[i]; + + return NULL; +} + +static int s5ka3dfx_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + int i; + + pr_debug("%s is called...\n", __func__); + + for (i = 0; i < ARRAY_SIZE(s5ka3dfx_controls); i++) { + if (s5ka3dfx_controls[i].id == qc->id) { + memcpy(qc, &s5ka3dfx_controls[i], + sizeof(struct v4l2_queryctrl)); + return 0; + } + } + + return -EINVAL; +} + +static int s5ka3dfx_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm) +{ + struct v4l2_queryctrl qctrl; + + pr_debug("%s is called...\n", __func__); + + qctrl.id = qm->id; + s5ka3dfx_queryctrl(sd, &qctrl); + + return v4l2_ctrl_query_menu(qm, &qctrl, s5ka3dfx_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 s5ka3dfx_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags) +{ + int err = -EINVAL; + + pr_debug("%s is called...\n", __func__); + + return err; +} + +static int s5ka3dfx_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + int err = 0; + + pr_debug("%s is called...\n", __func__); + + return err; +} + +static void s5ka3dfx_set_framesize(struct v4l2_subdev *sd, + const struct s5ka3dfx_enum_framesize *frmsize, + int frmsize_count) +{ + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + const struct s5ka3dfx_enum_framesize *last_frmsize = + &frmsize[frmsize_count - 1]; + + dev_dbg(&client->dev, "%s: Requested Res: %dx%d\n", __func__, + state->pix.width, state->pix.height); + + do { + if (frmsize->width == state->pix.width && + frmsize->height == state->pix.height) { + break; + } + + frmsize++; + } while (frmsize <= last_frmsize); + + if (frmsize > last_frmsize) + frmsize = last_frmsize; + + state->pix.width = frmsize->width; + state->pix.height = frmsize->height; + state->framesize_index = frmsize->index; + + dev_dbg(&client->dev, "%s: Preview Res Set: %dx%d, index %d\n", + __func__, state->pix.width, state->pix.height, + state->framesize_index); +} +static int s5ka3dfx_s_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int err = 0; + + if (fmt->code == V4L2_MBUS_FMT_FIXED && + fmt->colorspace != V4L2_COLORSPACE_JPEG) { + dev_dbg(&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? */ + + s5ka3dfx_set_framesize(sd, s5ka3dfx_framesize_list, + ARRAY_SIZE(s5ka3dfx_framesize_list)); + + return err; +} + +static int s5ka3dfx_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_frmsizeenum *fsize) +{ + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + int num_entries = sizeof(s5ka3dfx_framesize_list) / + sizeof(struct s5ka3dfx_enum_framesize); + struct s5ka3dfx_enum_framesize *elem; + int index = 0; + int i = 0; + + pr_debug("%s is called...\n", __func__); + + /* 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 (WVGA) + */ + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + index = state->framesize_index; + + for (i = 0; i < num_entries; i++) { + elem = &s5ka3dfx_framesize_list[i]; + if (elem->index == index) { + fsize->discrete.width = + s5ka3dfx_framesize_list[index].width; + fsize->discrete.height = + s5ka3dfx_framesize_list[index].height; + return 0; + } + } + + return -EINVAL; +} + +static int s5ka3dfx_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_frmivalenum *fival) +{ + int err = 0; + + pr_debug("%s is called...\n", __func__); + + return err; +} + +static int s5ka3dfx_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + int err = 0; + + pr_debug("%s is called...\n", __func__); + + return err; +} + +static int s5ka3dfx_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + int err = 0; + + pr_debug("%s is called...\n", __func__); + + return err; +} + +static int s5ka3dfx_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int err = 0; + + dev_dbg(&client->dev, "%s\n", __func__); + + return err; +} + +static int s5ka3dfx_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + int err = 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct sec_cam_parm *new_parms = + (struct sec_cam_parm *)¶m->parm.raw_data; + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + + dev_dbg(&client->dev, "%s: start\n", __func__); + + /* we return an error if one happened but don't stop trying to + * set all parameters passed + */ + + err = s5ka3dfx_set_parameter(sd, &parms->brightness, + new_parms->brightness, "brightness", + brightness, ARRAY_SIZE(brightness)); + err |= s5ka3dfx_set_parameter(sd, &parms->effects, new_parms->effects, + "effects", effects, + ARRAY_SIZE(effects)); + err |= s5ka3dfx_set_parameter(sd, &parms->white_balance, + new_parms->white_balance, + "white_balance", white_balance, + ARRAY_SIZE(white_balance)); + + dev_dbg(&client->dev, "%s: returning %d\n", __func__, err); + + return err; +} + +/* set sensor register values for adjusting brightness */ +static int s5ka3dfx_set_brightness(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct s5ka3dfx_regset_table *ev; + int err = -EINVAL; + int ev_index; + int array_size; + + dev_dbg(&client->dev, "%s: value : %d state->vt_mode %d\n", + __func__, ctrl->value, state->vt_mode); + + pr_debug("state->vt_mode : %d\n", state->vt_mode); + + if ((ctrl->value < 0) || (ctrl->value >= EV_MAX)) + ev_index = EV_DEFAULT; + else + ev_index = ctrl->value; + + if (state->vt_mode == 1) { + ev = brightness_vt; + array_size = ARRAY_SIZE(brightness_vt); + } else { + ev = brightness; + array_size = ARRAY_SIZE(brightness); + } + + if (ev_index >= array_size) + ev_index = EV_DEFAULT; + + ev += ev_index; + + err = s5ka3dfx_write_regset_table(sd, ev); + + if (err) + dev_dbg(&client->dev, "%s: register set failed\n", __func__); + + return err; +} + +/* + * set sensor register values for + * adjusting whitebalance, both auto and manual + */ +static int s5ka3dfx_set_wb(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_regset_table *wb = white_balance; + int err = -EINVAL; + + dev_dbg(&client->dev, "%s: value : %d\n", __func__, ctrl->value); + + if ((ctrl->value < WHITE_BALANCE_BASE) || + (ctrl->value > WHITE_BALANCE_MAX) || + (ctrl->value >= ARRAY_SIZE(white_balance))) { + dev_dbg(&client->dev, "%s: Value(%d) out of range([%d:%d])\n", + __func__, ctrl->value, + WHITE_BALANCE_BASE, WHITE_BALANCE_MAX); + dev_dbg(&client->dev, "%s: Value out of range\n", __func__); + goto out; + } + + wb += ctrl->value; + + err = s5ka3dfx_write_regset_table(sd, wb); + + if (err) + dev_dbg(&client->dev, "%s: register set failed\n", __func__); +out: + return err; +} + +/* set sensor register values for adjusting color effect */ +static int s5ka3dfx_set_effect(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_regset_table *effect = effects; + int err = -EINVAL; + + dev_dbg(&client->dev, "%s: value : %d\n", __func__, ctrl->value); + + if ((ctrl->value < IMAGE_EFFECT_BASE) || + (ctrl->value > IMAGE_EFFECT_MAX) || + (ctrl->value >= ARRAY_SIZE(effects))) { + dev_dbg(&client->dev, "%s: Value(%d) out of range([%d:%d])\n", + __func__, ctrl->value, + IMAGE_EFFECT_BASE, IMAGE_EFFECT_MAX); + goto out; + } + + effect += ctrl->value; + + err = s5ka3dfx_write_regset_table(sd, effect); + + if (err) + dev_dbg(&client->dev, "%s: register set failed\n", __func__); +out: + return err; +} + +/* set sensor register values for frame rate(fps) setting */ +static int s5ka3dfx_set_frame_rate(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct s5ka3dfx_regset_table *fps; + + int err = -EINVAL; + int fps_index; + + dev_dbg(&client->dev, "%s: value : %d\n", __func__, ctrl->value); + + pr_debug("state->vt_mode : %d\n", state->vt_mode); + + switch (ctrl->value) { + case 0: + fps_index = 3; + break; + + case 7: + fps_index = 0; + break; + + case 10: + fps_index = 1; + break; + + case 15: + fps_index = 2; + break; + + default: + dev_dbg(&client->dev, "%s: Value(%d) is not supported\n", + __func__, ctrl->value); + goto out; + } + + if (state->vt_mode == 1) + fps = fps_vt_table; + else + fps = fps_table; + + fps += fps_index; + state->fps = fps_index; + + err = s5ka3dfx_write_regset_table(sd, fps); +out: + return err; +} + +/* set sensor register values for adjusting blur effect */ +static int s5ka3dfx_set_blur(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct s5ka3dfx_regset_table *bl; + int err = -EINVAL; + int array_size; + + dev_dbg(&client->dev, "%s: value : %d\n", __func__, ctrl->value); + + pr_debug("state->vt_mode : %d\n", state->vt_mode); + + if ((ctrl->value < BLUR_LEVEL_0) || (ctrl->value > BLUR_LEVEL_MAX)) { + dev_dbg(&client->dev, "%s: Value(%d) out of range([%d:%d])\n", + __func__, ctrl->value, + BLUR_LEVEL_0, BLUR_LEVEL_MAX); + goto out; + } + + if (state->vt_mode == 1) { + bl = blur_vt; + array_size = ARRAY_SIZE(blur_vt); + } else { + bl = blur; + array_size = ARRAY_SIZE(blur); + } + + if (ctrl->value >= array_size) { + dev_dbg(&client->dev, "%s: Value(%d) out of range([%d:%d))\n", + __func__, ctrl->value, + BLUR_LEVEL_0, array_size); + goto out; + } + + bl += ctrl->value; + + err = s5ka3dfx_write_regset_table(sd, bl); +out: + return err; +} + +static int s5ka3dfx_check_dataline_stop(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + int err = -EINVAL; + + dev_dbg(&client->dev, "%s\n", __func__); + + err = s5ka3dfx_write_regset_table(sd, dataline_stop); + if (err < 0) { + v4l_info(client, "%s: register set failed\n", __func__); + return -EIO; + } + + state->check_dataline = 0; + err = s5ka3dfx_reset(sd); + if (err < 0) { + v4l_info(client, "%s: register set failed\n", __func__); + return -EIO; + } + return err; +} + +/* returns the real iso currently used by sensor due to lighting + * conditions, not the requested iso we sent using s_ctrl. + */ +static int s5ka3dfx_get_iso(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + int err; + struct i2c_client *client = v4l2_get_subdevdata(sd); + s32 read_value; + int gain; + + err = s5ka3dfx_i2c_write_multi(client, 0xEF, 0x02); + if (err < 0) + return err; + + read_value = i2c_smbus_read_byte_data(client, 0x1D); + if (read_value < 0) + return read_value; + + read_value &= 0x7F; + gain = (128 * 100) / (128 - read_value); + + if (gain > 280) + ctrl->value = ISO_400; + else if (gain > 230) + ctrl->value = ISO_200; + else if (gain > 190) + ctrl->value = ISO_100; + else if (gain > 100) + ctrl->value = ISO_50; + else + ctrl->value = gain; + + dev_dbg(&client->dev, "%s: get iso == %d (0x%x)\n", + __func__, ctrl->value, read_value); + + return err; +} + +static int s5ka3dfx_get_shutterspeed(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = to_state(sd); + s32 read_value; + int cintr; + int err; + + err = s5ka3dfx_i2c_write_multi(client, 0xEF, 0x02); + if (err < 0) + return err; + + read_value = i2c_smbus_read_byte_data(client, 0x0E); + if (read_value < 0) + return read_value; + cintr = (read_value & 0x1F) << 8; + + read_value = i2c_smbus_read_byte_data(client, 0x0F); + if (read_value < 0) + return read_value; + cintr |= read_value & 0xFF; + + /* A3D Shutter Speed (Micro Sec.) = + (2 * (cintr - 1) * 814) / MCLK * 1000 */ + ctrl->value = ((cintr - 1) * 1628) / (state->freq / 1000) * 1000; + + dev_dbg(&client->dev, + "%s: get shutterspeed == %d\n", __func__, ctrl->value); + + return err; +} + +static int s5ka3dfx_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct s5ka3dfx_userset userset = state->userset; + int err = 0; + + dev_dbg(&client->dev, "%s: id : 0x%08x\n", __func__, ctrl->id); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ctrl->value = userset.exposure_bias; + break; + + case V4L2_CID_AUTO_WHITE_BALANCE: + ctrl->value = userset.auto_wb; + break; + + case V4L2_CID_WHITE_BALANCE_PRESET: + ctrl->value = userset.manual_wb; + break; + + case V4L2_CID_COLORFX: + ctrl->value = userset.effect; + break; + + case V4L2_CID_CONTRAST: + ctrl->value = userset.contrast; + break; + + case V4L2_CID_SATURATION: + ctrl->value = userset.saturation; + break; + + case V4L2_CID_SHARPNESS: + ctrl->value = userset.saturation; + break; + + case V4L2_CID_CAMERA_GET_ISO: + err = s5ka3dfx_get_iso(sd, ctrl); + break; + + case V4L2_CID_CAMERA_GET_SHT_TIME: + err = s5ka3dfx_get_shutterspeed(sd, ctrl); + break; + + case V4L2_CID_ESD_INT: + ctrl->value = 0; + break; + + default: + dev_dbg(&client->dev, "%s: no such ctrl\n", __func__); + err = -EINVAL; + break; + } + + return err; +} + +static int s5ka3dfx_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + + int err = -EINVAL; + + pr_debug("%s : ctrl->id 0x%08x, ctrl->value %d\n", __func__, + ctrl->id, ctrl->value); + + switch (ctrl->id) { + + case V4L2_CID_CAMERA_BRIGHTNESS: + dev_dbg(&client->dev, "%s: " + "V4L2_CID_CAMERA_BRIGHTNESS\n", __func__); + err = s5ka3dfx_set_brightness(sd, ctrl); + break; + + case V4L2_CID_CAMERA_WHITE_BALANCE: + dev_dbg(&client->dev, "%s: " + "V4L2_CID_AUTO_WHITE_BALANCE\n", __func__); + err = s5ka3dfx_set_wb(sd, ctrl); + break; + + case V4L2_CID_CAMERA_EFFECT: + dev_dbg(&client->dev, "%s: " + "V4L2_CID_CAMERA_EFFECT\n", __func__); + err = s5ka3dfx_set_effect(sd, ctrl); + break; + + case V4L2_CID_CAMERA_FRAME_RATE: + dev_dbg(&client->dev, "%s: " + "V4L2_CID_CAMERA_FRAME_RATE\n", __func__); + err = s5ka3dfx_set_frame_rate(sd, ctrl); + break; + + case V4L2_CID_CAMERA_VGA_BLUR: + dev_dbg(&client->dev, "%s: " + "V4L2_CID_CAMERA_VGA_BLUR\n", __func__); + err = s5ka3dfx_set_blur(sd, ctrl); + break; + + case V4L2_CID_CAMERA_VT_MODE: + state->vt_mode = ctrl->value; + dev_dbg(&client->dev, "%s: V4L2_CID_CAMERA_VT_MODE : " + "state->vt_mode %d\n", + __func__, state->vt_mode); + err = 0; + break; + + case V4L2_CID_CAMERA_CHECK_DATALINE: + state->check_dataline = ctrl->value; + err = 0; + break; + + case V4L2_CID_CAMERA_CHECK_DATALINE_STOP: + err = s5ka3dfx_check_dataline_stop(sd); + break; + + case V4L2_CID_CAM_PREVIEW_ONOFF: + if (state->check_previewdata == 0) + err = s5ka3dfx_set_preview_start(sd); + else + err = -EIO; + break; + + case V4L2_CID_CAMERA_RESET: + dev_dbg(&client->dev, "%s: V4L2_CID_CAMERA_RESET\n", __func__); + err = s5ka3dfx_reset(sd); + break; + + default: + dev_dbg(&client->dev, "%s: no support control " + "in camera sensor, S5KA3DFX\n", __func__); + err = 0; + break; + } + + if (err < 0) + goto out; + else + return 0; + + out: + dev_dbg(&client->dev, "%s: vidioc_s_ctrl failed\n", __func__); + return err; +} + +static void s5ka3dfx_init_parameters(struct v4l2_subdev *sd) +{ + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + struct sec_cam_parm *parms = + (struct sec_cam_parm *)&state->strm.parm.raw_data; + + parms->effects = IMAGE_EFFECT_NONE; + parms->brightness = EV_DEFAULT; + parms->white_balance = WHITE_BALANCE_AUTO; + +} + +static int s5ka3dfx_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + int err = -EINVAL; + + pr_debug("camera initialization start, state->vt_mode : %d\n", + state->vt_mode); + pr_debug("state->check_dataline : %d\n", state->check_dataline); + + s5ka3dfx_init_parameters(sd); + if (state->vt_mode == 0) { + if (state->check_dataline) + err = s5ka3dfx_write_regset_table(sd, dataline); + else + err = s5ka3dfx_write_regset_table(sd, init_reg); + } else + err = s5ka3dfx_write_regset_table(sd, init_vt_reg); + + if (err < 0) { + /* This is preview fail */ + state->check_previewdata = 100; + v4l_err(client, + "%s: camera initialization failed. err(%d)\n", + __func__, state->check_previewdata); + return -EIO; + } + + /* This is preview success */ + state->check_previewdata = 0; + return 0; +} + +static const struct v4l2_subdev_core_ops s5ka3dfx_core_ops = { + .init = s5ka3dfx_init, /* initializing API */ + .queryctrl = s5ka3dfx_queryctrl, + .querymenu = s5ka3dfx_querymenu, + .g_ctrl = s5ka3dfx_g_ctrl, + .s_ctrl = s5ka3dfx_s_ctrl, +}; + +static const struct v4l2_subdev_video_ops s5ka3dfx_video_ops = { + .s_crystal_freq = s5ka3dfx_s_crystal_freq, + .g_mbus_fmt = s5ka3dfx_g_mbus_fmt, + .s_mbus_fmt = s5ka3dfx_s_mbus_fmt, + .enum_framesizes = s5ka3dfx_enum_framesizes, + .enum_frameintervals = s5ka3dfx_enum_frameintervals, + .enum_mbus_fmt = s5ka3dfx_enum_mbus_fmt, + .try_mbus_fmt = s5ka3dfx_try_mbus_fmt, + .g_parm = s5ka3dfx_g_parm, + .s_parm = s5ka3dfx_s_parm, +}; + +static const struct v4l2_subdev_ops s5ka3dfx_ops = { + .core = &s5ka3dfx_core_ops, + .video = &s5ka3dfx_video_ops, +}; + +/* + * s5ka3dfx_probe + * Fetching platform data is being done with s_config subdev call. + * In probe routine, we just register subdev device + */ +static int s5ka3dfx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct s5ka3dfx_state *state; + struct v4l2_subdev *sd; + struct s5ka3dfx_platform_data *pdata = client->dev.platform_data; + + state = kzalloc(sizeof(struct s5ka3dfx_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + sd = &state->sd; + strcpy(sd->name, S5KA3DFX_DRIVER_NAME); + + /* + * Assign default format and resolution + * Use configured default information in platform data + * or without them, use default information in driver + */ + if (!(pdata->default_width && pdata->default_height)) { + /* TODO: assign driver default resolution */ + } else { + state->pix.width = pdata->default_width; + state->pix.height = pdata->default_height; + } + + if (!pdata->pixelformat) + state->pix.pixelformat = DEFAULT_FMT; + else + state->pix.pixelformat = pdata->pixelformat; + + if (pdata->freq == 0) + state->freq = DEFUALT_MCLK; + else + state->freq = pdata->freq; + + if (!pdata->is_mipi) { + state->is_mipi = 0; + dev_dbg(&client->dev, "parallel mode\n"); + } else + state->is_mipi = pdata->is_mipi; + + /* Registering subdev */ + v4l2_i2c_subdev_init(sd, client, &s5ka3dfx_ops); + + dev_dbg(&client->dev, "s5ka3dfx has been probed\n"); + return 0; +} + +static int s5ka3dfx_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct s5ka3dfx_state *state = + container_of(sd, struct s5ka3dfx_state, sd); + + v4l2_device_unregister_subdev(sd); + kfree(state); + return 0; +} + +static const struct i2c_device_id s5ka3dfx_id[] = { + { S5KA3DFX_DRIVER_NAME, 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, s5ka3dfx_id); + +static struct i2c_driver v4l2_i2c_driver = { + .driver.name = S5KA3DFX_DRIVER_NAME, + .probe = s5ka3dfx_probe, + .remove = s5ka3dfx_remove, + .id_table = s5ka3dfx_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("Samsung Electronics S5KA3DFX UXGA camera driver"); +MODULE_AUTHOR("Jinsung Yang <jsgood.yang@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/s5ka3dfx.h b/drivers/media/video/s5ka3dfx.h new file mode 100755 index 0000000..7bf2a8e --- /dev/null +++ b/drivers/media/video/s5ka3dfx.h @@ -0,0 +1,1691 @@ +/* + * Driver for S5KA3DFX (VGA camera) from Samsung Electronics + * + * 1/4" 2.0Mp CMOS Image Sensor SoC with an Embedded Image Processor + * + * Copyright (C) 2009, Jinsung Yang <jsgood.yang@samsung.com> + * + * 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. + */ +#ifndef __S5KA3DFX_H__ +#define __S5KA3DFX_H__ + +struct s5ka3dfx_reg { + unsigned char addr; + unsigned char val; +}; + +struct s5ka3dfx_regset_type { + unsigned char *regset; + int len; +}; + +/* + * Macro + */ +#define REGSET_LENGTH(x) (sizeof(x) / sizeof(s5ka3dfx_reg)) + +/* + * User defined commands + */ +/* S/W defined features for tune */ +#define REG_DELAY 0xFF00 /* in ms */ +#define REG_CMD 0xFFFF /* Followed by command */ + +/* Following order should not be changed */ +enum image_size_s5ka3dfx { + SVGA, /* 800*600 */ +}; + +/* + * Following values describe controls of camera + * in user aspect and must be match with index of s5ka3dfx_regset[] + * These values indicates each controls and should be used + * to control each control + */ +enum s5ka3dfx_control { + S5KA3DFX_INIT, + S5KA3DFX_EV, + S5KA3DFX_AWB, + S5KA3DFX_MWB, + S5KA3DFX_EFFECT, + S5KA3DFX_CONTRAST, + S5KA3DFX_SATURATION, + S5KA3DFX_SHARPNESS, +}; + +#define S5KA3DFX_REGSET(x) { \ + .regset = (x), \ + .len = sizeof((x))/sizeof(s5ka3dfx_reg),} + +/* + * VGA Self shot init setting + */ +struct s5ka3dfx_reg s5ka3dfx_init_reg[] = { + { 0xef, 0x02 }, + { 0x13, 0xa0 }, + { 0x23, 0x53 }, + { 0x26, 0x24 }, + { 0x2c, 0x05 }, + { 0x05, 0x00 }, + { 0x03, 0x58 }, + { 0x24, 0x0a }, + { 0x0b, 0x84 }, + { 0x1e, 0xb7 }, + { 0x56, 0x05 }, + { 0x28, 0x96 }, + { 0x67, 0x3c }, + + { 0xef, 0x03 }, + { 0x50, 0xd2 }, + { 0x0f, 0x31 }, + { 0xef, 0x03 }, + { 0x70, 0x00 }, /*un-mirrored*/ + { 0x5F, 0x03 }, + { 0x60, 0x02 }, + { 0x61, 0x0F }, + { 0x62, 0x0C }, + { 0x63, 0x01 }, + { 0x64, 0xE7 }, + { 0x65, 0x01 }, + { 0x66, 0xE7 }, + + { 0x6d, 0x56 }, + { 0x6e, 0xC0 }, + { 0x6f, 0xC0 }, + + { 0x4c, 0x00 }, + { 0x4d, 0x9e }, + + { 0xef, 0x03 }, + { 0x00, 0x07 }, + { 0x01, 0x80 }, + { 0x02, 0x7f }, + { 0x2b, 0x41 }, + { 0x31, 0x00 }, + { 0x32, 0x09 }, + + { 0x33, 0x80 }, + { 0x34, 0x79 }, + + { 0x36, 0x3A }, /*39, 3a, N.L. ST */ + { 0x37, 0x38 }, + + { 0x6a, 0x00 }, + { 0x7b, 0x05 }, + { 0x38, 0x05 }, + { 0x39, 0x03 }, + + { 0x2d, 0x08 }, + { 0x2e, 0x20 }, + { 0x2f, 0x30 }, + { 0x30, 0xff }, + { 0x7c, 0x06 }, + { 0x7d, 0x20 }, + { 0x7e, 0x0c }, + { 0x7f, 0x20 }, + + { 0x28, 0x02 }, + { 0x29, 0x9f }, + { 0x2a, 0x00 }, + + { 0x13, 0x00 }, + { 0x14, 0xa0 }, + + { 0x1a, 0x5d }, + { 0x1b, 0x58 }, + { 0x1c, 0x60 }, + { 0x1d, 0x4f }, + + { 0x1e, 0x68 }, + { 0x1f, 0x42 }, /*44, Indoor Rgain Min */ + { 0x20, 0x7A }, /*75 82, 8a, Indoor Bgain Max */ + { 0x21, 0x4D }, /* 4Indoor Bgain Min */ + + { 0x3a, 0x13 }, + { 0x3b, 0x3c }, + { 0x3c, 0x00 }, + { 0x3d, 0x18 }, + + { 0x23, 0x80 }, + + { 0x15, 0x0b }, + { 0x16, 0xd2 }, + { 0x17, 0x64 }, + { 0x18, 0x78 }, + + { 0xef, 0x00 }, + { 0xde, 0x00 }, + { 0xdf, 0x1f }, + { 0xe0, 0x00 }, + { 0xe1, 0x37 }, + { 0xe2, 0x08 }, + { 0xe3, 0x42 }, + { 0xe4, 0x00 }, + { 0xe5, 0x12 }, + { 0xe6, 0x9e }, + { 0xe9, 0x00 }, + { 0xe7, 0x01 }, + { 0xe8, 0x13 }, + { 0xe9, 0x01 }, + { 0xe7, 0x01 }, + { 0xe8, 0x06 }, + { 0xe9, 0x02 }, + { 0xe7, 0x00 }, + { 0xe8, 0xef }, + { 0xe9, 0x03 }, + { 0xe7, 0x00 }, + { 0xe8, 0xe0 }, + { 0xe9, 0x04 }, + { 0xe7, 0x00 }, + { 0xe8, 0xc3 }, + { 0xe9, 0x05 }, + { 0xe7, 0x00 }, + { 0xe8, 0xab }, + { 0xe9, 0x06 }, + { 0xe7, 0x00 }, + { 0xe8, 0x91 }, + { 0xe9, 0x07 }, + { 0xe7, 0x00 }, + { 0xe8, 0xbd }, + { 0xe9, 0x08 }, + { 0xe7, 0x00 }, + { 0xe8, 0xab }, + { 0xe9, 0x09 }, + { 0xe7, 0x00 }, + { 0xe8, 0x9a }, + { 0xe9, 0x0a }, + { 0xe7, 0x00 }, + { 0xe8, 0x8f }, + { 0xe9, 0x0b }, + { 0xe7, 0x00 }, + { 0xe8, 0x78 }, + { 0xe9, 0x0c }, + { 0xe7, 0x00 }, + { 0xe8, 0x69 }, + { 0xe9, 0x0d }, + { 0xe7, 0x00 }, + { 0xe8, 0x55 }, + { 0xe9, 0x0e }, + { 0xe7, 0x00 }, + { 0xe8, 0x4c }, + { 0xe9, 0x0f }, + { 0xe7, 0x00 }, + { 0xe8, 0x4d }, + { 0xe9, 0x10 }, + { 0xe7, 0x00 }, + { 0xe8, 0x43 }, + { 0xe9, 0x11 }, + { 0xe7, 0x00 }, + { 0xe8, 0x39 }, + { 0xe9, 0x12 }, + { 0xe7, 0x00 }, + { 0xe8, 0x26 }, + { 0xe9, 0x13 }, + { 0xe7, 0x00 }, + { 0xe8, 0x1e }, + { 0xe9, 0x14 }, + { 0xe7, 0x00 }, + { 0xe8, 0x0d }, + { 0xe9, 0x15 }, + { 0xe7, 0x07 }, + { 0xe8, 0xd8 }, + { 0xe9, 0x16 }, + { 0xe7, 0x07 }, + { 0xe8, 0xd8 }, + { 0xe9, 0x17 }, + { 0xe7, 0x07 }, + { 0xe8, 0xe1 }, + { 0xe9, 0x18 }, + { 0xe7, 0x07 }, + { 0xe8, 0xdc }, + { 0xe9, 0x19 }, + { 0xe7, 0x07 }, + { 0xe8, 0xd3 }, + { 0xe9, 0x1a }, + { 0xe7, 0x07 }, + { 0xe8, 0xcb }, + { 0xe9, 0x1b }, + { 0xe7, 0x07 }, + { 0xe8, 0xbe }, + { 0xe9, 0x1c }, + { 0xe7, 0x07 }, + { 0xe8, 0x62 }, + { 0xe9, 0x1d }, + { 0xe7, 0x07 }, + { 0xe8, 0x66 }, + { 0xe9, 0x1e }, + { 0xe7, 0x07 }, + { 0xe8, 0x71 }, + { 0xe9, 0x1f }, + { 0xe7, 0x07 }, + { 0xe8, 0x80 }, + { 0xe9, 0x20 }, + { 0xe7, 0x07 }, + { 0xe8, 0x75 }, + { 0xe9, 0x21 }, + { 0xe7, 0x07 }, + { 0xe8, 0x67 }, + { 0xe9, 0x22 }, + { 0xe7, 0x07 }, + { 0xe8, 0x85 }, + { 0xe9, 0x40 }, + + + { 0xd1, 0x08 }, + { 0xdd, 0x03 }, + + { 0x23, 0x17 }, + { 0x24, 0x17 }, + { 0x25, 0x17 }, + { 0x27, 0x18 }, + { 0x29, 0x60 }, + { 0x2a, 0x22 }, + + { 0x2f, 0x01 }, + + { 0x36, 0x01 }, + { 0x37, 0xc2 }, + { 0x38, 0xa8 }, + { 0x39, 0x98 }, + { 0x3a, 0x00 }, + { 0x3b, 0xf0 }, + { 0x3c, 0x01 }, + { 0x3d, 0x5e }, + { 0xb9, 0x02 }, + { 0xbb, 0xb0 }, + { 0xbc, 0x18 }, + { 0xbd, 0x30 }, + { 0xbf, 0x38 }, + { 0xc1, 0x88 }, + { 0xc8, 0x11 }, + { 0xeb, 0x81 }, + { 0xed, 0x05 }, + { 0xb1, 0x00 }, + { 0xb2, 0x62 }, + { 0xb3, 0x00 }, + { 0xb4, 0x00 }, + { 0xb5, 0x01 }, + { 0xb6, 0xa3 }, + { 0xb7, 0x02 }, + { 0xb8, 0x80 }, + { 0x77, 0x00 }, + { 0x78, 0x00 }, + { 0xef, 0x00 }, + { 0x93, 0x40 }, + { 0x94, 0x80 }, + { 0x95, 0xc0 }, + { 0x96, 0xc0 }, + { 0x97, 0x20 }, + { 0x98, 0x20 }, + { 0x99, 0x30 }, + { 0xA0, 0x00 }, + { 0xA1, 0x00 }, + { 0xA2, 0x1c }, + { 0xA3, 0x16 }, + { 0xA4, 0x03 }, + { 0xA5, 0x07 }, + { 0xA6, 0x00 }, + { 0xef, 0x00 }, + { 0xad, 0xd0 }, + { 0xaf, 0x10 }, + { 0xef, 0x00 }, + { 0x42, 0x65 }, + { 0x44, 0x61 }, + + { 0x57, 0x00 }, + + { 0xef, 0x03 }, + { 0x01, 0x3C }, + { 0x02, 0x05 }, + { 0x03, 0x21 }, + { 0x04, 0x60 }, + { 0x06, 0x1c }, + { 0x07, 0x01 }, + { 0x08, 0x01 }, + { 0x0b, 0x01 }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x55, 0x22 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xcf }, + { 0x69, 0x17 }, + { 0xef, 0x00 }, + { 0x58, 0x00 }, + { 0x59, 0x00 }, + { 0x5a, 0x02 }, + { 0x5b, 0x73 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + { 0x5f, 0xe0 }, + { 0x60, 0x00 }, + { 0x61, 0xEA }, + { 0x62, 0x01 }, + { 0x63, 0x80 }, + { 0x64, 0x00 }, + { 0x65, 0xAF }, + { 0x66, 0x01 }, + { 0x67, 0x2D }, + { 0xef, 0x00 }, + { 0x6a, 0x01 }, + { 0x6b, 0xe0 }, + { 0x6c, 0x05 }, + { 0x6d, 0x00 }, + { 0x6e, 0x0e }, + { 0x6f, 0x00 }, + { 0x70, 0x10 }, + { 0xef, 0x03 }, + { 0x22, 0x24 }, + { 0x3e, 0x23 }, + { 0x3f, 0x23 }, + { 0x40, 0x00 }, + { 0x41, 0x09 }, + { 0x4a, 0x09 }, + { 0x4b, 0x04 }, + { 0x5b, 0x20 }, + { 0x5d, 0x35 }, + { 0x5e, 0x13 }, + { 0x78, 0x0f }, + { 0xef, 0x00 }, + { 0x4c, 0x80 }, + { 0x4d, 0xbb }, + { 0x4e, 0x84 }, + { 0x4f, 0x91 }, + { 0x50, 0x64 }, + { 0x51, 0x93 }, + { 0x52, 0x03 }, + { 0x53, 0xc7 }, + { 0x54, 0x83 }, + { 0xef, 0x03 }, + { 0x6e, 0x40 }, + { 0x6f, 0x50 }, /* dgain for shutter 700lux*/ + + { 0xef, 0x00 }, + { 0x48, 0x00 }, + { 0x49, 0x00 }, + { 0x4A, 0x03 }, + { 0x48, 0x01 }, + { 0x49, 0x00 }, + { 0x4A, 0x06 }, + { 0x48, 0x02 }, + { 0x49, 0x00 }, + { 0x4A, 0x24 }, + { 0x48, 0x03 }, + { 0x49, 0x00 }, + { 0x4A, 0x8a }, + { 0x48, 0x04 }, + { 0x49, 0x01 }, + { 0x4A, 0x20 }, + { 0x48, 0x05 }, + { 0x49, 0x01 }, + { 0x4A, 0xB4 }, + { 0x48, 0x06 }, + { 0x49, 0x02 }, + { 0x4A, 0x23 }, + { 0x48, 0x07 }, + { 0x49, 0x02 }, + { 0x4A, 0x72 }, + { 0x48, 0x08 }, + { 0x49, 0x02 }, + { 0x4A, 0xBE }, + { 0x48, 0x09 }, + { 0x49, 0x02 }, + { 0x4A, 0xFA }, + { 0x48, 0x0A }, + { 0x49, 0x03 }, + { 0x4A, 0x27 }, + { 0x48, 0x0B }, + { 0x49, 0x03 }, + { 0x4A, 0x55 }, + { 0x48, 0x0C }, + { 0x49, 0x03 }, + { 0x4A, 0x81 }, + { 0x48, 0x0D }, + { 0x49, 0x03 }, + { 0x4A, 0xA2 }, + { 0x48, 0x0E }, + { 0x49, 0x03 }, + { 0x4A, 0xBC }, + { 0x48, 0x0F }, + { 0x49, 0x03 }, + { 0x4A, 0xD4 }, + { 0x48, 0x10 }, + { 0x49, 0x03 }, + { 0x4A, 0xE8 }, + { 0x48, 0x11 }, + { 0x49, 0x03 }, + { 0x4A, 0xF4 }, + { 0x48, 0x12 }, + { 0x49, 0x03 }, + { 0x4A, 0xFF }, + { 0x48, 0x20 }, + { 0x49, 0x00 }, + { 0x4A, 0x03 }, + { 0x48, 0x21 }, + { 0x49, 0x00 }, + { 0x4A, 0x06 }, + { 0x48, 0x22 }, + { 0x49, 0x00 }, + { 0x4A, 0x24 }, + { 0x48, 0x23 }, + { 0x49, 0x00 }, + { 0x4A, 0x8a }, + { 0x48, 0x24 }, + { 0x49, 0x01 }, + { 0x4A, 0x20 }, + { 0x48, 0x25 }, + { 0x49, 0x01 }, + { 0x4A, 0xB4 }, + { 0x48, 0x26 }, + { 0x49, 0x02 }, + { 0x4A, 0x23 }, + { 0x48, 0x27 }, + { 0x49, 0x02 }, + { 0x4A, 0x72 }, + { 0x48, 0x28 }, + { 0x49, 0x02 }, + { 0x4A, 0xBE }, + { 0x48, 0x29 }, + { 0x49, 0x02 }, + { 0x4A, 0xFA }, + { 0x48, 0x2A }, + { 0x49, 0x03 }, + { 0x4A, 0x27 }, + { 0x48, 0x2B }, + { 0x49, 0x03 }, + { 0x4A, 0x55 }, + { 0x48, 0x2C }, + { 0x49, 0x03 }, + { 0x4A, 0x81 }, + { 0x48, 0x2D }, + { 0x49, 0x03 }, + { 0x4A, 0xA2 }, + { 0x48, 0x2E }, + { 0x49, 0x03 }, + { 0x4A, 0xBC }, + { 0x48, 0x2F }, + { 0x49, 0x03 }, + { 0x4A, 0xD4 }, + { 0x48, 0x30 }, + { 0x49, 0x03 }, + { 0x4A, 0xE8 }, + { 0x48, 0x31 }, + { 0x49, 0x03 }, + { 0x4A, 0xF4 }, + { 0x48, 0x32 }, + { 0x49, 0x03 }, + { 0x4A, 0xFF }, + { 0x48, 0x40 }, + { 0x49, 0x00 }, + { 0x4A, 0x03 }, + { 0x48, 0x41 }, + { 0x49, 0x00 }, + { 0x4A, 0x06 }, + { 0x48, 0x42 }, + { 0x49, 0x00 }, + { 0x4A, 0x24 }, + { 0x48, 0x43 }, + { 0x49, 0x00 }, + { 0x4A, 0x8a }, + { 0x48, 0x44 }, + { 0x49, 0x01 }, + { 0x4A, 0x20 }, + { 0x48, 0x45 }, + { 0x49, 0x01 }, + { 0x4A, 0xB4 }, + { 0x48, 0x46 }, + { 0x49, 0x02 }, + { 0x4A, 0x23 }, + { 0x48, 0x47 }, + { 0x49, 0x02 }, + { 0x4A, 0x72 }, + { 0x48, 0x48 }, + { 0x49, 0x02 }, + { 0x4A, 0xBE }, + { 0x48, 0x49 }, + { 0x49, 0x02 }, + { 0x4A, 0xFA }, + { 0x48, 0x4A }, + { 0x49, 0x03 }, + { 0x4A, 0x27 }, + { 0x48, 0x4B }, + { 0x49, 0x03 }, + { 0x4A, 0x55 }, + { 0x48, 0x4C }, + { 0x49, 0x03 }, + { 0x4A, 0x81 }, + { 0x48, 0x4D }, + { 0x49, 0x03 }, + { 0x4A, 0xA2 }, + { 0x48, 0x4E }, + { 0x49, 0x03 }, + { 0x4A, 0xBC }, + { 0x48, 0x4F }, + { 0x49, 0x03 }, + { 0x4A, 0xD4 }, + { 0x48, 0x50 }, + { 0x49, 0x03 }, + { 0x4A, 0xE8 }, + { 0x48, 0x51 }, + { 0x49, 0x03 }, + { 0x4A, 0xF4 }, + { 0x48, 0x52 }, + { 0x49, 0x03 }, + { 0x4A, 0xFF }, + { 0xEF, 0x03 }, + { 0x00, 0x03 }, +}; + +/* + * VT init setting + */ +struct s5ka3dfx_reg s5ka3dfx_init_vt_reg[] = { + { 0xef, 0x02 }, + { 0x13, 0xa0 }, + { 0x23, 0x53 }, + { 0x26, 0x24 }, + { 0x2c, 0x05 }, + { 0x05, 0x00 }, + { 0x03, 0x58 }, + { 0x24, 0x0a }, + { 0x0b, 0x82 }, + { 0x1e, 0xb7 }, + { 0x56, 0x05 }, + { 0x28, 0x96 }, + { 0x67, 0x3c }, + { 0x4b, 0x5e }, + { 0xef, 0x03 }, + { 0x50, 0xd2 }, + { 0x0f, 0x31 }, + { 0xef, 0x03 }, + { 0x5F, 0x03 }, + { 0x60, 0x02 }, + { 0x61, 0x0f }, + { 0x62, 0x0c }, + { 0x63, 0x05 }, + { 0x64, 0x43 }, + { 0x65, 0x05 }, + { 0x66, 0x43 }, + { 0x6d, 0x5a }, + { 0x6e, 0x40 }, + { 0x6f, 0x70 }, + { 0x4c, 0x00 }, + { 0x4d, 0x9e }, + { 0xef, 0x03 }, + { 0x00, 0x87 }, + { 0x01, 0x80 }, + { 0x02, 0x7f }, + { 0x2b, 0x41 }, + { 0x31, 0x07 }, + { 0x32, 0x18 }, + { 0x33, 0x80 }, + { 0x34, 0x79 }, + { 0x36, 0x36 }, + { 0x37, 0x27 }, + { 0x6a, 0x00 }, + { 0x7b, 0x05 }, + { 0x38, 0x05 }, + { 0x39, 0x03 }, + { 0x2d, 0x08 }, + { 0x2e, 0x20 }, + { 0x2f, 0x30 }, + { 0x30, 0xff }, + { 0x7c, 0x06 }, + { 0x7d, 0x20 }, + { 0x7e, 0x0c }, + { 0x7f, 0x20 }, + { 0x28, 0x02 }, + { 0x29, 0xa8 }, + { 0x2a, 0x00 }, + { 0x13, 0x00 }, + { 0x14, 0xa0 }, + { 0x1a, 0x6a }, + { 0x1b, 0x50 }, + { 0x1c, 0x63 }, + { 0x1d, 0x4b }, + { 0x1e, 0x6a }, + { 0x1f, 0x3c }, + { 0x20, 0x9a }, + { 0x21, 0x4b }, + { 0x3a, 0x13 }, + { 0x3b, 0x3e }, + { 0x3c, 0x00 }, + { 0x3d, 0x18 }, + { 0x23, 0x80 }, + { 0x15, 0x0b }, + { 0x16, 0xd2 }, + { 0x17, 0x64 }, + { 0x18, 0x78 }, + { 0xef, 0x00 }, + { 0xde, 0x00 }, + { 0xdf, 0x1F }, + { 0xe0, 0x00 }, + { 0xe1, 0x37 }, + { 0xe2, 0x08 }, + { 0xe3, 0x42 }, + { 0xe4, 0x00 }, + { 0xe5, 0x12 }, + { 0xe6, 0x9E }, + { 0xe9, 0x00 }, + { 0xe7, 0x00 }, + { 0xe8, 0xA8 }, + { 0xe9, 0x01 }, + { 0xe7, 0x00 }, + { 0xe8, 0xB1 }, + { 0xe9, 0x02 }, + { 0xe7, 0x00 }, + { 0xe8, 0xC4 }, + { 0xe9, 0x03 }, + { 0xe7, 0x00 }, + { 0xe8, 0xBA }, + { 0xe9, 0x04 }, + { 0xe7, 0x00 }, + { 0xe8, 0xC4 }, + { 0xe9, 0x05 }, + { 0xe7, 0x00 }, + { 0xe8, 0xE5 }, + { 0xe9, 0x06 }, + { 0xe7, 0x01 }, + { 0xe8, 0x13 }, + { 0xe9, 0x07 }, + { 0xe7, 0x00 }, + { 0xe8, 0x4B }, + { 0xe9, 0x08 }, + { 0xe7, 0x00 }, + { 0xe8, 0x4B }, + { 0xe9, 0x09 }, + { 0xe7, 0x00 }, + { 0xe8, 0x4E }, + { 0xe9, 0x0A }, + { 0xe7, 0x00 }, + { 0xe8, 0x4F }, + { 0xe9, 0x0B }, + { 0xe7, 0x00 }, + { 0xe8, 0x42 }, + { 0xe9, 0x0C }, + { 0xe7, 0x00 }, + { 0xe8, 0x6A }, + { 0xe9, 0x0D }, + { 0xe7, 0x00 }, + { 0xe8, 0x89 }, + { 0xe9, 0x0E }, + { 0xe7, 0x07 }, + { 0xe8, 0xD9 }, + { 0xe9, 0x0F }, + { 0xe7, 0x07 }, + { 0xe8, 0xD8 }, + { 0xe9, 0x10 }, + { 0xe7, 0x07 }, + { 0xe8, 0xDD }, + { 0xe9, 0x11 }, + { 0xe7, 0x07 }, + { 0xe8, 0xD1 }, + { 0xe9, 0x12 }, + { 0xe7, 0x07 }, + { 0xe8, 0xCA }, + { 0xe9, 0x13 }, + { 0xe7, 0x07 }, + { 0xe8, 0xCE }, + { 0xe9, 0x14 }, + { 0xe7, 0x07 }, + { 0xe8, 0xFA }, + { 0xe9, 0x15 }, + { 0xe7, 0x07 }, + { 0xe8, 0x6A }, + { 0xe9, 0x16 }, + { 0xe7, 0x07 }, + { 0xe8, 0x71 }, + { 0xe9, 0x17 }, + { 0xe7, 0x07 }, + { 0xe8, 0x70 }, + { 0xe9, 0x18 }, + { 0xe7, 0x07 }, + { 0xe8, 0x5E }, + { 0xe9, 0x19 }, + { 0xe7, 0x07 }, + { 0xe8, 0x50 }, + { 0xe9, 0x1A }, + { 0xe7, 0x07 }, + { 0xe8, 0x55 }, + { 0xe9, 0x1B }, + { 0xe7, 0x07 }, + { 0xe8, 0x6D }, + { 0xe9, 0x1C }, + { 0xe7, 0x07 }, + { 0xe8, 0x1C }, + { 0xe9, 0x1D }, + { 0xe7, 0x07 }, + { 0xe8, 0x12 }, + { 0xe9, 0x1E }, + { 0xe7, 0x07 }, + { 0xe8, 0x07 }, + { 0xe9, 0x1F }, + { 0xe7, 0x06 }, + { 0xe8, 0xFA }, + { 0xe9, 0x20 }, + { 0xe7, 0x06 }, + { 0xe8, 0xE5 }, + { 0xe9, 0x21 }, + { 0xe7, 0x06 }, + { 0xe8, 0xF0 }, + { 0xe9, 0x22 }, + { 0xe7, 0x07 }, + { 0xe8, 0x0A }, + { 0xe9, 0x40 }, + { 0xd1, 0x08 }, + { 0xdd, 0x03 }, + { 0x23, 0x10 }, + { 0x24, 0x10 }, + { 0x25, 0x10 }, + { 0x27, 0x18 }, + { 0x29, 0x60 }, + { 0x2a, 0x22 }, + { 0x2f, 0x01 }, + { 0x36, 0x01 }, + { 0x37, 0xe1 }, + { 0x38, 0xc7 }, + { 0x39, 0xb1 }, + { 0x3a, 0x01 }, + { 0x3b, 0x04 }, + { 0x3c, 0x01 }, + { 0x3d, 0x54 }, + { 0xb9, 0x02 }, + { 0xbb, 0xb0 }, + { 0xbc, 0x18 }, + { 0xbd, 0x30 }, + { 0xbf, 0x38 }, + { 0xc1, 0x88 }, + { 0xc8, 0x11 }, + { 0xeb, 0x81 }, + { 0xed, 0x05 }, + { 0xb1, 0x00 }, + { 0xb2, 0x62 }, + { 0xb3, 0x00 }, + { 0xb4, 0x00 }, + { 0xb5, 0x01 }, + { 0xb6, 0xa3 }, + { 0xb7, 0x02 }, + { 0xb8, 0x80 }, + { 0x77, 0x00 }, + { 0x78, 0x10 }, + { 0xef, 0x00 }, + { 0x93, 0x40 }, + { 0x94, 0x80 }, + { 0x95, 0xc0 }, + { 0x96, 0xc0 }, + { 0x97, 0x20 }, + { 0x98, 0x20 }, + { 0x99, 0x30 }, + { 0xA0, 0x00 }, + { 0xA1, 0x00 }, + { 0xA2, 0x1c }, + { 0xA3, 0x16 }, + { 0xA4, 0x03 }, + { 0xA5, 0x07 }, + { 0xA6, 0x00 }, + { 0xef, 0x00 }, + { 0xad, 0xd0 }, + { 0xaf, 0x10 }, + { 0xef, 0x00 }, + { 0x42, 0x5f }, + { 0x44, 0x61 }, + { 0x57, 0x00 }, + { 0xef, 0x03 }, + { 0x00, 0x87 }, + { 0x01, 0x3c }, + { 0x02, 0x05 }, + { 0x03, 0x21 }, + { 0x04, 0x6c }, + { 0x06, 0x1c }, + { 0x07, 0x01 }, + { 0x08, 0x01 }, + { 0x0b, 0x01 }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x55, 0x22 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xcf }, + { 0x69, 0x17 }, + { 0xef, 0x00 }, + { 0x58, 0x00 }, + { 0x59, 0x00 }, + { 0x5a, 0x02 }, + { 0x5b, 0x73 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + { 0x5f, 0xe0 }, + { 0x60, 0x00 }, + { 0x61, 0xae }, + { 0x62, 0x01 }, + { 0x63, 0xbb }, + { 0x64, 0x00 }, + { 0x65, 0x7e }, + { 0x66, 0x01 }, + { 0x67, 0x8e }, + { 0xef, 0x00 }, + { 0x6a, 0x01 }, + { 0x6b, 0xe0 }, + { 0x6c, 0x05 }, + { 0x6d, 0x00 }, + { 0x6e, 0x0e }, + { 0x6f, 0x00 }, + { 0x70, 0x10 }, + { 0xef, 0x03 }, + { 0x22, 0x24 }, + { 0x3e, 0x23 }, + { 0x3f, 0x23 }, + { 0x40, 0x00 }, + { 0x41, 0x09 }, + { 0x4a, 0x09 }, + { 0x4b, 0x04 }, + { 0x5b, 0x20 }, + { 0x5d, 0x35 }, + { 0x5e, 0x13 }, + { 0x78, 0x0f }, + { 0xef, 0x00 }, + { 0x4c, 0x79 }, + { 0x4d, 0xbe }, + { 0x4e, 0x08 }, + { 0x4f, 0x9c }, + { 0x50, 0x7a }, + { 0x51, 0x9e }, + { 0x52, 0x8f }, + { 0x53, 0xbb }, + { 0x54, 0x8a }, + { 0xef, 0x03 }, + { 0x70, 0x00 }, + { 0xef, 0x00 }, + { 0x48, 0x00 }, + { 0x49, 0x00 }, + { 0x4A, 0x03 }, + { 0x48, 0x01 }, + { 0x49, 0x00 }, + { 0x4A, 0x08 }, + { 0x48, 0x02 }, + { 0x49, 0x00 }, + { 0x4A, 0x4A }, + { 0x48, 0x03 }, + { 0x49, 0x00 }, + { 0x4A, 0x96 }, + { 0x48, 0x04 }, + { 0x49, 0x01 }, + { 0x4A, 0x24 }, + { 0x48, 0x05 }, + { 0x49, 0x01 }, + { 0x4A, 0xB4 }, + { 0x48, 0x06 }, + { 0x49, 0x02 }, + { 0x4A, 0x23 }, + { 0x48, 0x07 }, + { 0x49, 0x02 }, + { 0x4A, 0x72 }, + { 0x48, 0x08 }, + { 0x49, 0x02 }, + { 0x4A, 0xBE }, + { 0x48, 0x09 }, + { 0x49, 0x02 }, + { 0x4A, 0xFA }, + { 0x48, 0x0A }, + { 0x49, 0x03 }, + { 0x4A, 0x27 }, + { 0x48, 0x0B }, + { 0x49, 0x03 }, + { 0x4A, 0x55 }, + { 0x48, 0x0C }, + { 0x49, 0x03 }, + { 0x4A, 0x81 }, + { 0x48, 0x0D }, + { 0x49, 0x03 }, + { 0x4A, 0xA2 }, + { 0x48, 0x0E }, + { 0x49, 0x03 }, + { 0x4A, 0xBC }, + { 0x48, 0x0F }, + { 0x49, 0x03 }, + { 0x4A, 0xD4 }, + { 0x48, 0x10 }, + { 0x49, 0x03 }, + { 0x4A, 0xE8 }, + { 0x48, 0x11 }, + { 0x49, 0x03 }, + { 0x4A, 0xF4 }, + { 0x48, 0x12 }, + { 0x49, 0x03 }, + { 0x4A, 0xFF }, + { 0x48, 0x20 }, + { 0x49, 0x00 }, + { 0x4A, 0x03 }, + { 0x48, 0x21 }, + { 0x49, 0x00 }, + { 0x4A, 0x08 }, + { 0x48, 0x22 }, + { 0x49, 0x00 }, + { 0x4A, 0x4A }, + { 0x48, 0x23 }, + { 0x49, 0x00 }, + { 0x4A, 0x96 }, + { 0x48, 0x24 }, + { 0x49, 0x01 }, + { 0x4A, 0x24 }, + { 0x48, 0x25 }, + { 0x49, 0x01 }, + { 0x4A, 0xB4 }, + { 0x48, 0x26 }, + { 0x49, 0x02 }, + { 0x4A, 0x23 }, + { 0x48, 0x27 }, + { 0x49, 0x02 }, + { 0x4A, 0x72 }, + { 0x48, 0x28 }, + { 0x49, 0x02 }, + { 0x4A, 0xBE }, + { 0x48, 0x29 }, + { 0x49, 0x02 }, + { 0x4A, 0xFA }, + { 0x48, 0x2A }, + { 0x49, 0x03 }, + { 0x4A, 0x27 }, + { 0x48, 0x2B }, + { 0x49, 0x03 }, + { 0x4A, 0x55 }, + { 0x48, 0x2C }, + { 0x49, 0x03 }, + { 0x4A, 0x81 }, + { 0x48, 0x2D }, + { 0x49, 0x03 }, + { 0x4A, 0xA2 }, + { 0x48, 0x2E }, + { 0x49, 0x03 }, + { 0x4A, 0xBC }, + { 0x48, 0x2F }, + { 0x49, 0x03 }, + { 0x4A, 0xD4 }, + { 0x48, 0x30 }, + { 0x49, 0x03 }, + { 0x4A, 0xE8 }, + { 0x48, 0x31 }, + { 0x49, 0x03 }, + { 0x4A, 0xF4 }, + { 0x48, 0x32 }, + { 0x49, 0x03 }, + { 0x4A, 0xFF }, + { 0x48, 0x40 }, + { 0x49, 0x00 }, + { 0x4A, 0x03 }, + { 0x48, 0x41 }, + { 0x49, 0x00 }, + { 0x4A, 0x08 }, + { 0x48, 0x42 }, + { 0x49, 0x00 }, + { 0x4A, 0x4A }, + { 0x48, 0x43 }, + { 0x49, 0x00 }, + { 0x4A, 0x96 }, + { 0x48, 0x44 }, + { 0x49, 0x01 }, + { 0x4A, 0x24 }, + { 0x48, 0x45 }, + { 0x49, 0x01 }, + { 0x4A, 0xB4 }, + { 0x48, 0x46 }, + { 0x49, 0x02 }, + { 0x4A, 0x23 }, + { 0x48, 0x47 }, + { 0x49, 0x02 }, + { 0x4A, 0x72 }, + { 0x48, 0x48 }, + { 0x49, 0x02 }, + { 0x4A, 0xBE }, + { 0x48, 0x49 }, + { 0x49, 0x02 }, + { 0x4A, 0xFA }, + { 0x48, 0x4A }, + { 0x49, 0x03 }, + { 0x4A, 0x27 }, + { 0x48, 0x4B }, + { 0x49, 0x03 }, + { 0x4A, 0x55 }, + { 0x48, 0x4C }, + { 0x49, 0x03 }, + { 0x4A, 0x81 }, + { 0x48, 0x4D }, + { 0x49, 0x03 }, + { 0x4A, 0xA2 }, + { 0x48, 0x4E }, + { 0x49, 0x03 }, + { 0x4A, 0xBC }, + { 0x48, 0x4F }, + { 0x49, 0x03 }, + { 0x4A, 0xD4 }, + { 0x48, 0x50 }, + { 0x49, 0x03 }, + { 0x4A, 0xE8 }, + { 0x48, 0x51 }, + { 0x49, 0x03 }, + { 0x4A, 0xF4 }, + { 0x48, 0x52 }, + { 0x49, 0x03 }, + { 0x4A, 0xFF }, +}; + +/* Exposure Value Setting */ +/* EV bias */ +struct s5ka3dfx_reg s5ka3dfx_ev_m5[] = { + { 0xef, 0x03 }, + { 0x31, 0xc0 }, + { 0x32, 0x98 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_m4[] = { + { 0xef, 0x03 }, + { 0x31, 0xA5 }, + { 0x32, 0x90 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_m3[] = { + { 0xef, 0x03 }, + { 0x31, 0x9E }, + { 0x32, 0x88 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_m2[] = { + { 0xef, 0x03 }, + { 0x31, 0x90 }, + { 0x32, 0x00 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_m1[] = { + { 0xef, 0x03 }, + { 0x31, 0x8A }, + { 0x32, 0x08 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_default[] = { + { 0xef, 0x03 }, + { 0x31, 0x00 }, + { 0x32, 0x09 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_p1[] = { + { 0xef, 0x03 }, + { 0x31, 0x0A }, + { 0x32, 0x20 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_p2[] = { + { 0xef, 0x03 }, + { 0x31, 0x14 }, + { 0x32, 0x30 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_p3[] = { + { 0xef, 0x03 }, + { 0x31, 0x1E }, + { 0x32, 0x38 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_p4[] = { + { 0xef, 0x03 }, + { 0x31, 0x28 }, + { 0x32, 0x40 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_p5[] = { + { 0xef, 0x03 }, + { 0x31, 0x30 }, + { 0x32, 0x48 }, +}; + +/* EV bias for VT */ +struct s5ka3dfx_reg s5ka3dfx_ev_vt_m5[] = { + { 0xef, 0x03 }, + { 0x31, 0xa9 }, + { 0x32, 0xa4 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_m4[] = { + { 0xef, 0x03 }, + { 0x31, 0x99 }, + { 0x32, 0x9c }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_m3[] = { + { 0xef, 0x03 }, + { 0x31, 0x91 }, + { 0x32, 0x94 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_m2[] = { + { 0xef, 0x03 }, + { 0x31, 0x89 }, + { 0x32, 0x08 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_m1[] = { + { 0xef, 0x03 }, + { 0x31, 0x81 }, + { 0x32, 0x10 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_default[] = { + { 0xef, 0x03 }, + { 0x31, 0x07 }, + { 0x32, 0x18 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_p1[] = { + { 0xef, 0x03 }, + { 0x31, 0x0e }, + { 0x32, 0x28 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_p2[] = { + { 0xef, 0x03 }, + { 0x31, 0x17 }, + { 0x32, 0x38 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_p3[] = { + { 0xef, 0x03 }, + { 0x31, 0x27 }, + { 0x32, 0x40 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_p4[] = { + { 0xef, 0x03 }, + { 0x31, 0x2a }, + { 0x32, 0x3e }, +}; + +struct s5ka3dfx_reg s5ka3dfx_ev_vt_p5[] = { + { 0xef, 0x03 }, + { 0x31, 0x32 }, + { 0x32, 0x46 }, +}; + +/* White Balance Setting */ +struct s5ka3dfx_reg s5ka3dfx_wb_auto[] = { + { 0xef, 0x03 }, + { 0x00, 0x87 }, + { 0xef, 0x00 }, + { 0x42, 0x6f }, + { 0x43, 0x40 }, + { 0x44, 0x5a }, +}; + +struct s5ka3dfx_reg s5ka3dfx_wb_tungsten[] = { + { 0xef, 0x03 }, + { 0x00, 0x85 }, + { 0xef, 0x00 }, + { 0x42, 0x48 }, + { 0x43, 0x43 }, + { 0x44, 0x7e }, +}; + +struct s5ka3dfx_reg s5ka3dfx_wb_fluorescent[] = { + { 0xef, 0x03 }, + { 0x00, 0x85 }, + { 0xef, 0x00 }, + { 0x42, 0x5c }, + { 0x43, 0x40 }, + { 0x44, 0x6d }, +}; + +struct s5ka3dfx_reg s5ka3dfx_wb_sunny[] = { + { 0xef, 0x03 }, + { 0x00, 0x85 }, + { 0xef, 0x00 }, + { 0x42, 0x67 }, + { 0x43, 0x40 }, + { 0x44, 0x4c }, +}; + +struct s5ka3dfx_reg s5ka3dfx_wb_cloudy[] = { + { 0xef, 0x03 }, + { 0x00, 0x85 }, + { 0xef, 0x00 }, + { 0x42, 0x75 }, + { 0x43, 0x3d }, + { 0x44, 0x42 }, +}; + +/* Effect Setting */ +struct s5ka3dfx_reg s5ka3dfx_effect_none[] = { + { 0xef, 0x00 }, + { 0xd3, 0x00 }, + { 0xd4, 0x00 }, + { 0xd5, 0x01 }, + { 0xd6, 0xa3 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_effect_gray[] = { + { 0xef, 0x00 }, + { 0xd3, 0x00 }, + { 0xd4, 0x03 }, + { 0xd5, 0x80 }, + { 0xd6, 0x80 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_effect_sepia[] = { + { 0xef, 0x00 }, + { 0xd3, 0x00 }, + { 0xd4, 0x03 }, + { 0xd5, 0x60 }, + { 0xd6, 0x8c }, +}; + +struct s5ka3dfx_reg s5ka3dfx_effect_negative[] = { + { 0xef, 0x00 }, + { 0xd3, 0x01 }, + { 0xd4, 0x00 }, + { 0xd5, 0x2c }, + { 0xd6, 0x81 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_effect_aqua[] = { + { 0xef, 0x00 }, + { 0xd3, 0x00 }, + { 0xd4, 0x03 }, + { 0xd5, 0xdc }, + { 0xd6, 0x00 }, +}; + +/* Blur Setting */ +/*Self shot*/ +struct s5ka3dfx_reg s5ka3dfx_blur_none[] = { + { 0xef, 0x03 }, + { 0x01, 0x3c }, + { 0x29, 0x8f }, + { 0x34, 0x79 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_blur_p1[] = { + { 0xef, 0x03 }, + { 0x01, 0x4a }, + { 0x29, 0x5f }, + { 0x34, 0x89 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_blur_p2[] = { + { 0xef, 0x03 }, + { 0x01, 0x58 }, + { 0x29, 0x2f }, + { 0x34, 0x99 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_blur_p3[] = { + { 0xef, 0x03 }, + { 0x01, 0x66 }, + { 0x29, 0x00 }, + { 0x34, 0xa9 }, +}; + +/*vt call*/ +struct s5ka3dfx_reg s5ka3dfx_blur_vt_none[] = { + { 0xef, 0x03 }, + { 0x01, 0x3c }, + { 0x29, 0xa8 }, + { 0x34, 0x79 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_blur_vt_p1[] = { + { 0xef, 0x03 }, + { 0x01, 0x4a }, + { 0x29, 0x68 }, + { 0x34, 0x89 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_blur_vt_p2[] = { + { 0xef, 0x03 }, + { 0x01, 0x58 }, + { 0x29, 0x38 }, + { 0x34, 0x99 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_blur_vt_p3[] = { + { 0xef, 0x03 }, + { 0x01, 0x66 }, + { 0x29, 0x18 }, + { 0x34, 0xa9 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_dataline[] = { + { 0xef, 0x00 }, + { 0x0a, 0x01 }, /* s/w reset */ + { 0x04, 0x01 }, + { 0xcb, 0x01 }, + { 0xd1, 0x08 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_dataline_stop[] = { + { 0xef, 0x00 }, + { 0xcb, 0x00 }, +}; + +/* FPS */ +struct s5ka3dfx_reg s5ka3dfx_fps_7[] = { + { 0xEF, 0x03 }, + { 0x5F, 0x03 }, + { 0x60, 0x02 }, + { 0x61, 0x11 }, + { 0x62, 0x0E }, + { 0x63, 0x06 }, + { 0x64, 0x4B }, + { 0x65, 0x06 }, + { 0x66, 0x4B }, + { 0x48, 0x00 }, + { 0x49, 0x9E }, + { 0x4C, 0x00 }, + { 0x4D, 0x9E }, + { 0xEF, 0x03 }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xCF }, +}; + +struct s5ka3dfx_reg s5ka3dfx_fps_10[] = { + { 0xEF, 0x03 }, + { 0x5F, 0x03 }, + { 0x60, 0x02 }, + { 0x61, 0x0C }, + { 0x62, 0x0A }, + { 0x63, 0x03 }, + { 0x64, 0xD3 }, + { 0x65, 0x03 }, + { 0x66, 0xD3 }, + { 0x48, 0x00 }, + { 0x49, 0x9E }, + { 0x4C, 0x00 }, + { 0x4D, 0x9E }, + { 0xEF, 0x03 }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xCF }, +}; + +struct s5ka3dfx_reg s5ka3dfx_fps_15[] = { + { 0xEF, 0x03 }, + { 0x5F, 0x03 }, + { 0x60, 0x02 }, + { 0x61, 0x08 }, + { 0x62, 0x06 }, + { 0x63, 0x01 }, + { 0x64, 0xE7 }, + { 0x65, 0x01 }, + { 0x66, 0xE7 }, + { 0x48, 0x00 }, + { 0x49, 0x9E }, + { 0x4C, 0x00 }, + { 0x4D, 0x9E }, + { 0xEF, 0x03 }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xCF }, +}; + +struct s5ka3dfx_reg s5ka3dfx_fps_auto[] = { + { 0xEF, 0x03 }, + { 0x5F, 0x03 }, + { 0x60, 0x02 }, + { 0x61, 0x0F }, + { 0x62, 0x0C }, + { 0x63, 0x01 }, + { 0x64, 0xE7 }, + { 0x65, 0x01 }, + { 0x66, 0xE7 }, + { 0x48, 0x00 }, + { 0x49, 0x9E }, + { 0x4C, 0x00 }, + { 0x4D, 0x9E }, + { 0xEF, 0x03 }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xCF }, +}; +struct s5ka3dfx_reg s5ka3dfx_vt_fps_7[] = { + { 0xef, 0x03 }, + { 0x50, 0xd2 }, + { 0x0f, 0x31 }, + { 0xef, 0x03 }, + { 0x5f, 0x11 }, + { 0x60, 0x0e }, + { 0x61, 0x11 }, + { 0x62, 0x0e }, + { 0x63, 0x06 }, + { 0x64, 0x4b }, + { 0x65, 0x06 }, + { 0x66, 0x4b }, + { 0x6d, 0x6c }, + { 0x6E, 0x40 }, + { 0x6f, 0x40 }, + { 0x4c, 0x00 }, + { 0x4d, 0x9E }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x55, 0x22 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xcf }, +}; + +struct s5ka3dfx_reg s5ka3dfx_vt_fps_10[] = { + { 0xef, 0x03 }, + { 0x50, 0xd2 }, + { 0x0f, 0x31 }, + { 0xef, 0x03 }, + { 0x5f, 0x0c }, + { 0x60, 0x0a }, + { 0x61, 0x0c }, + { 0x62, 0x0a }, + { 0x63, 0x03 }, + { 0x64, 0xd3 }, + { 0x65, 0x03 }, + { 0x66, 0xd3 }, + { 0x6d, 0x6C }, + { 0x6E, 0x40 }, + { 0x6f, 0x40 }, + { 0x4c, 0x00 }, + { 0x4d, 0x9E }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x55, 0x22 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xcf }, +}; + +struct s5ka3dfx_reg s5ka3dfx_vt_fps_15[] = { + { 0xef, 0x03 }, + { 0x50, 0xd2 }, + { 0x0f, 0x31 }, + { 0xef, 0x03 }, + { 0x5f, 0x08 }, + { 0x60, 0x06 }, + { 0x61, 0x08 }, + { 0x62, 0x06 }, + { 0x63, 0x01 }, + { 0x64, 0xE7 }, + { 0x65, 0x01 }, + { 0x66, 0xE7 }, + { 0x6d, 0x6C }, + { 0x6E, 0x40 }, + { 0x6f, 0x40 }, + { 0x4c, 0x00 }, + { 0x4d, 0x9E }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x55, 0x22 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xcf }, +}; + +struct s5ka3dfx_reg s5ka3dfx_vt_fps_auto[] = { + { 0xef, 0x03 }, + { 0x50, 0xd2 }, + { 0x0f, 0x31 }, + { 0xef, 0x03 }, + { 0x5f, 0x03 }, + { 0x60, 0x02 }, + { 0x61, 0x0f }, + { 0x62, 0x0c }, + { 0x63, 0x05 }, + { 0x64, 0x43 }, + { 0x65, 0x05 }, + { 0x66, 0x43 }, + { 0x6d, 0x5a }, + { 0x6E, 0x40 }, + { 0x6f, 0x70 }, + { 0x4c, 0x00 }, + { 0x4d, 0x9E }, + { 0x51, 0x10 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x00 }, + { 0x55, 0x22 }, + { 0x56, 0x01 }, + { 0x57, 0x61 }, + { 0x58, 0x25 }, + { 0x67, 0xcf }, + +}; + +struct s5ka3dfx_reg s5ka3dfx_Return_VGA[] = { + { 0xef, 0x00 }, + { 0x7a, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x15, 0x02 }, + { 0x16, 0x90 }, + { 0x13, 0x01 }, + { 0x14, 0xF0 }, + { 0x31, 0x04 }, + { 0x30, 0x06 }, + { 0x34, 0x02 }, + { 0x35, 0x88 }, + { 0x32, 0x01 }, + { 0x33, 0xE8 }, + { 0x7d, 0x02 }, + { 0x7e, 0x88 }, + { 0x7b, 0x01 }, + { 0x7C, 0xe8 }, + { 0x81, 0x02 }, + { 0x82, 0x01 }, + { 0x7f, 0x01 }, + { 0x80, 0xe8 }, + { 0xc3, 0x04 }, + { 0xc2, 0x04 }, + { 0xc6, 0x02 }, + { 0xc7, 0x80 }, + { 0xc4, 0x01 }, + { 0xc5, 0xe0 }, + { 0x7a, 0x01 }, +}; + +struct s5ka3dfx_reg s5ka3dfx_QVGA[] = { /* 320 x 240 */ + { 0xef, 0x00 }, + { 0x7a, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x15, 0x02 }, + { 0x16, 0x90 }, + { 0x13, 0x01 }, + { 0x14, 0xF0 }, + { 0x31, 0x04 }, + { 0x30, 0x06 }, + { 0x34, 0x02 }, + { 0x35, 0x88 }, + { 0x32, 0x01 }, + { 0x33, 0xE8 }, + { 0x7d, 0x02 }, + { 0x7e, 0x88 }, + { 0x7b, 0x01 }, + { 0x7c, 0xe8 }, + { 0x81, 0x01 }, + { 0x82, 0x48 }, + { 0x7f, 0x00 }, + { 0x80, 0xf8 }, + { 0xc3, 0x04 }, + { 0xc2, 0x04 }, + { 0xc6, 0x01 }, + { 0xc7, 0x40 }, + { 0xc4, 0x00 }, + { 0xc5, 0xf0 }, + { 0x7a, 0x03 }, +}; + + +struct s5ka3dfx_reg s5ka3dfx_QCIF[] = { /* 176 x 144 */ + { 0xef, 0x00 }, + { 0x7a, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x15, 0x02 }, + { 0x16, 0x90 }, + { 0x13, 0x01 }, + { 0x14, 0xF0 }, + { 0x31, 0x04 }, + { 0x30, 0x06 }, + { 0x34, 0x02 }, + { 0x35, 0x88 }, + { 0x32, 0x01 }, + { 0x33, 0xE8 }, + { 0x7d, 0x02 }, + { 0x7e, 0x88 }, + { 0x7b, 0x01 }, + { 0x7c, 0xe8 }, + { 0x81, 0x00 }, + { 0x82, 0xc0 }, + { 0x7f, 0x00 }, + { 0x80, 0x98 }, + { 0xc3, 0x08 }, + { 0xc2, 0x04 }, + { 0xc6, 0x00 }, + { 0xc7, 0xb0 }, + { 0xc4, 0x00 }, + { 0xc5, 0x90 }, + { 0x7a, 0x03 }, +}; +#endif diff --git a/drivers/media/video/samsung/Kconfig b/drivers/media/video/samsung/Kconfig new file mode 100644 index 0000000..15c0eb2 --- /dev/null +++ b/drivers/media/video/samsung/Kconfig @@ -0,0 +1,26 @@ +config VIDEO_SAMSUNG + bool "Samsung Multimedia Devices" + depends on VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2 + select VIDEO_FIXED_MINOR_RANGES + default n + ---help--- + This is a representative video4linux configuration for Samsung multimedia devices. + +config VIDEO_SAMSUNG_V4L2 + bool "V4L2 API for digital camera to be contributed by samsung" + depends on VIDEO_DEV && VIDEO_SAMSUNG + default n + ---help--- + This feature is for new V4L2 APIs all about digital camera + +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/tsi/Kconfig" +if CPU_S5PV210_EVT1 +#source "drivers/media/video/samsung/rotator/Kconfig" +#source "drivers/media/video/samsung/g2d/Kconfig" +endif +endif diff --git a/drivers/media/video/samsung/Makefile b/drivers/media/video/samsung/Makefile new file mode 100644 index 0000000..1f99c16 --- /dev/null +++ b/drivers/media/video/samsung/Makefile @@ -0,0 +1,10 @@ +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_G2D) += g2d/ +#obj-$(CONFIG_VIDEO_TSI) += tsi/ + +EXTRA_CFLAGS += -Idrivers/media/video + diff --git a/drivers/media/video/samsung/fimc/Kconfig b/drivers/media/video/samsung/fimc/Kconfig new file mode 100644 index 0000000..c9eae69 --- /dev/null +++ b/drivers/media/video/samsung/fimc/Kconfig @@ -0,0 +1,32 @@ +config VIDEO_FIMC + bool "Samsung Camera Interface (FIMC) driver" + depends on VIDEO_SAMSUNG && ARCH_S5PV210 + default n + help + This is a video4linux driver for Samsung FIMC device. + +choice +depends on VIDEO_FIMC +prompt "Select CSC Range config" +default VIDEO_FIMC_RANGE_NARROW +config VIDEO_FIMC_RANGE_NARROW + bool "Narrow" + depends on VIDEO_FIMC && ARCH_S5PV210 + ---help--- + RGB <-> YUV Color Conversion Narrow Range Equation + +config VIDEO_FIMC_RANGE_WIDE + bool "Wide" + depends on VIDEO_FIMC && ARCH_S5PV210 + ---help--- + RGB <-> YUV Color Conversion Wide Range Equation +endchoice + +config VIDEO_FIMC_DEBUG + bool "FIMC driver debug messages" + depends on VIDEO_FIMC + +config VIDEO_FIMC_MIPI + bool "MIPI-CSI2 Slave Interface support" + depends on VIDEO_FIMC && ARCH_S5PV210 + default y diff --git a/drivers/media/video/samsung/fimc/Makefile b/drivers/media/video/samsung/fimc/Makefile new file mode 100644 index 0000000..4f6e5c9 --- /dev/null +++ b/drivers/media/video/samsung/fimc/Makefile @@ -0,0 +1,12 @@ +obj-$(CONFIG_VIDEO_FIMC) += fimc_dev.o fimc_v4l2.o fimc_capture.o fimc_output.o fimc_overlay.o fimc_regs.o +obj-$(CONFIG_VIDEO_FIMC_MIPI) += csis.o + +ifeq ($(CONFIG_CPU_S5PV210),y) +EXTRA_CFLAGS += -DCONFIG_MIPI_CSI_ADV_FEATURE +endif + +EXTRA_CFLAGS += -Idrivers/media/video + +ifeq ($(CONFIG_VIDEO_FIMC_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/media/video/samsung/fimc/csis.c b/drivers/media/video/samsung/fimc/csis.c new file mode 100644 index 0000000..f512d10 --- /dev/null +++ b/drivers/media/video/samsung/fimc/csis.c @@ -0,0 +1,431 @@ +/* linux/drivers/media/video/samsung/csis.c + * + * Copyright (c) 2010 Samsung Electronics Co,. Ltd. + * http://www.samsung.com/ + * + * MIPI-CSI2 Support file for FIMC 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/errno.h> +#include <linux/clk.h> +#include <linux/fs.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/videodev2.h> +#include <linux/slab.h> + +#include <linux/io.h> +#include <linux/memory.h> +#include <plat/clock.h> +#include <plat/regs-csis.h> +#include <plat/csis.h> +#include "csis.h" + +static struct s3c_csis_info *s3c_csis; + +static struct s3c_platform_csis *to_csis_plat(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return (struct s3c_platform_csis *) pdev->dev.platform_data; +} + +static int s3c_csis_set_info(void) +{ + s3c_csis = (struct s3c_csis_info *) \ + kmalloc(sizeof(struct s3c_csis_info), GFP_KERNEL); + if (!s3c_csis) { + err("no memory for configuration\n"); + return -ENOMEM; + } + + strcpy(s3c_csis->name, S3C_CSIS_NAME); + s3c_csis->nr_lanes = S3C_CSIS_NR_LANES; + + return 0; +} + +static void s3c_csis_reset(void) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONTROL); + cfg |= S3C_CSIS_CONTROL_RESET; + writel(cfg, s3c_csis->regs + S3C_CSIS_CONTROL); +} + +static void s3c_csis_set_nr_lanes(int lanes) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONFIG); + cfg &= ~S3C_CSIS_CONFIG_NR_LANE_MASK; + + if (lanes == 1) + cfg |= S3C_CSIS_CONFIG_NR_LANE_1; + else + cfg |= S3C_CSIS_CONFIG_NR_LANE_2; + + writel(cfg, s3c_csis->regs + S3C_CSIS_CONFIG); +} + +static void s3c_csis_enable_interrupt(void) +{ + u32 cfg = 0; + + /* enable all interrupts */ + cfg |= S3C_CSIS_INTMSK_EVEN_BEFORE_ENABLE | \ + S3C_CSIS_INTMSK_EVEN_AFTER_ENABLE | \ + S3C_CSIS_INTMSK_ODD_BEFORE_ENABLE | \ + S3C_CSIS_INTMSK_ODD_AFTER_ENABLE | \ + S3C_CSIS_INTMSK_ERR_SOT_HS_ENABLE | \ + S3C_CSIS_INTMSK_ERR_ESC_ENABLE | \ + S3C_CSIS_INTMSK_ERR_CTRL_ENABLE | \ + S3C_CSIS_INTMSK_ERR_ECC_ENABLE | \ + S3C_CSIS_INTMSK_ERR_CRC_ENABLE | \ + S3C_CSIS_INTMSK_ERR_ID_ENABLE; + + writel(cfg, s3c_csis->regs + S3C_CSIS_INTMSK); +} + +static void s3c_csis_disable_interrupt(void) +{ + /* disable all interrupts */ + writel(0, s3c_csis->regs + S3C_CSIS_INTMSK); +} + +static void s3c_csis_system_on(void) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONTROL); + cfg |= S3C_CSIS_CONTROL_ENABLE; + writel(cfg, s3c_csis->regs + S3C_CSIS_CONTROL); +} + +static void s3c_csis_system_off(void) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONTROL); + cfg &= ~S3C_CSIS_CONTROL_ENABLE; + writel(cfg, s3c_csis->regs + S3C_CSIS_CONTROL); +} + +static void s3c_csis_phy_on(void) +{ + u32 cfg; + cfg = readl(s3c_csis->regs + S3C_CSIS_DPHYCTRL); + cfg |= S3C_CSIS_DPHYCTRL_ENABLE; + writel(cfg, s3c_csis->regs + S3C_CSIS_DPHYCTRL); +} + +static void s3c_csis_phy_off(void) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_DPHYCTRL); + cfg &= ~S3C_CSIS_DPHYCTRL_ENABLE; + writel(cfg, s3c_csis->regs + S3C_CSIS_DPHYCTRL); +} + +#ifdef CONFIG_MIPI_CSI_ADV_FEATURE +static void s3c_csis_update_shadow(void) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONTROL); + cfg |= S3C_CSIS_CONTROL_UPDATE_SHADOW; + writel(cfg, s3c_csis->regs + S3C_CSIS_CONTROL); +} + +static void s3c_csis_set_data_align(int align) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONTROL); + cfg &= ~S3C_CSIS_CONTROL_ALIGN_MASK; + + if (align == 24) + cfg |= S3C_CSIS_CONTROL_ALIGN_24BIT; + else + cfg |= S3C_CSIS_CONTROL_ALIGN_32BIT; + + writel(cfg, s3c_csis->regs + S3C_CSIS_CONTROL); +} + +static void s3c_csis_set_wclk(int extclk) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONTROL); + cfg &= ~S3C_CSIS_CONTROL_WCLK_MASK; + + if (extclk) + cfg |= S3C_CSIS_CONTROL_WCLK_EXTCLK; + else + cfg |= S3C_CSIS_CONTROL_WCLK_PCLK; + + writel(cfg, s3c_csis->regs + S3C_CSIS_CONTROL); +} + +static void s3c_csis_set_format(enum mipi_format fmt) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_CONFIG); + cfg &= ~S3C_CSIS_CONFIG_FORMAT_MASK; + cfg |= (fmt << S3C_CSIS_CONFIG_FORMAT_SHIFT); + + writel(cfg, s3c_csis->regs + S3C_CSIS_CONFIG); +} + +static void s3c_csis_set_resol(int width, int height) +{ + u32 cfg = 0; + + cfg |= width << S3C_CSIS_RESOL_HOR_SHIFT; + cfg |= height << S3C_CSIS_RESOL_VER_SHIFT; + + writel(cfg, s3c_csis->regs + S3C_CSIS_RESOL); +} + +static void s3c_csis_set_hs_settle(int settle) +{ + u32 cfg; + + cfg = readl(s3c_csis->regs + S3C_CSIS_DPHYCTRL); + cfg &= ~S3C_CSIS_DPHYCTRL_HS_SETTLE_MASK; + cfg |= (settle << S3C_CSIS_DPHYCTRL_HS_SETTLE_SHIFT); + + writel(cfg, s3c_csis->regs + S3C_CSIS_DPHYCTRL); +} +#endif + +void s3c_csis_start(int lanes, int settle, int align, int width, + int height, int pixel_format) +{ + struct platform_device *pdev = to_platform_device(s3c_csis->dev); + struct s3c_platform_csis *pdata; + + pdata = to_csis_plat(s3c_csis->dev); + if (pdata->cfg_phy_global) + pdata->cfg_phy_global(pdev, 1); + + s3c_csis_reset(); + s3c_csis_set_nr_lanes(lanes); + +#ifdef CONFIG_MIPI_CSI_ADV_FEATURE + /* FIXME: how configure the followings with FIMC dynamically? */ + s3c_csis_set_hs_settle(settle); /* s5k6aa */ + s3c_csis_set_data_align(align); + s3c_csis_set_wclk(0); + if (pixel_format == V4L2_PIX_FMT_JPEG) + s3c_csis_set_format(MIPI_USER_DEF_PACKET_1); + else + s3c_csis_set_format(MIPI_CSI_YCBCR422_8BIT); + s3c_csis_set_resol(width, height); + s3c_csis_update_shadow(); +#endif + + s3c_csis_enable_interrupt(); + s3c_csis_system_on(); + s3c_csis_phy_on(); + + info("Samsung MIPI-CSI2 operation started\n"); +} + +static void s3c_csis_stop(struct platform_device *pdev) +{ + struct s3c_platform_csis *plat; + + s3c_csis_disable_interrupt(); + s3c_csis_system_off(); + s3c_csis_phy_off(); + + plat = to_csis_plat(&pdev->dev); + if (plat->cfg_phy_global) + plat->cfg_phy_global(pdev, 0); +} + +static irqreturn_t s3c_csis_irq(int irq, void *dev_id) +{ + u32 cfg; + + /* just clearing the pends */ + cfg = readl(s3c_csis->regs + S3C_CSIS_INTSRC); + writel(cfg, s3c_csis->regs + S3C_CSIS_INTSRC); + + return IRQ_HANDLED; +} + +static int s3c_csis_clk_on(struct platform_device *pdev) +{ + struct s3c_platform_csis *pdata; + struct clk *parent, *mout_csis; + + pdata = to_csis_plat(&pdev->dev); + + /* mout_mpll */ + parent = clk_get(&pdev->dev, pdata->srclk_name); + if (IS_ERR(parent)) { + err("failed to get parent clock for csis\n"); + return -EINVAL; + } + + /* mout_csis */ + mout_csis = clk_get(&pdev->dev, "mout_csis"); + + /* sclk_csis */ + s3c_csis->clock = clk_get(&pdev->dev, pdata->clk_name); + if (IS_ERR(s3c_csis->clock)) { + err("failed to get csis clock source\n"); + return -EINVAL; + } + + clk_set_parent(mout_csis, parent); + clk_set_parent(s3c_csis->clock, mout_csis); + + /* Turn on csis power domain regulator */ + regulator_enable(s3c_csis->regulator); + /* clock enable for csis */ + clk_enable(s3c_csis->clock); + + return 0; +} + +static int s3c_csis_clk_off(struct platform_device *pdev) +{ + struct s3c_platform_csis *plat; + + plat = to_csis_plat(&pdev->dev); + + /* sclk_csis */ + s3c_csis->clock = clk_get(&pdev->dev, plat->clk_name); + if (IS_ERR(s3c_csis->clock)) { + err("failed to get csis clock source\n"); + return -EINVAL; + } + + /* clock disable for csis */ + clk_disable(s3c_csis->clock); + /* Turn off csis power domain regulator */ + regulator_disable(s3c_csis->regulator); + + return 0; +} + +static int s3c_csis_probe(struct platform_device *pdev) +{ + struct s3c_platform_csis *pdata; + struct resource *res; + + s3c_csis_set_info(); + + s3c_csis->dev = &pdev->dev; + + pdata = to_csis_plat(&pdev->dev); + if (pdata->cfg_gpio) + pdata->cfg_gpio(); + + /* Get csis power domain regulator */ + s3c_csis->regulator = regulator_get(&pdev->dev, "pd"); + if (IS_ERR(s3c_csis->regulator)) { + err("%s: failed to get resource %s\n", + __func__, "s3c-csis"); + return PTR_ERR(s3c_csis->regulator); + } + /* clock & power on */ + s3c_csis_clk_on(pdev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err("failed to get io memory region\n"); + return -EINVAL; + } + + res = request_mem_region(res->start, + res->end - res->start + 1, pdev->name); + if (!res) { + err("failed to request io memory region\n"); + return -EINVAL; + } + + /* ioremap for register block */ + s3c_csis->regs = ioremap(res->start, res->end - res->start + 1); + if (!s3c_csis->regs) { + err("failed to remap io region\n"); + return -EINVAL; + } + + /* irq */ + s3c_csis->irq = platform_get_irq(pdev, 0); + if (request_irq(s3c_csis->irq, s3c_csis_irq, IRQF_DISABLED, \ + s3c_csis->name, s3c_csis)) + err("request_irq failed\n"); + + info("Samsung MIPI-CSI2 driver probed successfully\n"); + + return 0; +} + +static int s3c_csis_remove(struct platform_device *pdev) +{ + s3c_csis_stop(pdev); + kfree(s3c_csis); + + return 0; +} + +/* sleep */ +int s3c_csis_suspend(struct platform_device *pdev, pm_message_t state) +{ + s3c_csis_clk_off(pdev); + return 0; +} + +/* wakeup */ +int s3c_csis_resume(struct platform_device *pdev) +{ + s3c_csis_clk_on(pdev); + return 0; +} + +static struct platform_driver s3c_csis_driver = { + .probe = s3c_csis_probe, + .remove = s3c_csis_remove, + .suspend = s3c_csis_suspend, + .resume = s3c_csis_resume, + .driver = { + .name = "s5p-mipi-csis", + .owner = THIS_MODULE, + }, +}; + +static int s3c_csis_register(void) +{ + platform_driver_register(&s3c_csis_driver); + + return 0; +} + +static void s3c_csis_unregister(void) +{ + platform_driver_unregister(&s3c_csis_driver); +} + +module_init(s3c_csis_register); +module_exit(s3c_csis_unregister); + +MODULE_AUTHOR("Jinsung, Yang <jsgood.yang@samsung.com>"); +MODULE_AUTHOR("Sewoon, Park <seuni.park@samsung.com>"); +MODULE_DESCRIPTION("MIPI-CSI2 support for FIMC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/samsung/fimc/csis.h b/drivers/media/video/samsung/fimc/csis.h new file mode 100644 index 0000000..4943c8f --- /dev/null +++ b/drivers/media/video/samsung/fimc/csis.h @@ -0,0 +1,42 @@ +/* linux/drivers/media/video/samsung/csis.h + * + * Copyright (c) 2010 Samsung Electronics Co,. Ltd. + * http://www.samsung.com/ + * + * Header file for Samsung MIPI-CSI2 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. +*/ + +#ifndef __CSIS_H +#define __CSIS_H __FILE__ + +#define S3C_CSIS_NAME "s5p-mipi-csis" +#define S3C_CSIS_NR_LANES 1 + +#define info(args...) \ + do { printk(KERN_INFO S3C_CSIS_NAME ": " args); } while (0) +#define err(args...) \ + do { printk(KERN_ERR S3C_CSIS_NAME ": " args); } while (0) + +enum mipi_format { + MIPI_CSI_YCBCR422_8BIT = 0x1e, + MIPI_CSI_RAW8 = 0x2a, + MIPI_CSI_RAW10 = 0x2b, + MIPI_CSI_RAW12 = 0x2c, + MIPI_USER_DEF_PACKET_1 = 0x30, /* User defined Byte-based packet 1 */ +}; + +struct s3c_csis_info { + char name[16]; + struct device *dev; + struct clk *clock; + struct regulator *regulator; + void __iomem *regs; + int irq; + int nr_lanes; +}; + +#endif /* __CSIS_H */ diff --git a/drivers/media/video/samsung/fimc/fimc.h b/drivers/media/video/samsung/fimc/fimc.h new file mode 100644 index 0000000..e261382 --- /dev/null +++ b/drivers/media/video/samsung/fimc/fimc.h @@ -0,0 +1,707 @@ +/* linux/drivers/media/video/samsung/fimc/fimc.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Header file for Samsung Camera Interface (FIMC) 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. +*/ + + +#ifndef __FIMC_H +#define __FIMC_H __FILE__ + +#ifdef __KERNEL__ +#include <linux/wait.h> +#include <linux/mutex.h> +#include <linux/i2c.h> +#include <linux/fb.h> +#include <linux/videodev2.h> +#include <linux/platform_device.h> +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf-core.h> +#include <plat/media.h> +#include <plat/fimc.h> +#endif + +#define FIMC_NAME "s3c-fimc" + +#define FIMC_DEVICES 3 +#define FIMC_SUBDEVS 3 +#define FIMC_MAXCAMS 5 /* added 1 because of WriteBack */ +#define FIMC_PHYBUFS 4 +#define FIMC_OUTBUFS 3 +#define FIMC_INQUEUES 10 +#define FIMC_MAX_CTXS 1 +#define FIMC_TPID 3 +#define FIMC_CAPBUFS 16 +#define FIMC_ONESHOT_TIMEOUT 200 +#define FIMC_DQUEUE_TIMEOUT 200 +#define FIMC_FIFOOFF_CNT 1000000 /* Sufficiently big value for stop */ + +#define FORMAT_FLAGS_PACKED 0x1 +#define FORMAT_FLAGS_PLANAR 0x2 +#define FORMAT_FLAGS_ENCODED 0x3 + +#define FIMC_ADDR_Y 0 +#define FIMC_ADDR_CB 1 +#define FIMC_ADDR_CR 2 + +#define FIMC_HD_WIDTH 1280 +#define FIMC_HD_HEIGHT 720 + +#define FIMC_FHD_WIDTH 1920 +#define FIMC_FHD_HEIGHT 1080 + +#define FIMC_MMAP_IDX -1 +#define FIMC_USERPTR_IDX -2 + +#define FIMC_HCLK 0 +#define FIMC_SCLK 1 +#define FIMC_OVLY_MODE FIMC_OVLY_DMA_AUTO + +#define FIMC_PINGPONG 2 + +/* + * ENUMERATIONS +*/ +enum fimc_status { + FIMC_READY_OFF = 0x00, + FIMC_STREAMOFF = 0x01, + FIMC_READY_ON = 0x02, + FIMC_STREAMON = 0x03, + FIMC_STREAMON_IDLE = 0x04, /* oneshot mode */ + FIMC_OFF_SLEEP = 0x05, + FIMC_ON_SLEEP = 0x06, + FIMC_ON_IDLE_SLEEP = 0x07, /* oneshot mode */ + FIMC_READY_RESUME = 0x08, +}; + +enum fimc_fifo_state { + FIFO_CLOSE, + FIFO_SLEEP, +}; + +enum fimc_fimd_state { + FIMD_OFF, + FIMD_ON, +}; + +enum fimc_rot_flip { + FIMC_XFLIP = 0x01, + FIMC_YFLIP = 0x02, + FIMC_ROT = 0x10, +}; + +enum fimc_input { + FIMC_SRC_CAM, + FIMC_SRC_MSDMA, +}; + +enum fimc_overlay_mode { + /* Overlay mode isn't fixed. */ + FIMC_OVLY_NOT_FIXED = 0x0, + /* Non-destructive Overlay with DMA */ + FIMC_OVLY_DMA_AUTO = 0x1, + /* Non-destructive Overlay with DMA */ + FIMC_OVLY_DMA_MANUAL = 0x2, + /* Destructive Overlay with DMA single destination buffer */ + FIMC_OVLY_NONE_SINGLE_BUF = 0x3, + /* Destructive Overlay with DMA multiple dstination buffer */ + FIMC_OVLY_NONE_MULTI_BUF = 0x4, +}; + +enum fimc_autoload { + FIMC_AUTO_LOAD, + FIMC_ONE_SHOT, +}; + +enum fimc_log { + FIMC_LOG_DEBUG = 0x1000, + FIMC_LOG_INFO_L2 = 0x0200, + FIMC_LOG_INFO_L1 = 0x0100, + FIMC_LOG_WARN = 0x0010, + FIMC_LOG_ERR = 0x0001, +}; + +enum fimc_pixel_format_type{ + FIMC_RGB, + FIMC_YUV420, + FIMC_YUV422, + FIMC_YUV444, +}; + +/* + * STRUCTURES +*/ + +/* for reserved memory */ +struct fimc_meminfo { + dma_addr_t base; /* buffer base */ + size_t size; /* total length */ + dma_addr_t curr; /* current addr */ +}; + +struct fimc_buf { + dma_addr_t base[3]; + size_t length[3]; +}; + +struct fimc_overlay_buf { + u32 vir_addr[3]; + size_t size[3]; + u32 phy_addr[3]; +}; + +struct fimc_overlay { + enum fimc_overlay_mode mode; + struct fimc_overlay_buf buf; + s32 req_idx; + int fb_id; +}; + +/* general buffer */ +struct fimc_buf_set { + int id; + /* Plane 0/1/2 for raw data, Plane 3 for padding buffer (if required) */ + dma_addr_t base[4]; + size_t length[4]; + size_t garbage[4]; + enum videobuf_state state; + u32 flags; + atomic_t mapped_cnt; + struct list_head list; +}; + +/* for capture device */ +struct fimc_capinfo { + struct v4l2_cropcap cropcap; + struct v4l2_rect crop; + struct v4l2_pix_format fmt; + struct fimc_buf_set bufs[FIMC_CAPBUFS]; + struct list_head inq; + int outq[FIMC_PHYBUFS]; + int nr_bufs; + int irq; + int lastirq; + + /* flip: V4L2_CID_xFLIP, rotate: 90, 180, 270 */ + u32 flip; + u32 rotate; +}; + +/* for output overlay device */ +struct fimc_idx { + int ctx; + int idx; +}; + +struct fimc_ctx_idx { + struct fimc_idx prev; + struct fimc_idx active; + struct fimc_idx next; +}; + +/* scaler abstraction: local use recommended */ +struct fimc_scaler { + u32 bypass; + u32 hfactor; + u32 vfactor; + u32 pre_hratio; + u32 pre_vratio; + u32 pre_dst_width; + u32 pre_dst_height; + u32 scaleup_h; + u32 scaleup_v; + u32 main_hratio; + u32 main_vratio; + u32 real_width; + u32 real_height; + u32 shfactor; + u32 skipline; +}; + +struct fimc_ctx { + u32 ctx_num; + struct v4l2_cropcap cropcap; + struct v4l2_rect crop; + struct v4l2_pix_format pix; + struct v4l2_window win; + struct v4l2_framebuffer fbuf; + struct fimc_scaler sc; + struct fimc_overlay overlay; + + u32 buf_num; + u32 is_requested; + struct fimc_buf_set src[FIMC_OUTBUFS]; + struct fimc_buf_set dst[FIMC_OUTBUFS]; + s32 inq[FIMC_OUTBUFS]; + s32 outq[FIMC_OUTBUFS]; + + u32 flip; + u32 rotate; + enum fimc_status status; +}; + +struct fimc_outinfo { + int last_ctx; + spinlock_t lock_in; + spinlock_t lock_out; + struct fimc_idx inq[FIMC_INQUEUES]; + struct fimc_ctx ctx[FIMC_MAX_CTXS]; + struct fimc_ctx_idx idxs; +}; + +struct s3cfb_user_window { + int x; + int y; +}; + +enum s3cfb_data_path_t { + DATA_PATH_FIFO = 0, + DATA_PATH_DMA = 1, + DATA_PATH_IPC = 2, +}; + +enum s3cfb_mem_owner_t { + DMA_MEM_NONE = 0, + DMA_MEM_FIMD = 1, + DMA_MEM_OTHER = 2, +}; + +enum s3cfb_alpha_t { + PLANE_BLENDING, + PIXEL_BLENDING, +}; + +enum s3cfb_chroma_dir_t { + CHROMA_FG, + CHROMA_BG, +}; + +struct s3cfb_alpha { + enum s3cfb_alpha_t mode; + int channel; + unsigned int value; +}; + + +struct s3cfb_chroma { + int enabled; + int blended; + unsigned int key; + unsigned int comp_key; + unsigned int alpha; + enum s3cfb_chroma_dir_t dir; +}; + +struct s3cfb_window { + int id; + int enabled; + atomic_t in_use; + int x; + int y; + enum s3cfb_data_path_t path; + enum s3cfb_mem_owner_t owner; + unsigned int other_mem_addr; + unsigned int other_mem_size; + int local_channel; + int dma_burst; + unsigned int pseudo_pal[16]; + struct s3cfb_alpha alpha; + struct s3cfb_chroma chroma; +}; + +#define S3CFB_WIN_OFF_ALL _IO('F', 202) +#define S3CFB_WIN_POSITION _IOW('F', 203, struct s3cfb_user_window) +#define S3CFB_GET_LCD_WIDTH _IOR('F', 302, int) +#define S3CFB_GET_LCD_HEIGHT _IOR('F', 303, int) +#define S3CFB_SET_WRITEBACK _IOW('F', 304, u32) +#define S3CFB_SET_WIN_ON _IOW('F', 306, u32) +#define S3CFB_SET_WIN_OFF _IOW('F', 307, u32) +#define S3CFB_SET_WIN_PATH _IOW('F', 308, enum s3cfb_data_path_t) +#define S3CFB_SET_WIN_ADDR _IOW('F', 309, unsigned long) +#define S3CFB_SET_WIN_MEM _IOW('F', 310, enum s3cfb_mem_owner_t) +/* ------------------------------------------------------------------------ */ + +struct fimc_fbinfo { + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + int lcd_hres; + int lcd_vres; + u32 is_enable; +}; + +struct fimc_limit { + u32 pre_dst_w; + u32 bypass_w; + u32 trg_h_no_rot; + u32 trg_h_rot; + u32 real_w_no_rot; + u32 real_h_rot; +}; + +enum FIMC_EFFECT_FIN { + FIMC_EFFECT_FIN_BYPASS = 0, + FIMC_EFFECT_FIN_ARBITRARY_CBCR, + FIMC_EFFECT_FIN_NEGATIVE, + FIMC_EFFECT_FIN_ART_FREEZE, + FIMC_EFFECT_FIN_EMBOSSING, + FIMC_EFFECT_FIN_SILHOUETTE, +}; + + +struct fimc_effect { + int ie_on; + int ie_after_sc; + enum FIMC_EFFECT_FIN fin; + int pat_cb; + int pat_cr; +}; + +/* fimc controller abstration */ +struct fimc_control { + int id; /* controller id */ + char name[16]; + atomic_t in_use; + void __iomem *regs; /* register i/o */ + struct clk *clk; /* interface clock */ + struct regulator *regulator; /* pd regulator */ + struct fimc_meminfo mem; /* for reserved mem */ + + /* kernel helpers */ + struct mutex lock; /* controller lock */ + struct mutex alloc_lock; + struct mutex v4l2_lock; + wait_queue_head_t wq; + struct device *dev; + int irq; + + /* v4l2 related */ + struct video_device *vd; + struct v4l2_device v4l2_dev; + + /* fimc specific */ + struct fimc_limit *limit; /* H/W limitation */ + struct s3c_platform_camera *cam; /* activated camera */ + struct fimc_capinfo *cap; /* capture dev info */ + struct fimc_outinfo *out; /* output dev info */ + struct fimc_fbinfo fb; /* fimd info */ + struct fimc_scaler sc; /* scaler info */ + struct fimc_effect fe; /* fimc effect info */ + + enum fimc_status status; + enum fimc_log log; + + u32 ctx_busy[FIMC_MAX_CTXS]; +}; + +/* global */ +struct fimc_global { + struct fimc_control ctrl[FIMC_DEVICES]; + struct s3c_platform_camera camera[FIMC_MAXCAMS]; + int camera_isvalid[FIMC_MAXCAMS]; + int active_camera; + int initialized; +}; + +struct fimc_prv_data { + struct fimc_control *ctrl; + int ctx_id; +}; + +/* debug macro */ +#define FIMC_LOG_DEFAULT (FIMC_LOG_WARN | FIMC_LOG_ERR) + +#define FIMC_DEBUG(fmt, ...) \ + do { \ + if (ctrl->log & FIMC_LOG_DEBUG) \ + printk(KERN_DEBUG FIMC_NAME "-%d : " \ + fmt, ctrl->id, ##__VA_ARGS__); \ + } while (0) + +#define FIMC_INFO_L2(fmt, ...) \ + do { \ + if (ctrl->log & FIMC_LOG_INFO_L2) \ + printk(KERN_INFO FIMC_NAME "-%d : " \ + fmt, ctrl->id, ##__VA_ARGS__); \ + } while (0) + +#define FIMC_INFO_L1(fmt, ...) \ + do { \ + if (ctrl->log & FIMC_LOG_INFO_L1) \ + printk(KERN_INFO FIMC_NAME "-%d : " \ + fmt, ctrl->id, ##__VA_ARGS__); \ + } while (0) + +#define FIMC_WARN(fmt, ...) \ + do { \ + if (ctrl->log & FIMC_LOG_WARN) \ + printk(KERN_WARNING FIMC_NAME "-%d : " \ + fmt, ctrl->id, ##__VA_ARGS__); \ + } while (0) + + +#define FIMC_ERROR(fmt, ...) \ + do { \ + if (ctrl->log & FIMC_LOG_ERR) \ + printk(KERN_ERR FIMC_NAME "-%d : " \ + fmt, ctrl->id, ##__VA_ARGS__); \ + } while (0) + + +#define fimc_dbg(fmt, ...) FIMC_DEBUG(fmt, ##__VA_ARGS__) +#define fimc_info2(fmt, ...) FIMC_INFO_L2(fmt, ##__VA_ARGS__) +#define fimc_info1(fmt, ...) FIMC_INFO_L1(fmt, ##__VA_ARGS__) +#define fimc_warn(fmt, ...) FIMC_WARN(fmt, ##__VA_ARGS__) +#define fimc_err(fmt, ...) FIMC_ERROR(fmt, ##__VA_ARGS__) + +/* + * EXTERNS +*/ +extern struct fimc_global *fimc_dev; +extern struct video_device fimc_video_device[FIMC_DEVICES]; +extern const struct v4l2_ioctl_ops fimc_v4l2_ops; +extern struct fimc_limit fimc40_limits[FIMC_DEVICES]; +extern struct fimc_limit fimc43_limits[FIMC_DEVICES]; +extern struct fimc_limit fimc50_limits[FIMC_DEVICES]; + +/* general */ +extern void s3c_csis_start(int lanes, int settle, int align, + int width, int height, + int pixel_format); +extern int fimc_dma_alloc(struct fimc_control *ctrl, + struct fimc_buf_set *bs, + int i, int align); +extern void fimc_dma_free(struct fimc_control *ctrl, + struct fimc_buf_set *bs, int i); +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 rotate); +extern void fimc_clk_en(struct fimc_control *ctrl, bool on); + +/* camera */ +extern int fimc_select_camera(struct fimc_control *ctrl); + +/* capture device */ +extern int fimc_enum_input(struct file *file, void *fh, + struct v4l2_input *inp); +extern int fimc_g_input(struct file *file, void *fh, unsigned int *i); +extern int fimc_s_input(struct file *file, void *fh, unsigned int i); +extern int fimc_enum_fmt_vid_capture(struct file *file, void *fh, + struct v4l2_fmtdesc *f); +extern int fimc_g_fmt_vid_capture(struct file *file, void *fh, + struct v4l2_format *f); +extern int fimc_s_fmt_vid_capture(struct file *file, void *fh, + struct v4l2_format *f); +extern int fimc_try_fmt_vid_capture(struct file *file, void *fh, + struct v4l2_format *f); +extern int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b); +extern int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b); +extern int fimc_g_ctrl_capture(void *fh, struct v4l2_control *c); +extern int fimc_s_ctrl_capture(void *fh, struct v4l2_control *c); +extern int fimc_s_ext_ctrls_capture(void *fh, struct v4l2_ext_controls *c); +extern int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a); +extern int fimc_g_crop_capture(void *fh, struct v4l2_crop *a); +extern int fimc_s_crop_capture(void *fh, struct v4l2_crop *a); +extern int fimc_streamon_capture(void *fh); +extern int fimc_streamoff_capture(void *fh); +extern int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b); +extern int fimc_dqbuf_capture(void *fh, struct v4l2_buffer *b); +extern int fimc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *a); +extern int fimc_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *a); +extern int fimc_queryctrl(struct file *file, void *fh, + struct v4l2_queryctrl *qc); +extern int fimc_querymenu(struct file *file, void *fh, + struct v4l2_querymenu *qm); + +#if defined(CONFIG_CPU_S5PV210) +extern int fimc_change_clksrc(struct fimc_control *ctrl, int fimc_clk); +#endif +extern int fimc_release_subdev(struct fimc_control *ctrl); + +/* output device */ +extern void fimc_outdev_set_src_addr(struct fimc_control *ctrl, + dma_addr_t *base); +extern int fimc_outdev_set_ctx_param(struct fimc_control *ctrl, + struct fimc_ctx *ctx); +extern int fimc_start_fifo(struct fimc_control *ctrl, + struct fimc_ctx *ctx); +extern int fimc_fimd_rect(const struct fimc_control *ctrl, + const struct fimc_ctx *ctx, + struct v4l2_rect *fimd_rect); +extern int fimc_outdev_stop_streaming(struct fimc_control *ctrl, + struct fimc_ctx *ctx); +extern int fimc_outdev_resume_dma(struct fimc_control *ctrl, + struct fimc_ctx *ctx); +extern int fimc_outdev_start_camif(void *param); +extern int fimc_reqbufs_output(void *fh, struct v4l2_requestbuffers *b); +extern int fimc_querybuf_output(void *fh, struct v4l2_buffer *b); +extern int fimc_g_ctrl_output(void *fh, struct v4l2_control *c); +extern int fimc_s_ctrl_output(struct file *filp, void *fh, + struct v4l2_control *c); +extern int fimc_cropcap_output(void *fh, struct v4l2_cropcap *a); +extern int fimc_g_crop_output(void *fh, struct v4l2_crop *a); +extern int fimc_s_crop_output(void *fh, struct v4l2_crop *a); +extern int fimc_streamon_output(void *fh); +extern int fimc_streamoff_output(void *fh); +extern int fimc_qbuf_output(void *fh, struct v4l2_buffer *b); +extern int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b); +extern int fimc_g_fmt_vid_out(struct file *filp, void *fh, + struct v4l2_format *f); +extern int fimc_s_fmt_vid_out(struct file *filp, void *fh, + struct v4l2_format *f); +extern int fimc_try_fmt_vid_out(struct file *filp, void *fh, + struct v4l2_format *f); +extern int fimc_output_set_dst_addr(struct fimc_control *ctrl, + struct fimc_ctx *ctx, int idx); +extern int fimc_init_in_queue(struct fimc_control *ctrl, struct fimc_ctx *ctx); +extern int fimc_push_inq(struct fimc_control *ctrl, + struct fimc_ctx *ctx, int idx); +extern int fimc_pop_inq(struct fimc_control *ctrl, int *ctx_num, int *idx); +extern int fimc_push_outq(struct fimc_control *ctrl, + struct fimc_ctx *ctx, int idx); +extern int fimc_pop_outq(struct fimc_control *ctrl, + struct fimc_ctx *ctx, int *idx); +extern int fimc_init_out_queue(struct fimc_control *ctrl, struct fimc_ctx *ctx); +extern void fimc_outdev_init_idxs(struct fimc_control *ctrl); + +extern void fimc_dump_context(struct fimc_control *ctrl, struct fimc_ctx *ctx); +extern void fimc_print_signal(struct fimc_control *ctrl); + +/* overlay device */ +extern int fimc_try_fmt_overlay(struct file *filp, void *fh, + struct v4l2_format *f); +extern int fimc_g_fmt_vid_overlay(struct file *filp, void *fh, + struct v4l2_format *f); +extern int fimc_s_fmt_vid_overlay(struct file *filp, void *fh, + struct v4l2_format *f); +extern int fimc_g_fbuf(struct file *filp, void *fh, + struct v4l2_framebuffer *fb); +extern int fimc_s_fbuf(struct file *filp, void *fh, + struct v4l2_framebuffer *fb); + +/* Register access file */ +extern void fimc_reset(struct fimc_control *ctrl); +extern int fimc_hwset_camera_source(struct fimc_control *ctrl); +extern int fimc_hwset_enable_irq(struct fimc_control *ctrl, + int overflow, int level); +extern int fimc_hwset_disable_irq(struct fimc_control *ctrl); +extern int fimc_hwset_clear_irq(struct fimc_control *ctrl); +extern int fimc_hwset_reset(struct fimc_control *ctrl); +extern int fimc_hwset_sw_reset(struct fimc_control *ctrl); +extern int fimc_hwset_clksrc(struct fimc_control *ctrl, int src_clk); +extern int fimc_hwget_overflow_state(struct fimc_control *ctrl); +extern int fimc_hwset_camera_offset(struct fimc_control *ctrl); +extern int fimc_hwset_camera_polarity(struct fimc_control *ctrl); +extern int fimc_hwset_camera_type(struct fimc_control *ctrl); +extern int fimc_hwset_output_size(struct fimc_control *ctrl, + int width, int height); +extern int fimc_hwset_output_colorspace(struct fimc_control *ctrl, + u32 pixelformat); +extern int fimc_hwset_output_rot_flip(struct fimc_control *ctrl, + u32 rot, u32 flip); +extern int fimc_hwset_output_area(struct fimc_control *ctrl, + u32 width, u32 height); +extern int fimc_hwset_output_area_size(struct fimc_control *ctrl, u32 size); +extern int fimc_hwset_output_scan(struct fimc_control *ctrl, + struct v4l2_pix_format *fmt); +extern int fimc_hwset_enable_lastirq(struct fimc_control *ctrl); +extern int fimc_hwset_disable_lastirq(struct fimc_control *ctrl); +extern int fimc_hwset_prescaler(struct fimc_control *ctrl, + struct fimc_scaler *sc); +extern int fimc_hwset_output_yuv(struct fimc_control *ctrl, u32 pixelformat); +extern int fimc_hwset_output_address(struct fimc_control *ctrl, + struct fimc_buf_set *bs, + int id); +extern int fimc_hwset_input_rot(struct fimc_control *ctrl, u32 rot, u32 flip); +extern int fimc_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc); +extern int fimc_hwset_scaler_bypass(struct fimc_control *ctrl); +extern int fimc_hwset_enable_lcdfifo(struct fimc_control *ctrl); +extern int fimc_hwset_disable_lcdfifo(struct fimc_control *ctrl); +extern int fimc_hwset_start_scaler(struct fimc_control *ctrl); +extern int fimc_hwset_stop_scaler(struct fimc_control *ctrl); +extern int fimc_hwset_input_rgb(struct fimc_control *ctrl, u32 pixelformat); +extern int fimc_hwset_intput_field(struct fimc_control *ctrl, + enum v4l2_field field); +extern int fimc_hwset_output_rgb(struct fimc_control *ctrl, u32 pixelformat); +extern int fimc_hwset_ext_rgb(struct fimc_control *ctrl, int enable); +extern int fimc_hwset_enable_capture(struct fimc_control *ctrl, + u32 bypass); +extern int fimc_hwset_disable_capture(struct fimc_control *ctrl); +extern void fimc_wait_disable_capture(struct fimc_control *ctrl); +extern int fimc_hwset_input_address(struct fimc_control *ctrl, + dma_addr_t *base); +extern int fimc_hwset_enable_autoload(struct fimc_control *ctrl); +extern int fimc_hwset_disable_autoload(struct fimc_control *ctrl); +extern int fimc_hwset_real_input_size(struct fimc_control *ctrl, + u32 width, u32 height); +extern int fimc_hwset_addr_change_enable(struct fimc_control *ctrl); +extern int fimc_hwset_addr_change_disable(struct fimc_control *ctrl); +extern int fimc_hwset_input_burst_cnt(struct fimc_control *ctrl, u32 cnt); +extern int fimc_hwset_input_colorspace(struct fimc_control *ctrl, + u32 pixelformat); +extern int fimc_hwset_input_yuv(struct fimc_control *ctrl, u32 pixelformat); +extern int fimc_hwset_input_flip(struct fimc_control *ctrl, u32 rot, u32 flip); +extern int fimc_hwset_input_source(struct fimc_control *ctrl, + enum fimc_input path); +extern int fimc_hwset_start_input_dma(struct fimc_control *ctrl); +extern int fimc_hwset_stop_input_dma(struct fimc_control *ctrl); +extern int fimc_hwset_output_offset(struct fimc_control *ctrl, + u32 pixelformat, + struct v4l2_rect *bound, + struct v4l2_rect *crop); +extern int fimc_hwset_input_offset(struct fimc_control *ctrl, + u32 pixelformat, + struct v4l2_rect *bound, + struct v4l2_rect *crop); +extern int fimc_hwset_org_input_size(struct fimc_control *ctrl, + u32 width, u32 height); +extern int fimc_hwset_org_output_size(struct fimc_control *ctrl, + u32 width, u32 height); +extern int fimc_hwset_ext_output_size(struct fimc_control *ctrl, + u32 width, u32 height); +extern int fimc_hwset_input_addr_style(struct fimc_control *ctrl, + u32 pixelformat); +extern int fimc_hwset_output_addr_style(struct fimc_control *ctrl, + u32 pixelformat); +extern int fimc_hwset_jpeg_mode(struct fimc_control *ctrl, bool enable); +extern int fimc_hwget_frame_count(struct fimc_control *ctrl); +extern int fimc_hw_wait_winoff(struct fimc_control *ctrl); +extern int fimc_hw_wait_stop_input_dma(struct fimc_control *ctrl); +extern int fimc_hwset_input_lineskip(struct fimc_control *ctrl); +extern int fimc_hw_reset_camera(struct fimc_control *ctrl); +extern void fimc_hwset_stop_processing(struct fimc_control *ctrl); +extern int fimc_hwset_image_effect(struct fimc_control *ctrl); +extern int fimc_hwset_shadow_enable(struct fimc_control *ctrl); +extern int fimc_hwset_shadow_disable(struct fimc_control *ctrl); +extern void fimc_save_regs(struct fimc_control *ctrl); +extern void fimc_load_regs(struct fimc_control *ctrl); +extern void fimc_dump_regs(struct fimc_control *ctrl); + +/* + * D R I V E R H E L P E R S + * +*/ +#define to_fimc_plat(d) (to_platform_device(d)->dev.platform_data) + +static inline struct fimc_global *get_fimc_dev(void) +{ + return fimc_dev; +} + +static inline struct fimc_control *get_fimc_ctrl(int id) +{ + return &fimc_dev->ctrl[id]; +} + +#endif /* _FIMC_H */ + diff --git a/drivers/media/video/samsung/fimc/fimc_capture.c b/drivers/media/video/samsung/fimc/fimc_capture.c new file mode 100644 index 0000000..6b4fd85 --- /dev/null +++ b/drivers/media/video/samsung/fimc/fimc_capture.c @@ -0,0 +1,1794 @@ +/* linux/drivers/media/video/samsung/fimc/fimc_capture.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * V4L2 Capture device support file for Samsung Camera Interface (FIMC) 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/slab.h> +#include <linux/bootmem.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/videodev2.h> +#include <linux/videodev2_samsung.h> +#include <linux/clk.h> +#include <linux/mm.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <plat/media.h> +#include <plat/clock.h> +#include <plat/fimc.h> +#include <linux/delay.h> + +#include "fimc.h" + +/* subdev handling macro */ +#define subdev_call(ctrl, o, f, args...) \ + v4l2_subdev_call(ctrl->cam->sd, o, f, ##args) + +/* #define FIMC_CAP_DEBUG */ + +#ifdef FIMC_CAP_DEBUG +#ifdef fimc_dbg +#undef fimc_dbg +#endif +#define fimc_dbg fimc_err +#endif + +static int vtmode = 0; +static int device_id = 0; + +static const struct v4l2_fmtdesc capture_fmts[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PACKED, + .description = "RGB-5-6-5", + .pixelformat = V4L2_PIX_FMT_RGB565, + }, { + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PACKED, + .description = "RGB-8-8-8, unpacked 24 bpp", + .pixelformat = V4L2_PIX_FMT_RGB32, + }, { + .index = 2, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PACKED, + .description = "YUV 4:2:2 packed, YCbYCr", + .pixelformat = V4L2_PIX_FMT_YUYV, + }, { + .index = 3, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PACKED, + .description = "YUV 4:2:2 packed, CbYCrY", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, { + .index = 4, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PACKED, + .description = "YUV 4:2:2 packed, CrYCbY", + .pixelformat = V4L2_PIX_FMT_VYUY, + }, { + .index = 5, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PACKED, + .description = "YUV 4:2:2 packed, YCrYCb", + .pixelformat = V4L2_PIX_FMT_YVYU, + }, { + .index = 6, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PLANAR, + .description = "YUV 4:2:2 planar, Y/Cb/Cr", + .pixelformat = V4L2_PIX_FMT_YUV422P, + }, { + .index = 7, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PLANAR, + .description = "YUV 4:2:0 planar, Y/CbCr", + .pixelformat = V4L2_PIX_FMT_NV12, + }, { + .index = 8, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PLANAR, + .description = "YUV 4:2:0 planar, Y/CbCr, Tiled", + .pixelformat = V4L2_PIX_FMT_NV12T, + }, { + .index = 9, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PLANAR, + .description = "YUV 4:2:0 planar, Y/CrCb", + .pixelformat = V4L2_PIX_FMT_NV21, + }, { + .index = 10, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PLANAR, + .description = "YUV 4:2:2 planar, Y/CbCr", + .pixelformat = V4L2_PIX_FMT_NV16, + }, { + .index = 11, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PLANAR, + .description = "YUV 4:2:2 planar, Y/CrCb", + .pixelformat = V4L2_PIX_FMT_NV61, + }, { + .index = 12, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_PLANAR, + .description = "YUV 4:2:0 planar, Y/Cb/Cr", + .pixelformat = V4L2_PIX_FMT_YUV420, + }, { + .index = 13, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = FORMAT_FLAGS_ENCODED, + .description = "Encoded JPEG bitstream", + .pixelformat = V4L2_PIX_FMT_JPEG, + }, +}; + +static const struct v4l2_queryctrl fimc_controls[] = { + { + .id = V4L2_CID_ROTATION, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Roataion", + .minimum = 0, + .maximum = 270, + .step = 90, + .default_value = 0, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_PADDR_Y, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Physical address Y", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, + }, { + .id = V4L2_CID_PADDR_CB, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Physical address Cb", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, + }, { + .id = V4L2_CID_PADDR_CR, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Physical address Cr", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, + }, { + .id = V4L2_CID_PADDR_CBCR, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Physical address CbCr", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, + }, +}; + +#ifndef CONFIG_VIDEO_FIMC_MIPI +void s3c_csis_start(int lanes, int settle, int align, int width, int height, + int pixel_format) {} +#endif + +static int fimc_camera_init(struct fimc_control *ctrl) +{ + int ret; + + fimc_dbg("%s\n", __func__); + + /* do nothing if already initialized */ + if (ctrl->cam->initialized) + return 0; + + /* enable camera power if needed */ + if (ctrl->cam->cam_power) + ctrl->cam->cam_power(1); + + /* subdev call for init */ + ret = subdev_call(ctrl, core, init, 0); + if (ret == -ENOIOCTLCMD) { + fimc_err("%s: init subdev api not supported\n", + __func__); + return ret; + } + + if (ctrl->cam->type == CAM_TYPE_MIPI) { + /* subdev call for sleep/wakeup: + * no error although no s_stream api support + */ + u32 pixelformat; + if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG) + pixelformat = V4L2_PIX_FMT_JPEG; + else + pixelformat = ctrl->cam->pixelformat; + + subdev_call(ctrl, video, s_stream, 0); + s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle, \ + ctrl->cam->mipi_align, ctrl->cam->width, \ + ctrl->cam->height, pixelformat); + subdev_call(ctrl, video, s_stream, 1); + } + + ctrl->cam->initialized = 1; + + return 0; +} + + +/* This function must be called after s_fmt and s_parm call to the subdev + * has already been made. + * + * - obtains the camera output (input to FIMC) resolution. + * - sets the preview size (aka camera output resolution) and framerate. + * - starts the preview operation. + * + * On success, returns 0. + * On failure, returns the error code of the call that failed. + */ +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 { + 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; + cam_ctrl.value = 1; + ret = subdev_call(ctrl, core, s_ctrl, &cam_ctrl); + + /* When the device is waking up from sleep, this call may fail. In + * that case, it is better to reset the camera sensor and start again. + * If the preview fails again, the reason might be something else and + * we should return the error. + */ + if (ret < 0 && ret != -ENOIOCTLCMD) { + ctrl->cam->initialized = 0; + fimc_camera_init(ctrl); + ret = subdev_call(ctrl, core, s_ctrl, &cam_ctrl); + if (ret < 0 && ret != -ENOIOCTLCMD) { + fimc_err("%s: Error in V4L2_CID_CAM_PREVIEW_ONOFF" + " - start\n", __func__); + return ret; + } + } + + return 0; +} + +static int fimc_camera_get_jpeg_memsize(struct fimc_control *ctrl) +{ + int ret; + struct v4l2_control cam_ctrl; + cam_ctrl.id = V4L2_CID_CAM_JPEG_MEMSIZE; + + ret = subdev_call(ctrl, core, g_ctrl, &cam_ctrl); + if (ret < 0) { + fimc_err("%s: Subdev doesn't support JEPG encoding.\n", \ + __func__); + return 0; + } + + return cam_ctrl.value; +} + + +static int fimc_capture_scaler_info(struct fimc_control *ctrl) +{ + struct fimc_scaler *sc = &ctrl->sc; + struct v4l2_rect *window = &ctrl->cam->window; + int tx, ty, sx, sy; + + sx = window->width; + sy = window->height; + tx = ctrl->cap->fmt.width; + ty = ctrl->cap->fmt.height; + + sc->real_width = sx; + sc->real_height = sy; + + fimc_dbg("%s: CamOut (%d, %d), TargetOut (%d, %d)\n", \ + __func__, sx, sy, tx, ty); + + if (sx <= 0 || sy <= 0) { + fimc_err("%s: invalid source size\n", __func__); + return -EINVAL; + } + + if (tx <= 0 || ty <= 0) { + fimc_err("%s: invalid target size\n", __func__); + return -EINVAL; + } + + fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor); + fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor); + + /* Tushar - sx and sy should be multiple of pre_hratio and pre_vratio */ + sc->pre_dst_width = sx / sc->pre_hratio; + sc->pre_dst_height = sy / sc->pre_vratio; + + sc->main_hratio = (sx << 8) / (tx << sc->hfactor); + sc->main_vratio = (sy << 8) / (ty << sc->vfactor); + + sc->scaleup_h = (tx >= sx) ? 1 : 0; + sc->scaleup_v = (ty >= sy) ? 1 : 0; + + return 0; +} + +/** + * fimc_add_inqueue: used to add the buffer at given index to inqueue + * + * Called from qbuf(). + * + * Returns error if buffer is already in queue or buffer index is out of range. + */ +static int fimc_add_inqueue(struct fimc_control *ctrl, int i) +{ + struct fimc_capinfo *cap = ctrl->cap; + + struct fimc_buf_set *buf; + + if (i >= cap->nr_bufs) + return -EINVAL; + + list_for_each_entry(buf, &cap->inq, list) { + if (buf->id == i) { + fimc_dbg("%s: buffer %d already in inqueue.\n", \ + __func__, i); + return -EINVAL; + } + } + list_add_tail(&cap->bufs[i].list, &cap->inq); + + return 0; +} + +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; + + /* 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; + } + + 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; +} + +static int fimc_update_hwaddr(struct fimc_control *ctrl) +{ + int i; + + for (i = 0; i < FIMC_PINGPONG; i++) + fimc_add_outqueue(ctrl, i); + + return 0; +} + +int fimc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cam || !ctrl->cam->sd) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + ret = subdev_call(ctrl, video, g_parm, a); + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + +int fimc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = 0; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cam || !ctrl->cam->sd) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + if (ctrl->id != 2) + ret = subdev_call(ctrl, video, s_parm, a); + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + +/* Enumerate controls */ +int fimc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int i, ret; + + fimc_dbg("%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(fimc_controls); i++) { + if (fimc_controls[i].id == qc->id) { + memcpy(qc, &fimc_controls[i], \ + sizeof(struct v4l2_queryctrl)); + return 0; + } + } + + mutex_lock(&ctrl->v4l2_lock); + ret = subdev_call(ctrl, core, queryctrl, qc); + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + +/* Menu control items */ +int fimc_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qm) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret; + + fimc_dbg("%s\n", __func__); + + mutex_lock(&ctrl->v4l2_lock); + ret = subdev_call(ctrl, core, querymenu, qm); + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + + +/* Given the index, we will return the camera name if there is any camera + * present at the given id. + */ +int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp) +{ + struct fimc_global *fimc = get_fimc_dev(); + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + + fimc_dbg("%s: index %d\n", __func__, inp->index); + + if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) { + fimc_err("%s: invalid input index, received = %d\n", \ + __func__, inp->index); + return -EINVAL; + } + + if (!fimc->camera_isvalid[inp->index]) + return -EINVAL; + + strcpy(inp->name, fimc->camera[inp->index].info->type); + inp->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +int fimc_g_input(struct file *file, void *fh, unsigned int *i) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_global *fimc = get_fimc_dev(); + + /* In case of isueing g_input before s_input */ + if (!ctrl->cam) { + fimc_err("no camera device selected yet!" \ + "do VIDIOC_S_INPUT first\n"); + return -ENODEV; + } + + *i = (unsigned int) fimc->active_camera; + + fimc_dbg("%s: index %d\n", __func__, *i); + + return 0; +} + +int fimc_release_subdev(struct fimc_control *ctrl) +{ + struct fimc_global *fimc = get_fimc_dev(); + struct i2c_client *client; + + if (ctrl && ctrl->cam && ctrl->cam->sd) { + fimc_dbg("%s called\n", __func__); + client = v4l2_get_subdevdata(ctrl->cam->sd); + i2c_unregister_device(client); + ctrl->cam->sd = NULL; + if (ctrl->cam->cam_power) + ctrl->cam->cam_power(0); + ctrl->cam->initialized = 0; + ctrl->cam = NULL; + fimc->active_camera = -1; + } + return 0; +} + +static int fimc_configure_subdev(struct fimc_control *ctrl) +{ + struct i2c_adapter *i2c_adap; + struct i2c_board_info *i2c_info; + struct v4l2_subdev *sd; + unsigned short addr; + char *name; + + /* set parent for mclk */ + if (clk_get_parent(ctrl->cam->clk->parent)) + clk_set_parent(ctrl->cam->clk->parent, ctrl->cam->srclk); + + /* set rate for mclk */ + if (clk_get_rate(ctrl->cam->clk)) + clk_set_rate(ctrl->cam->clk, ctrl->cam->clk_rate); + + i2c_adap = i2c_get_adapter(ctrl->cam->i2c_busnum); + if (!i2c_adap) + fimc_err("subdev i2c_adapter missing-skip registration\n"); + + i2c_info = ctrl->cam->info; + if (!i2c_info) { + fimc_err("%s: subdev i2c board info missing\n", __func__); + return -ENODEV; + } + + name = i2c_info->type; + if (!name) { + fimc_err("subdev i2c driver name missing-skip registration\n"); + return -ENODEV; + } + + addr = i2c_info->addr; + if (!addr) { + fimc_err("subdev i2c address missing-skip registration\n"); + return -ENODEV; + } + /* + * NOTE: first time subdev being registered, + * s_config is called and try to initialize subdev device + * but in this point, we are not giving MCLK and power to subdev + * so nothing happens but pass platform data through + */ + sd = v4l2_i2c_new_subdev_board(&ctrl->v4l2_dev, i2c_adap, + i2c_info, &addr); + if (!sd) { + fimc_err("%s: v4l2 subdev board registering failed\n", + __func__); + } + + /* Assign subdev to proper camera device pointer */ + ctrl->cam->sd = sd; + + return 0; +} + +int fimc_s_input(struct file *file, void *fh, unsigned int i) +{ + struct fimc_global *fimc = get_fimc_dev(); + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = 0; + + fimc_dbg("%s: index %d\n", __func__, i); + + if (i < 0 || i >= FIMC_MAXCAMS) { + fimc_err("%s: invalid input index\n", __func__); + return -EINVAL; + } + + if (!fimc->camera_isvalid[i]) + return -EINVAL; + + if (fimc->camera[i].sd && ctrl->id != 2) { + fimc_err("%s: Camera already in use.\n", __func__); + return -EBUSY; + } + + mutex_lock(&ctrl->v4l2_lock); + /* If ctrl->cam is not NULL, there is one subdev already registered. + * We need to unregister that subdev first. + */ + if (i != fimc->active_camera) { + fimc_release_subdev(ctrl); + ctrl->cam = &fimc->camera[i]; + ret = fimc_configure_subdev(ctrl); + if (ret < 0) { + mutex_unlock(&ctrl->v4l2_lock); + fimc_err("%s: Could not register camera sensor " + "with V4L2.\n", __func__); + return -ENODEV; + } + fimc->active_camera = i; + } + + if (ctrl->id == 2) { + if (i == fimc->active_camera) { + ctrl->cam = &fimc->camera[i]; + } else { + mutex_unlock(&ctrl->v4l2_lock); + return -EINVAL; + } + } + + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +int fimc_enum_fmt_vid_capture(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int i = f->index; + int num_entries = 0; + int ret = 0; + enum v4l2_mbus_pixelcode code; + + fimc_dbg("%s\n", __func__); + + if (ctrl->out) { + fimc_err("%s: fimc is already used for output mode\n", + __func__); + return -EINVAL; + } + + if (!ctrl->cam || !ctrl->cam->sd) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + num_entries = sizeof(capture_fmts)/sizeof(struct v4l2_fmtdesc); + + if (i >= num_entries) { + mutex_lock(&ctrl->v4l2_lock); + ret = subdev_call(ctrl, video, enum_mbus_fmt, + f->index - num_entries, &code); + mutex_unlock(&ctrl->v4l2_lock); + return ret; + } + + memcpy(f, &capture_fmts[i], sizeof(*f)); + + return 0; +} + +int fimc_g_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cap) { + fimc_err("%s: no capture device info\n", __func__); + return -EINVAL; + } + + mutex_lock(&ctrl->v4l2_lock); + + memcpy(&f->fmt.pix, &ctrl->cap->fmt, sizeof(f->fmt.pix)); + + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +/* + * Check for whether the requested format + * can be streamed out from FIMC + * depends on FIMC node + */ +static int fimc_fmt_avail(struct fimc_control *ctrl, + struct v4l2_format *f) +{ + int i; + + /* + * TODO: check for which FIMC is used. + * Available fmt should be varied for each FIMC + */ + + for (i = 0; i < sizeof(capture_fmts); i++) { + if (capture_fmts[i].pixelformat == f->fmt.pix.pixelformat) + return 0; + } + + fimc_err("Not supported pixelformat requested\n"); + + return -1; +} + +/* + * figures out the depth of requested format + */ +static int fimc_fmt_depth(struct fimc_control *ctrl, struct v4l2_format *f) +{ + int err, depth = 0; + + /* First check for available format or not */ + err = fimc_fmt_avail(ctrl, f); + if (err < 0) + return -EINVAL; + + /* handles only supported pixelformats */ + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB32: + depth = 32; + fimc_dbg("32bpp\n"); + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + depth = 16; + fimc_dbg("16bpp\n"); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YUV420: + depth = 12; + fimc_dbg("12bpp\n"); + break; + case V4L2_PIX_FMT_JPEG: + depth = -1; + fimc_dbg("Compressed format.\n"); + break; + default: + fimc_dbg("why am I here? - received %x\n", + f->fmt.pix.pixelformat); + break; + } + + return depth; +} + +int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_capinfo *cap; + struct v4l2_mbus_framefmt mbus_fmt; + int ret = 0; + int depth; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cam || !ctrl->cam->sd) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + /* + * The first time alloc for struct cap_info, and will be + * 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); + fimc_err("%s: no memory for " + "capture device info\n", __func__); + return -ENOMEM; + } + + } + cap = ctrl->cap; + memset(cap, 0, sizeof(*cap)); + memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt)); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, 0); + + /* + * Note that expecting format only can be with + * available output format from FIMC + * Following items should be handled in driver + * bytesperline = width * depth / 8 + * sizeimage = bytesperline * height + */ + /* This function may return 0 or -1 in case of error, hence need to + * check here. + */ + depth = fimc_fmt_depth(ctrl, f); + if (depth == 0) { + mutex_unlock(&ctrl->v4l2_lock); + fimc_err("%s: Invalid pixel format\n", __func__); + return -EINVAL; + } else if (depth < 0) { + /* + * When the pixelformat is JPEG, the application is requesting + * for data in JPEG compressed format. + */ + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + ret = subdev_call(ctrl, video, try_mbus_fmt, &mbus_fmt); + if (ret < 0) { + mutex_unlock(&ctrl->v4l2_lock); + return -EINVAL; + } + cap->fmt.colorspace = V4L2_COLORSPACE_JPEG; + } else { + cap->fmt.bytesperline = (cap->fmt.width * depth) >> 3; + cap->fmt.sizeimage = (cap->fmt.bytesperline * cap->fmt.height); + } + + if (cap->fmt.colorspace == V4L2_COLORSPACE_JPEG) { + ctrl->sc.bypass = 1; + cap->lastirq = 1; + } + + if (ctrl->id != 2) { + ret = subdev_call(ctrl, video, s_mbus_fmt, &mbus_fmt); + } + + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + +int fimc_try_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) +{ + return 0; +} + +static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align) +{ + struct fimc_capinfo *cap = ctrl->cap; + int i, plane; + + for (i = 0; i < cap->nr_bufs; i++) { + for (plane = 0; plane < 4; plane++) { + cap->bufs[i].length[plane] = size[plane]; + if (!cap->bufs[i].length[plane]) + continue; + + fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align); + + if (!cap->bufs[i].base[plane]) + goto err_alloc; + } + + cap->bufs[i].state = VIDEOBUF_PREPARED; + cap->bufs[i].id = i; + } + + return 0; + +err_alloc: + for (i = 0; i < cap->nr_bufs; i++) { + if (cap->bufs[i].base[plane]) + fimc_dma_free(ctrl, &cap->bufs[i], plane); + + memset(&cap->bufs[i], 0, sizeof(cap->bufs[i])); + } + + return -ENOMEM; +} + +static void fimc_free_buffers(struct fimc_control *ctrl) +{ + struct fimc_capinfo *cap; + int i; + + if (ctrl && ctrl->cap) + cap = ctrl->cap; + else + return; + + + for (i = 0; i < cap->nr_bufs; i++) { + memset(&cap->bufs[i], 0, sizeof(cap->bufs[i])); + cap->bufs[i].state = VIDEOBUF_NEEDS_INIT; + } + + ctrl->mem.curr = ctrl->mem.base; +} + +int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_capinfo *cap = ctrl->cap; + int ret = 0, i; + int size[4] = { 0, 0, 0, 0}; + int align = 0; + + if (b->memory != V4L2_MEMORY_MMAP) { + fimc_err("%s: invalid memory type\n", __func__); + return -EINVAL; + } + + if (!cap) { + fimc_err("%s: no capture device info\n", __func__); + return -ENODEV; + } + + if (!ctrl->cam || !ctrl->cam->sd) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + + if (b->count < 1 || b->count > FIMC_CAPBUFS) + return -EINVAL; + + /* It causes flickering as buf_0 and buf_3 refer to same hardware + * address. + */ + if (b->count == 3) + b->count = 4; + + cap->nr_bufs = b->count; + + fimc_dbg("%s: requested %d buffers\n", __func__, b->count); + + INIT_LIST_HEAD(&cap->inq); + fimc_free_buffers(ctrl); + + switch (cap->fmt.pixelformat) { + case V4L2_PIX_FMT_RGB32: /* fall through */ + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_YUV422P: /* fall through */ + size[0] = cap->fmt.sizeimage; + break; + + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: + size[0] = cap->fmt.width * cap->fmt.height; + size[1] = cap->fmt.width * cap->fmt.height; + break; + case V4L2_PIX_FMT_NV12: + size[0] = cap->fmt.width * cap->fmt.height; + size[1] = cap->fmt.width * cap->fmt.height/2; + break; + case V4L2_PIX_FMT_NV21: + size[0] = cap->fmt.width * cap->fmt.height; + size[1] = cap->fmt.width * cap->fmt.height/2; + break; + case V4L2_PIX_FMT_NV12T: + /* Tiled frame size calculations as per 4x2 tiles + * - Width: Has to be aligned to 2 times the tile width + * - Height: Has to be aligned to the tile height + * - Alignment: Has to be aligned to the size of the + * macrotile (size of 4 tiles) + * + * NOTE: In case of rotation, we need modified calculation as + * width and height are aligned to different values. + */ + if (cap->rotate == 90 || cap->rotate == 270) { + size[0] = ALIGN(ALIGN(cap->fmt.height, 128) * + ALIGN(cap->fmt.width, 32), + SZ_8K); + size[1] = ALIGN(ALIGN(cap->fmt.height, 128) * + ALIGN(cap->fmt.width/2, 32), + SZ_8K); + } else { + size[0] = ALIGN(ALIGN(cap->fmt.width, 128) * + ALIGN(cap->fmt.height, 32), + SZ_8K); + size[1] = ALIGN(ALIGN(cap->fmt.width, 128) * + ALIGN(cap->fmt.height/2, 32), + SZ_8K); + } + align = SZ_8K; + break; + + case V4L2_PIX_FMT_YUV420: + size[0] = cap->fmt.width * cap->fmt.height; + size[1] = cap->fmt.width * cap->fmt.height >> 2; + size[2] = cap->fmt.width * cap->fmt.height >> 2; + break; + + case V4L2_PIX_FMT_JPEG: + size[0] = fimc_camera_get_jpeg_memsize(ctrl); + default: + break; + } + + ret = fimc_alloc_buffers(ctrl, size, align); + if (ret) { + fimc_err("%s: no memory for " + "capture buffer\n", __func__); + mutex_unlock(&ctrl->v4l2_lock); + return -ENOMEM; + } + + for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) { + memcpy(&cap->bufs[i], \ + &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i])); + } + + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + + if (!ctrl->cap || !ctrl->cap->bufs) { + fimc_err("%s: no capture device info\n", __func__); + return -ENODEV; + } + + if (ctrl->status != FIMC_STREAMOFF) { + fimc_err("fimc is running\n"); + return -EBUSY; + } + + mutex_lock(&ctrl->v4l2_lock); + + b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y] + + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB] + + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR]; + + b->m.offset = b->index * PAGE_SIZE; + + ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE; + + mutex_unlock(&ctrl->v4l2_lock); + + fimc_dbg("%s: %d bytes at index: %d\n", __func__, b->length, b->index); + + return 0; +} + +int fimc_g_ctrl_capture(void *fh, struct v4l2_control *c) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = 0; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + + switch (c->id) { + case V4L2_CID_ROTATION: + c->value = ctrl->cap->rotate; + break; + + case V4L2_CID_HFLIP: + c->value = (ctrl->cap->flip & FIMC_XFLIP) ? 1 : 0; + break; + + case V4L2_CID_VFLIP: + c->value = (ctrl->cap->flip & FIMC_YFLIP) ? 1 : 0; + break; + + default: + /* get ctrl supported by subdev */ + mutex_unlock(&ctrl->v4l2_lock); + ret = subdev_call(ctrl, core, g_ctrl, c); + mutex_lock(&ctrl->v4l2_lock); + break; + } + + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + +/** + * We used s_ctrl API to get the physical address of the buffers. + * In g_ctrl, we can pass only one parameter, thus we cannot pass + * the index of the buffer. + * In order to use g_ctrl for obtaining the physical address, we + * will have to create CID ids for all values (4 ids for Y0~Y3 and 4 ids + * for C0~C3). Currently, we will continue with the existing + * implementation till we get any better idea to implement. + */ +int fimc_s_ctrl_capture(void *fh, struct v4l2_control *c) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = 0; + + fimc_info2("%s\n", __func__); + + if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap || !ctrl->cap->bufs) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + + switch (c->id) { + case V4L2_CID_ROTATION: + ctrl->cap->rotate = c->value; + break; + + case V4L2_CID_HFLIP: /* fall through */ + ctrl->cap->flip |= FIMC_XFLIP; + break; + case V4L2_CID_VFLIP: + ctrl->cap->flip |= FIMC_YFLIP; + break; + + case V4L2_CID_PADDR_Y: + c->value = ctrl->cap->bufs[c->value].base[FIMC_ADDR_Y]; + break; + + case V4L2_CID_PADDR_CB: /* fall through */ + case V4L2_CID_PADDR_CBCR: + c->value = ctrl->cap->bufs[c->value].base[FIMC_ADDR_CB]; + break; + + case V4L2_CID_PADDR_CR: + c->value = ctrl->cap->bufs[c->value].base[FIMC_ADDR_CR]; + break; + + /* Implementation as per C100 FIMC driver */ + case V4L2_CID_STREAM_PAUSE: + fimc_hwset_stop_processing(ctrl); + break; + + case V4L2_CID_IMAGE_EFFECT_APPLY: + ctrl->fe.ie_on = c->value ? 1 : 0; + ctrl->fe.ie_after_sc = 0; + ret = fimc_hwset_image_effect(ctrl); + break; + + case V4L2_CID_IMAGE_EFFECT_FN: + if (c->value < 0 || c->value > FIMC_EFFECT_FIN_SILHOUETTE) + return -EINVAL; + ctrl->fe.fin = c->value; + ret = 0; + break; + + case V4L2_CID_IMAGE_EFFECT_CB: + ctrl->fe.pat_cb = c->value & 0xFF; + ret = 0; + break; + + case V4L2_CID_IMAGE_EFFECT_CR: + ctrl->fe.pat_cr = c->value & 0xFF; + 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); + if (2 != ctrl->id) + ret = subdev_call(ctrl, core, s_ctrl, c); + else + ret = 0; + mutex_lock(&ctrl->v4l2_lock); + break; + } + + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + +int fimc_s_ext_ctrls_capture(void *fh, struct v4l2_ext_controls *c) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = 0; + + mutex_lock(&ctrl->v4l2_lock); + + /* try on subdev */ + ret = subdev_call(ctrl, core, s_ext_ctrls, c); + + mutex_unlock(&ctrl->v4l2_lock); + + return ret; +} + +int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_capinfo *cap = ctrl->cap; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + + /* crop limitations */ + cap->cropcap.bounds.left = 0; + cap->cropcap.bounds.top = 0; + cap->cropcap.bounds.width = ctrl->cam->width; + cap->cropcap.bounds.height = ctrl->cam->height; + + /* crop default values */ + cap->cropcap.defrect.left = 0; + cap->cropcap.defrect.top = 0; + cap->cropcap.defrect.width = ctrl->cam->width; + cap->cropcap.defrect.height = ctrl->cam->height; + + a->bounds = cap->cropcap.bounds; + a->defrect = cap->cropcap.defrect; + + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +int fimc_g_crop_capture(void *fh, struct v4l2_crop *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cap) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + a->c = ctrl->cap->crop; + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +static int fimc_capture_crop_size_check(struct fimc_control *ctrl) +{ + struct fimc_capinfo *cap = ctrl->cap; + int win_hor_offset = 0, win_hor_offset2 = 0; + int win_ver_offset = 0, win_ver_offset2 = 0; + int crop_width = 0, crop_height = 0; + + /* check win_hor_offset, win_hor_offset2 */ + win_hor_offset = ctrl->cam->window.left; + win_hor_offset2 = ctrl->cam->width - ctrl->cam->window.left - + ctrl->cam->window.width; + + win_ver_offset = ctrl->cam->window.top; + win_ver_offset2 = ctrl->cam->height - ctrl->cam->window.top - + ctrl->cam->window.height; + + if (win_hor_offset < 0 || win_hor_offset2 < 0) { + fimc_err("%s: Offset (left-side(%d) or right-side(%d) " + "is negative.\n", __func__, \ + win_hor_offset, win_hor_offset2); + return -1; + } + + if (win_ver_offset < 0 || win_ver_offset2 < 0) { + fimc_err("%s: Offset (top-side(%d) or bottom-side(%d)) " + "is negative.\n", __func__, \ + win_ver_offset, win_ver_offset2); + return -1; + } + + if ((win_hor_offset % 2) || (win_hor_offset2 % 2)) { + fimc_err("%s: win_hor_offset must be multiple of 2\n", \ + __func__); + return -1; + } + + /* check crop_width, crop_height */ + crop_width = ctrl->cam->window.width; + crop_height = ctrl->cam->window.height; + + if (crop_width % 16) { + fimc_err("%s: crop_width must be multiple of 16\n", __func__); + return -1; + } + + switch (cap->fmt.pixelformat) { + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV12T: /* fall through */ + if ((crop_height % 2) || (crop_height < 8)) { + fimc_err("%s: crop_height error!\n", __func__); + return -1; + } + break; + default: + break; + } + + return 0; +} + +/** Given crop parameters are w.r.t. target resolution. Scale + * it w.r.t. camera source resolution. + * + * Steps: + * 1. Scale as camera resolution with fixed-point calculation + * 2. Check for overflow condition + * 3. Apply FIMC constrainsts + */ +static void fimc_capture_update_crop_window(struct fimc_control *ctrl) +{ + unsigned int zoom_hor = 0; + unsigned int zoom_ver = 0; + unsigned int multiplier = 1024; + + if (!ctrl->cam->width || !ctrl->cam->height) + return; + + zoom_hor = ctrl->cap->fmt.width * multiplier / ctrl->cam->width; + zoom_ver = ctrl->cap->fmt.height * multiplier / ctrl->cam->height; + + if (!zoom_hor || !zoom_ver) + return; + + /* Width */ + ctrl->cam->window.width = ctrl->cap->crop.width * multiplier / zoom_hor; + if (ctrl->cam->window.width > ctrl->cam->width) + ctrl->cam->window.width = ctrl->cam->width; + if (ctrl->cam->window.width % 16) + ctrl->cam->window.width = + (ctrl->cam->window.width + 0xF) & ~0xF; + + /* Left offset */ + ctrl->cam->window.left = ctrl->cap->crop.left * multiplier / zoom_hor; + if (ctrl->cam->window.width + ctrl->cam->window.left > ctrl->cam->width) + ctrl->cam->window.left = + (ctrl->cam->width - ctrl->cam->window.width)/2; + if (ctrl->cam->window.left % 2) + ctrl->cam->window.left--; + + /* Height */ + ctrl->cam->window.height = + (ctrl->cap->crop.height * multiplier) / zoom_ver; + if (ctrl->cam->window.top > ctrl->cam->height) + ctrl->cam->window.height = ctrl->cam->height; + if (ctrl->cam->window.height % 2) + ctrl->cam->window.height--; + + /* Top offset */ + ctrl->cam->window.top = ctrl->cap->crop.top * multiplier / zoom_ver; + if (ctrl->cam->window.height + ctrl->cam->window.top > + ctrl->cam->height) + ctrl->cam->window.top = + (ctrl->cam->height - ctrl->cam->window.height)/2; + if (ctrl->cam->window.top % 2) + ctrl->cam->window.top--; + + fimc_dbg("Cam (%dx%d) Crop: (%d %d %d %d) Win: (%d %d %d %d)\n", \ + ctrl->cam->width, ctrl->cam->height, \ + ctrl->cap->crop.left, ctrl->cap->crop.top, \ + ctrl->cap->crop.width, ctrl->cap->crop.height, \ + ctrl->cam->window.left, ctrl->cam->window.top, \ + ctrl->cam->window.width, ctrl->cam->window.height); + +} + +int fimc_s_crop_capture(void *fh, struct v4l2_crop *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = 0; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cap) { + fimc_err("%s: No capture device.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + ctrl->cap->crop = a->c; + + fimc_capture_update_crop_window(ctrl); + + ret = fimc_capture_crop_size_check(ctrl); + if (ret < 0) { + mutex_unlock(&ctrl->v4l2_lock); + fimc_err("%s: Invalid crop parameters.\n", __func__); + return -EINVAL; + } + + if (ctrl->status == FIMC_STREAMON && + ctrl->cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) { + fimc_hwset_shadow_disable(ctrl); + fimc_hwset_camera_offset(ctrl); + fimc_capture_scaler_info(ctrl); + fimc_hwset_prescaler(ctrl, &ctrl->sc); + fimc_hwset_scaler(ctrl, &ctrl->sc); + fimc_hwset_shadow_enable(ctrl); + } + + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +int fimc_start_capture(struct fimc_control *ctrl) +{ + fimc_dbg("%s\n", __func__); + + if (!ctrl->sc.bypass) + fimc_hwset_start_scaler(ctrl); + + fimc_hwset_enable_capture(ctrl, ctrl->sc.bypass); + + return 0; +} + +int fimc_stop_capture(struct fimc_control *ctrl) +{ + fimc_dbg("%s\n", __func__); + + if (ctrl->cap->lastirq) { + fimc_hwset_enable_lastirq(ctrl); + fimc_hwset_disable_capture(ctrl); + fimc_hwset_disable_lastirq(ctrl); + ctrl->cap->lastirq = 0; + } else { + fimc_hwset_disable_capture(ctrl); + } + + fimc_hwset_disable_irq(ctrl); + fimc_hwset_clear_irq(ctrl); + + if (!ctrl->sc.bypass) + fimc_hwset_stop_scaler(ctrl); + else + ctrl->sc.bypass = 0; + + fimc_wait_disable_capture(ctrl); + + return 0; +} + +static void fimc_reset_capture(struct fimc_control *ctrl) +{ + int i; + + ctrl->status = FIMC_READY_OFF; + + fimc_stop_capture(ctrl); + + for (i = 0; i < FIMC_PINGPONG; i++) + fimc_add_inqueue(ctrl, ctrl->cap->outq[i]); + + fimc_hwset_reset(ctrl); + + if (0 != ctrl->id) + fimc_clk_en(ctrl, false); + + ctrl->status = FIMC_STREAMOFF; +} + + +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__); + return -ENODEV; + } + + if (ctrl->status == FIMC_STREAMON) { + fimc_err("%s: Camera already running.\n", __func__); + return -EBUSY; + } + + mutex_lock(&ctrl->v4l2_lock); + + if (0 != ctrl->id) + fimc_clk_en(ctrl, true); + + ctrl->status = FIMC_READY_ON; + cap->irq = 0; + + fimc_hwset_enable_irq(ctrl, 0, 1); + + 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); + if (ret < 0) { + fimc_reset_capture(ctrl); + mutex_unlock(&ctrl->v4l2_lock); + return ret; + } + } + + fimc_hwset_camera_type(ctrl); + fimc_hwset_camera_polarity(ctrl); + fimc_update_hwaddr(ctrl); + + if (cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) { + fimc_hwset_camera_source(ctrl); + fimc_hwset_camera_offset(ctrl); + + fimc_capture_scaler_info(ctrl); + fimc_hwset_prescaler(ctrl, &ctrl->sc); + fimc_hwset_scaler(ctrl, &ctrl->sc); + + fimc_hwset_output_colorspace(ctrl, cap->fmt.pixelformat); + fimc_hwset_output_addr_style(ctrl, cap->fmt.pixelformat); + fimc_hwset_output_area(ctrl, cap->fmt.width, cap->fmt.height); + + if (cap->fmt.pixelformat == V4L2_PIX_FMT_RGB32 || + cap->fmt.pixelformat == V4L2_PIX_FMT_RGB565) + fimc_hwset_output_rgb(ctrl, cap->fmt.pixelformat); + else + fimc_hwset_output_yuv(ctrl, cap->fmt.pixelformat); + + 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); + + if (rot & FIMC_ROT) { + fimc_hwset_org_output_size(ctrl, cap->fmt.height, + cap->fmt.width); + } else { + fimc_hwset_org_output_size(ctrl, cap->fmt.width, + cap->fmt.height); + } + fimc_hwset_jpeg_mode(ctrl, false); + } else { + fimc_hwset_output_area_size(ctrl, \ + fimc_camera_get_jpeg_memsize(ctrl)/2); + fimc_hwset_jpeg_mode(ctrl, true); + } + + if (ctrl->cap->fmt.colorspace == V4L2_COLORSPACE_JPEG) + fimc_hwset_scaler_bypass(ctrl); + + fimc_start_capture(ctrl); + + if (ctrl->cap->fmt.colorspace == V4L2_COLORSPACE_JPEG && + ctrl->id != 2) { + struct v4l2_control cam_ctrl; + + cam_ctrl.id = V4L2_CID_CAM_CAPTURE; + ret = subdev_call(ctrl, core, s_ctrl, &cam_ctrl); + if (ret < 0 && ret != -ENOIOCTLCMD) { + fimc_reset_capture(ctrl); + mutex_unlock(&ctrl->v4l2_lock); + fimc_err("%s: Error in V4L2_CID_CAM_CAPTURE\n", \ + __func__); + return -EPERM; + } + } + + ctrl->status = FIMC_STREAMON; + + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +int fimc_streamoff_capture(void *fh) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + + fimc_dbg("%s\n", __func__); + + if (!ctrl->cap || !ctrl->cam || !ctrl->cam->sd) { + fimc_err("%s: No capture info.\n", __func__); + return -ENODEV; + } + + mutex_lock(&ctrl->v4l2_lock); + fimc_reset_capture(ctrl); + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +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); + + return 0; +} + +int fimc_dqbuf_capture(void *fh, struct v4l2_buffer *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_capinfo *cap; + int pp, ret = 0; + + 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; + } + + cap = ctrl->cap; + + mutex_lock(&ctrl->v4l2_lock); + + if (ctrl->status != FIMC_STREAMON) { + mutex_unlock(&ctrl->v4l2_lock); + fimc_dbg("%s: FIMC is not active.\n", __func__); + return -EINVAL; + } + + /* find out the real index */ + pp = ((fimc_hwget_frame_count(ctrl) + 2) % 4); + + /* We have read the latest frame, hence should reset availability + * flag + */ + cap->irq = 0; + + /* skip even frame: no data */ + if (cap->fmt.field == V4L2_FIELD_INTERLACED_TB) + pp &= ~0x1; + + 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__); + } + + mutex_unlock(&ctrl->v4l2_lock); + + /* fimc_dbg("%s: buf_index = %d\n", __func__, b->index); */ + + return ret; +} + diff --git a/drivers/media/video/samsung/fimc/fimc_dev.c b/drivers/media/video/samsung/fimc/fimc_dev.c new file mode 100644 index 0000000..aadae21 --- /dev/null +++ b/drivers/media/video/samsung/fimc/fimc_dev.c @@ -0,0 +1,1689 @@ +/* linux/drivers/media/video/samsung/fimc/fimc_dev.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Core file for Samsung Camera Interface (FIMC) 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/errno.h> +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/poll.h> +#include <linux/wait.h> +#include <linux/fs.h> +#include <linux/irq.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <media/v4l2-device.h> +#include <linux/io.h> +#include <linux/memory.h> +#include <linux/ctype.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <plat/clock.h> +#include <plat/media.h> +#include <mach/media.h> +#include <plat/fimc.h> +#include <linux/videodev2_samsung.h> +#include <linux/delay.h> +#include <plat/regs-fimc.h> + +#include "fimc.h" + +struct fimc_global *fimc_dev; + +int fimc_dma_alloc(struct fimc_control *ctrl, struct fimc_buf_set *bs, + int i, int align) +{ + dma_addr_t end, *curr; + + mutex_lock(&ctrl->alloc_lock); + + end = ctrl->mem.base + ctrl->mem.size; + curr = &ctrl->mem.curr; + + if (!bs->length[i]) + return -EINVAL; + + if (!align) { + if (*curr + bs->length[i] > end) { + goto overflow; + } else { + bs->base[i] = *curr; + bs->garbage[i] = 0; + *curr += bs->length[i]; + } + } else { + if (ALIGN(*curr, align) + bs->length[i] > end) + goto overflow; + else { + bs->base[i] = ALIGN(*curr, align); + bs->garbage[i] = ALIGN(*curr, align) - *curr; + *curr += (bs->length[i] + bs->garbage[i]); + } + } + + mutex_unlock(&ctrl->alloc_lock); + + return 0; + +overflow: + bs->base[i] = 0; + bs->length[i] = 0; + bs->garbage[i] = 0; + + mutex_unlock(&ctrl->alloc_lock); + + return -ENOMEM; +} + +void fimc_dma_free(struct fimc_control *ctrl, struct fimc_buf_set *bs, int i) +{ + int total = bs->length[i] + bs->garbage[i]; + mutex_lock(&ctrl->alloc_lock); + + if (bs->base[i]) { + if (ctrl->mem.curr - total >= ctrl->mem.base) + ctrl->mem.curr -= total; + + bs->base[i] = 0; + bs->length[i] = 0; + bs->garbage[i] = 0; + } + + mutex_unlock(&ctrl->alloc_lock); +} + +void fimc_clk_en(struct fimc_control *ctrl, bool on) +{ + struct platform_device *pdev; + struct s3c_platform_fimc *pdata; + struct clk *lclk; + + pdev = to_platform_device(ctrl->dev); + pdata = to_fimc_plat(ctrl->dev); + lclk = clk_get(&pdev->dev, pdata->lclk_name); + + if (on) { + if (!lclk->usage) { + if (!ctrl->out) + fimc_info1("(%d) Clock %s(%d) enabled.\n", + ctrl->id, ctrl->clk->name, + ctrl->clk->id); + + /* Turn on fimc power domain regulator */ + regulator_enable(ctrl->regulator); + clk_enable(lclk); + } + } else { + while (lclk->usage > 0) { + if (!ctrl->out) + fimc_info1("(%d) Clock %s(%d) disabled.\n", + ctrl->id, ctrl->clk->name, + ctrl->clk->id); + clk_disable(lclk); + /* Turn off fimc power domain regulator */ + regulator_disable(ctrl->regulator); + } + } + +} + +static inline u32 fimc_irq_out_single_buf(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + int ret = -1, ctx_num, next; + u32 wakeup = 1; + + if (ctx->status == FIMC_READY_OFF) { + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + ctx->status = FIMC_STREAMOFF; + ctrl->status = FIMC_STREAMOFF; + + return wakeup; + } + + ctx->status = FIMC_STREAMON_IDLE; + + /* Attach done buffer to outgoing queue. */ + ret = fimc_push_outq(ctrl, ctx, ctrl->out->idxs.active.idx); + if (ret < 0) + fimc_err("Failed: fimc_push_outq\n"); + + /* Detach buffer from incomming queue. */ + ret = fimc_pop_inq(ctrl, &ctx_num, &next); + if (ret == 0) { /* There is a buffer in incomming queue. */ + if (ctx_num != ctrl->out->last_ctx) { + ctx = &ctrl->out->ctx[ctx_num]; + ctrl->out->last_ctx = ctx->ctx_num; + fimc_outdev_set_ctx_param(ctrl, ctx); + } + + fimc_outdev_set_src_addr(ctrl, ctx->src[next].base); + + fimc_output_set_dst_addr(ctrl, ctx, next); + + ret = fimc_outdev_start_camif(ctrl); + if (ret < 0) + fimc_err("Fail: fimc_start_camif\n"); + + ctrl->out->idxs.active.ctx = ctx_num; + ctrl->out->idxs.active.idx = next; + ctx->status = FIMC_STREAMON; + ctrl->status = FIMC_STREAMON; + } else { /* There is no buffer in incomming queue. */ + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + ctx->status = FIMC_STREAMON_IDLE; + ctrl->status = FIMC_STREAMON_IDLE; + } + + return wakeup; +} + +static inline u32 fimc_irq_out_multi_buf(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + int ret = -1, ctx_num, next; + u32 wakeup = 1; + + if (ctx->status == FIMC_READY_OFF) { + if (ctrl->out->idxs.active.ctx == ctx->ctx_num) { + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + } + + ctx->status = FIMC_STREAMOFF; + + return wakeup; + } + + /* Attach done buffer to outgoing queue. */ + ret = fimc_push_outq(ctrl, ctx, ctrl->out->idxs.active.idx); + if (ret < 0) + fimc_err("Failed: fimc_push_outq\n"); + + /* Detach buffer from incomming queue. */ + ret = fimc_pop_inq(ctrl, &ctx_num, &next); + if (ret == 0) { /* There is a buffer in incomming queue. */ + if (ctx_num != ctrl->out->last_ctx) { + ctx = &ctrl->out->ctx[ctx_num]; + ctrl->out->last_ctx = ctx->ctx_num; + fimc_outdev_set_ctx_param(ctrl, ctx); + } + + fimc_outdev_set_src_addr(ctrl, ctx->src[next].base); + + fimc_output_set_dst_addr(ctrl, ctx, next); + + ret = fimc_outdev_start_camif(ctrl); + if (ret < 0) + fimc_err("Fail: fimc_start_camif\n"); + + ctrl->out->idxs.active.ctx = ctx_num; + ctrl->out->idxs.active.idx = next; + ctx->status = FIMC_STREAMON; + ctrl->status = FIMC_STREAMON; + } else { /* There is no buffer in incomming queue. */ + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + ctx->status = FIMC_STREAMON_IDLE; + ctrl->status = FIMC_STREAMON_IDLE; + } + + return wakeup; +} + +static inline u32 fimc_irq_out_dma(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct fimc_buf_set buf_set; + int idx = ctrl->out->idxs.active.idx; + int ret = -1, i, ctx_num, next; + u32 wakeup = 1; + + if (ctx->status == FIMC_READY_OFF) { + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + ctx->status = FIMC_STREAMOFF; + ctrl->status = FIMC_STREAMOFF; + return wakeup; + } + + /* Attach done buffer to outgoing queue. */ + ret = fimc_push_outq(ctrl, ctx, idx); + if (ret < 0) + fimc_err("Failed: fimc_push_outq\n"); + + if (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO) { + struct s3cfb_window *win; + struct fb_info *fbinfo; + + fbinfo = registered_fb[ctx->overlay.fb_id]; + win = (struct s3cfb_window *)fbinfo->par; + + win->other_mem_addr = ctx->dst[idx].base[FIMC_ADDR_Y]; + + ret = fb_pan_display(fbinfo, &fbinfo->var); + if (ret < 0) { + fimc_err("%s: fb_pan_display fail (ret=%d)\n", + __func__, ret); + return -EINVAL; + } + } + + /* Detach buffer from incomming queue. */ + ret = fimc_pop_inq(ctrl, &ctx_num, &next); + if (ret == 0) { /* There is a buffer in incomming queue. */ + ctx = &ctrl->out->ctx[ctx_num]; + fimc_outdev_set_src_addr(ctrl, ctx->src[next].base); + + memset(&buf_set, 0x00, sizeof(buf_set)); + buf_set.base[FIMC_ADDR_Y] = ctx->dst[next].base[FIMC_ADDR_Y]; + + for (i = 0; i < FIMC_PHYBUFS; i++) + fimc_hwset_output_address(ctrl, &buf_set, i); + + ret = fimc_outdev_start_camif(ctrl); + if (ret < 0) + fimc_err("Fail: fimc_start_camif\n"); + + ctrl->out->idxs.active.ctx = ctx_num; + ctrl->out->idxs.active.idx = next; + + ctx->status = FIMC_STREAMON; + ctrl->status = FIMC_STREAMON; + } else { /* There is no buffer in incomming queue. */ + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + + ctx->status = FIMC_STREAMON_IDLE; + ctrl->status = FIMC_STREAMON_IDLE; + } + + return wakeup; +} + +static inline u32 fimc_irq_out_fimd(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct fimc_idx prev; + int ret = -1, ctx_num, next; + u32 wakeup = 0; + + /* Attach done buffer to outgoing queue. */ + if (ctrl->out->idxs.prev.idx != -1) { + ret = fimc_push_outq(ctrl, ctx, ctrl->out->idxs.prev.idx); + if (ret < 0) { + fimc_err("Failed: fimc_push_outq\n"); + } else { + ctrl->out->idxs.prev.ctx = -1; + ctrl->out->idxs.prev.idx = -1; + wakeup = 1; /* To wake up fimc_v4l2_dqbuf */ + } + } + + /* Update index structure. */ + if (ctrl->out->idxs.next.idx != -1) { + ctrl->out->idxs.active.ctx = ctrl->out->idxs.next.ctx; + ctrl->out->idxs.active.idx = ctrl->out->idxs.next.idx; + ctrl->out->idxs.next.idx = -1; + ctrl->out->idxs.next.ctx = -1; + } + + /* Detach buffer from incomming queue. */ + ret = fimc_pop_inq(ctrl, &ctx_num, &next); + if (ret == 0) { /* There is a buffer in incomming queue. */ + prev.ctx = ctrl->out->idxs.active.ctx; + prev.idx = ctrl->out->idxs.active.idx; + + ctrl->out->idxs.prev.ctx = prev.ctx; + ctrl->out->idxs.prev.idx = prev.idx; + + ctrl->out->idxs.next.ctx = ctx_num; + ctrl->out->idxs.next.idx = next; + + /* set source address */ + fimc_outdev_set_src_addr(ctrl, ctx->src[next].base); + } + + return wakeup; +} + +static inline void fimc_irq_out(struct fimc_control *ctrl) +{ + struct fimc_ctx *ctx; + u32 wakeup = 1; + int ctx_num = ctrl->out->idxs.active.ctx; + + /* Interrupt pendding clear */ + fimc_hwset_clear_irq(ctrl); + + /* check context num */ + if (ctx_num < 0 || ctx_num >= FIMC_MAX_CTXS) { + fimc_err("fimc_irq_out: invalid ctx (ctx=%d)\n", ctx_num); + wake_up(&ctrl->wq); + return; + } + + ctx = &ctrl->out->ctx[ctx_num]; + + switch (ctx->overlay.mode) { + case FIMC_OVLY_NONE_SINGLE_BUF: + wakeup = fimc_irq_out_single_buf(ctrl, ctx); + break; + case FIMC_OVLY_NONE_MULTI_BUF: + wakeup = fimc_irq_out_multi_buf(ctrl, ctx); + break; + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: + wakeup = fimc_irq_out_dma(ctrl, ctx); + break; + default: + fimc_err("[ctx=%d] fimc_irq_out: wrong overlay.mode (%d)\n", + ctx_num, ctx->overlay.mode); + break; + } + + if (wakeup == 1) + wake_up(&ctrl->wq); +} + +static inline void fimc_irq_cap(struct fimc_control *ctrl) +{ + struct fimc_capinfo *cap = ctrl->cap; + int pp; + u32 cfg; + + fimc_hwset_clear_irq(ctrl); + if (fimc_hwget_overflow_state(ctrl)) { + /* s/w reset -- added for recovering module in ESD state*/ + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg |= (S3C_CIGCTRL_SWRST); + writel(cfg, ctrl->regs + S3C_CIGCTRL); + msleep(1); + + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg &= ~S3C_CIGCTRL_SWRST; + writel(cfg, ctrl->regs + S3C_CIGCTRL); + } + pp = ((fimc_hwget_frame_count(ctrl) + 2) % 4); + if (cap->fmt.field == V4L2_FIELD_INTERLACED_TB) { + /* odd value of pp means one frame is made with top/bottom */ + if (pp & 0x1) { + cap->irq = 1; + wake_up(&ctrl->wq); + } + } else { + cap->irq = 1; + wake_up(&ctrl->wq); + } +} + +static irqreturn_t fimc_irq(int irq, void *dev_id) +{ + struct fimc_control *ctrl = (struct fimc_control *) dev_id; + + if (ctrl->cap) + fimc_irq_cap(ctrl); + else if (ctrl->out) + fimc_irq_out(ctrl); + + return IRQ_HANDLED; +} + +static +struct fimc_control *fimc_register_controller(struct platform_device *pdev) +{ + struct s3c_platform_fimc *pdata; + struct fimc_control *ctrl; + struct resource *res; + int id, mdev_id; + + id = pdev->id; + mdev_id = S5P_MDEV_FIMC0 + id; + pdata = to_fimc_plat(&pdev->dev); + + ctrl = get_fimc_ctrl(id); + ctrl->id = id; + ctrl->dev = &pdev->dev; + ctrl->vd = &fimc_video_device[id]; + ctrl->vd->minor = id; + + /* alloc from bank1 as default */ + ctrl->mem.base = pdata->pmem_start; + ctrl->mem.size = pdata->pmem_size; + ctrl->mem.curr = ctrl->mem.base; + + ctrl->status = FIMC_STREAMOFF; + switch (pdata->hw_ver) { + case 0x40: + ctrl->limit = &fimc40_limits[id]; + break; + case 0x43: + case 0x45: + ctrl->limit = &fimc43_limits[id]; + break; + case 0x50: + ctrl->limit = &fimc50_limits[id]; + break; + } + + ctrl->log = FIMC_LOG_DEFAULT; + + sprintf(ctrl->name, "%s%d", FIMC_NAME, id); + strcpy(ctrl->vd->name, ctrl->name); + + atomic_set(&ctrl->in_use, 0); + mutex_init(&ctrl->lock); + mutex_init(&ctrl->alloc_lock); + mutex_init(&ctrl->v4l2_lock); + init_waitqueue_head(&ctrl->wq); + + /* get resource for io memory */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + fimc_err("%s: failed to get io memory region\n", __func__); + return NULL; + } + + /* request mem region */ + res = request_mem_region(res->start, res->end - res->start + 1, + pdev->name); + if (!res) { + fimc_err("%s: failed to request io memory region\n", __func__); + return NULL; + } + + /* ioremap for register block */ + ctrl->regs = ioremap(res->start, res->end - res->start + 1); + if (!ctrl->regs) { + fimc_err("%s: failed to remap io region\n", __func__); + return NULL; + } + + /* irq */ + ctrl->irq = platform_get_irq(pdev, 0); + if (request_irq(ctrl->irq, fimc_irq, IRQF_DISABLED, ctrl->name, ctrl)) + fimc_err("%s: request_irq failed\n", __func__); + + fimc_hwset_reset(ctrl); + + return ctrl; +} + +static int fimc_unregister_controller(struct platform_device *pdev) +{ + struct s3c_platform_fimc *pdata; + struct fimc_control *ctrl; + int id = pdev->id; + + pdata = to_fimc_plat(&pdev->dev); + ctrl = get_fimc_ctrl(id); + + free_irq(ctrl->irq, ctrl); + mutex_destroy(&ctrl->lock); + mutex_destroy(&ctrl->alloc_lock); + mutex_destroy(&ctrl->v4l2_lock); + + fimc_clk_en(ctrl, false); + + iounmap(ctrl->regs); + memset(ctrl, 0, sizeof(*ctrl)); + + return 0; +} + +static void fimc_mmap_open(struct vm_area_struct *vma) +{ + struct fimc_global *dev = fimc_dev; + int pri_data = (int)vma->vm_private_data; + u32 id = pri_data / 0x100; + u32 ctx = (pri_data - (id * 0x100)) / 0x10; + u32 idx = pri_data % 0x10; + + atomic_inc(&dev->ctrl[id].out->ctx[ctx].src[idx].mapped_cnt); +} + +static void fimc_mmap_close(struct vm_area_struct *vma) +{ + struct fimc_global *dev = fimc_dev; + int pri_data = (int)vma->vm_private_data; + u32 id = pri_data / 0x100; + u32 ctx = (pri_data - (id * 0x100)) / 0x10; + u32 idx = pri_data % 0x10; + + atomic_dec(&dev->ctrl[id].out->ctx[ctx].src[idx].mapped_cnt); +} + +static struct vm_operations_struct fimc_mmap_ops = { + .open = fimc_mmap_open, + .close = fimc_mmap_close, +}; + +static inline +int fimc_mmap_out_src(struct file *filp, struct vm_area_struct *vma) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + int ctx_id = prv_data->ctx_id; + struct fimc_ctx *ctx = &ctrl->out->ctx[ctx_id]; + u32 start_phy_addr = 0; + u32 size = vma->vm_end - vma->vm_start; + u32 pfn, idx = vma->vm_pgoff; + u32 buf_length = 0; + int pri_data = 0; + + buf_length = PAGE_ALIGN(ctx->src[idx].length[FIMC_ADDR_Y] + + ctx->src[idx].length[FIMC_ADDR_CB] + + ctx->src[idx].length[FIMC_ADDR_CR]); + if (size > PAGE_ALIGN(buf_length)) { + fimc_err("Requested mmap size is too big\n"); + return -EINVAL; + } + + pri_data = (ctrl->id * 0x100) + (ctx_id * 0x10) + idx; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED; + vma->vm_ops = &fimc_mmap_ops; + vma->vm_private_data = (void *)pri_data; + + if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { + fimc_err("writable mapping must be shared\n"); + return -EINVAL; + } + + start_phy_addr = ctx->src[idx].base[FIMC_ADDR_Y]; + pfn = __phys_to_pfn(start_phy_addr); + + if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) { + fimc_err("mmap fail\n"); + return -EINVAL; + } + + vma->vm_ops->open(vma); + + ctx->src[idx].flags |= V4L2_BUF_FLAG_MAPPED; + + return 0; +} + +static inline +int fimc_mmap_out_dst(struct file *filp, struct vm_area_struct *vma, u32 idx) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + int ctx_id = prv_data->ctx_id; + unsigned long pfn = 0, size; + int ret = 0; + + size = vma->vm_end - vma->vm_start; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED; + + pfn = __phys_to_pfn(ctrl->out->ctx[ctx_id].dst[idx].base[0]); + ret = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); + if (ret != 0) + fimc_err("remap_pfn_range fail.\n"); + + return ret; +} + +static inline int fimc_mmap_out(struct file *filp, struct vm_area_struct *vma) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + int ctx_id = prv_data->ctx_id; + int idx = ctrl->out->ctx[ctx_id].overlay.req_idx; + int ret = -1; + + if (idx >= 0) + ret = fimc_mmap_out_dst(filp, vma, idx); + else if (idx == FIMC_MMAP_IDX) + ret = fimc_mmap_out_src(filp, vma); + + return ret; +} + +static inline int fimc_mmap_cap(struct file *filp, struct vm_area_struct *vma) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + u32 size = vma->vm_end - vma->vm_start; + u32 pfn, idx = vma->vm_pgoff; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED; + + /* + * page frame number of the address for a source frame + * to be stored at. + */ + pfn = __phys_to_pfn(ctrl->cap->bufs[idx].base[0]); + + if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { + fimc_err("%s: writable mapping must be shared\n", __func__); + return -EINVAL; + } + + if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) { + fimc_err("%s: mmap fail\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int fimc_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + int ret; + + if (ctrl->cap) + ret = fimc_mmap_cap(filp, vma); + else + ret = fimc_mmap_out(filp, vma); + + return ret; +} + +static u32 fimc_poll(struct file *filp, poll_table *wait) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + struct fimc_capinfo *cap = ctrl->cap; + u32 mask = 0; + + if (cap) { + if (cap->irq || (ctrl->status != FIMC_STREAMON)) { + mask = POLLIN | POLLRDNORM; + cap->irq = 0; + } else { + poll_wait(filp, &ctrl->wq, wait); + } + } + + return mask; +} + +static +ssize_t fimc_read(struct file *filp, char *buf, size_t count, loff_t *pos) +{ + return 0; +} + +static +ssize_t fimc_write(struct file *filp, const char *b, size_t c, loff_t *offset) +{ + return 0; +} + +u32 fimc_mapping_rot_flip(u32 rot, u32 flip) +{ + u32 ret = 0; + + switch (rot) { + case 0: + if (flip & FIMC_XFLIP) + ret |= FIMC_XFLIP; + + if (flip & FIMC_YFLIP) + ret |= FIMC_YFLIP; + break; + + case 90: + ret = FIMC_ROT; + if (flip & FIMC_XFLIP) + ret |= FIMC_XFLIP; + + if (flip & FIMC_YFLIP) + ret |= FIMC_YFLIP; + break; + + case 180: + ret = (FIMC_XFLIP | FIMC_YFLIP); + if (flip & FIMC_XFLIP) + ret &= ~FIMC_XFLIP; + + if (flip & FIMC_YFLIP) + ret &= ~FIMC_YFLIP; + break; + + case 270: + ret = (FIMC_XFLIP | FIMC_YFLIP | FIMC_ROT); + if (flip & FIMC_XFLIP) + ret &= ~FIMC_XFLIP; + + if (flip & FIMC_YFLIP) + ret &= ~FIMC_YFLIP; + break; + } + + return ret; +} + +int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) +{ + if (src >= tar * 64) { + return -EINVAL; + } else if (src >= tar * 32) { + *ratio = 32; + *shift = 5; + } else if (src >= tar * 16) { + *ratio = 16; + *shift = 4; + } else if (src >= tar * 8) { + *ratio = 8; + *shift = 3; + } else if (src >= tar * 4) { + *ratio = 4; + *shift = 2; + } else if (src >= tar * 2) { + *ratio = 2; + *shift = 1; + } else { + *ratio = 1; + *shift = 0; + } + + return 0; +} + +void fimc_get_nv12t_size(int img_hres, int img_vres, + int *y_size, int *cb_size, int rotate) +{ + int remain; + int y_hres_byte, y_vres_byte; + int cb_hres_byte, cb_vres_byte; + 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) { + remain = 16 - remain; + img_hres = img_hres + remain; + } + remain = img_vres % 16; + if (remain != 0) { + remain = 16 - remain; + img_vres = img_vres + remain; + } + + cb_hres_byte = img_hres; + cb_vres_byte = img_vres; + + y_hres_byte = img_hres - 1; + y_vres_byte = img_vres - 1; + y_hres_roundup = ((y_hres_byte >> 4) >> 3) + 1; + y_vres_roundup = ((y_vres_byte >> 4) >> 2) + 1; + if ((y_vres_byte & 0x20) == 0) { + y_hres_byte = y_hres_byte & 0x7f00; + y_hres_byte = y_hres_byte >> 8; + y_hres_byte = y_hres_byte & 0x7f; + + y_vres_byte = y_vres_byte & 0x7fc0; + y_vres_byte = y_vres_byte >> 6; + y_vres_byte = y_vres_byte & 0x1ff; + + *y_size = y_hres_byte +\ + (y_vres_byte * y_hres_roundup) + 1; + } else { + *y_size = y_hres_roundup * y_vres_roundup; + } + + *y_size = *(y_size) << 13; + + cb_hres_byte = img_hres - 1; + cb_vres_byte = (img_vres >> 1) - 1; + cb_hres_roundup = ((cb_hres_byte >> 4) >> 3) + 1; + cb_vres_roundup = ((cb_vres_byte >> 4) >> 2) + 1; + if ((cb_vres_byte & 0x20) == 0) { + cb_hres_byte = cb_hres_byte & 0x7f00; + cb_hres_byte = cb_hres_byte >> 8; + cb_hres_byte = cb_hres_byte & 0x7f; + + cb_vres_byte = cb_vres_byte & 0x7fc0; + cb_vres_byte = cb_vres_byte >> 6; + cb_vres_byte = cb_vres_byte & 0x1ff; + + *cb_size = cb_hres_byte + (cb_vres_byte * cb_hres_roundup) + 1; + } else { + *cb_size = cb_hres_roundup * cb_vres_roundup; + } + *cb_size = (*cb_size) << 13; + +} + +static int fimc_get_free_ctx(struct fimc_control *ctrl) +{ + int i; + + if (1 != ctrl->id) + return 0; + + for (i = 0; i < FIMC_MAX_CTXS; i++) { + if (ctrl->ctx_busy[i] == 0) { + ctrl->ctx_busy[i] = 1; + fimc_info1("Current context is %d\n", i); + return i; + } + } + + return -1; +} + +static int fimc_open(struct file *filp) +{ + struct fimc_control *ctrl; + struct s3c_platform_fimc *pdata; + struct fimc_prv_data *prv_data; + int in_use; + int ret; + + ctrl = video_get_drvdata(video_devdata(filp)); + pdata = to_fimc_plat(ctrl->dev); + + mutex_lock(&ctrl->lock); + + in_use = atomic_read(&ctrl->in_use); + if (in_use >= FIMC_MAX_CTXS || (in_use && 1 != ctrl->id)) { + fimc_err("%s: Device busy.\n", __func__); + ret = -EBUSY; + goto resource_busy; + } else { + atomic_inc(&ctrl->in_use); + } + in_use = atomic_read(&ctrl->in_use); + + prv_data = kzalloc(sizeof(struct fimc_prv_data), GFP_KERNEL); + if (!prv_data) { + fimc_err("%s: not enough memory\n", __func__); + ret = -ENOMEM; + goto kzalloc_err; + } + + prv_data->ctx_id = fimc_get_free_ctx(ctrl); + if (prv_data->ctx_id < 0) { + fimc_err("%s: Context busy flag not reset.\n", __func__); + ret = -EBUSY; + goto ctx_err; + } + prv_data->ctrl = ctrl; + filp->private_data = prv_data; + + if (in_use == 1) { + fimc_clk_en(ctrl, true); + + if (pdata->hw_ver == 0x40) + fimc_hw_reset_camera(ctrl); + + /* Apply things to interface register */ + fimc_hwset_reset(ctrl); + + if (num_registered_fb > 0) { + struct fb_info *fbinfo = registered_fb[0]; + ctrl->fb.lcd_hres = (int)fbinfo->var.xres; + ctrl->fb.lcd_vres = (int)fbinfo->var.yres; + fimc_info1("%s: fd.lcd_hres=%d fd.lcd_vres=%d\n", + __func__, ctrl->fb.lcd_hres, + ctrl->fb.lcd_vres); + } + + ctrl->mem.curr = ctrl->mem.base; + ctrl->status = FIMC_STREAMOFF; + + if (0 != ctrl->id) + fimc_clk_en(ctrl, false); + } + + mutex_unlock(&ctrl->lock); + + fimc_info1("%s opened.\n", ctrl->name); + + return 0; + +ctx_err: + kfree(prv_data); + +kzalloc_err: + atomic_dec(&ctrl->in_use); + +resource_busy: + mutex_unlock(&ctrl->lock); + return ret; +} + +static int fimc_release(struct file *filp) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + int ctx_id = prv_data->ctx_id; + struct s3c_platform_fimc *pdata; + struct fimc_overlay_buf *buf; + struct mm_struct *mm = current->mm; + struct fimc_ctx *ctx; + int ret = 0, i; + ctx = &ctrl->out->ctx[ctx_id]; + + pdata = to_fimc_plat(ctrl->dev); + + mutex_lock(&ctrl->lock); + atomic_dec(&ctrl->in_use); + + /* FIXME: turning off actual working camera */ + if (ctrl->cam && ctrl->id != 2) { + /* Unload the subdev (camera sensor) module, + * reset related status flags + */ + fimc_release_subdev(ctrl); + } + + if (ctrl->cap) { + ctrl->mem.curr = ctrl->mem.base; + kfree(filp->private_data); + filp->private_data = NULL; + + for (i = 0; i < FIMC_CAPBUFS; i++) { + fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 0); + fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 1); + fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 2); + } + + fimc_clk_en(ctrl, false); + + kfree(ctrl->cap); + ctrl->cap = NULL; + } + + if (ctrl->out) { + if (ctx->status != FIMC_STREAMOFF) { + fimc_clk_en(ctrl, true); + ret = fimc_outdev_stop_streaming(ctrl, ctx); + fimc_clk_en(ctrl, false); + if (ret < 0) + fimc_err("Fail: fimc_stop_streaming\n"); + + ret = fimc_init_in_queue(ctrl, ctx); + if (ret < 0) { + fimc_err("Fail: fimc_init_in_queue\n"); + ret = -EINVAL; + goto release_err; + } + + ret = fimc_init_out_queue(ctrl, ctx); + if (ret < 0) { + fimc_err("Fail: fimc_init_out_queue\n"); + ret = -EINVAL; + goto release_err; + } + + /* Make all buffers DQUEUED state. */ + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->src[i].state = VIDEOBUF_IDLE; + ctx->src[i].flags = V4L2_BUF_FLAG_MAPPED; + } + + if (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO) { + ctrl->mem.curr = ctx->dst[0].base[FIMC_ADDR_Y]; + + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->dst[i].base[FIMC_ADDR_Y] = 0; + ctx->dst[i].length[FIMC_ADDR_Y] = 0; + + ctx->dst[i].base[FIMC_ADDR_CB] = 0; + ctx->dst[i].length[FIMC_ADDR_CB] = 0; + + ctx->dst[i].base[FIMC_ADDR_CR] = 0; + ctx->dst[i].length[FIMC_ADDR_CR] = 0; + } + } + + ctx->status = FIMC_STREAMOFF; + } + + buf = &ctx->overlay.buf; + for (i = 0; i < FIMC_OUTBUFS; i++) { + if (buf->vir_addr[i]) { + ret = do_munmap(mm, buf->vir_addr[i], + buf->size[i]); + if (ret < 0) + fimc_err("%s: do_munmap fail\n", \ + __func__); + } + } + + ctrl->ctx_busy[ctx_id] = 0; + memset(ctx, 0x00, sizeof(struct fimc_ctx)); + + if (atomic_read(&ctrl->in_use) == 0) { + ctrl->status = FIMC_STREAMOFF; + fimc_outdev_init_idxs(ctrl); + + fimc_clk_en(ctrl, false); + + ctrl->mem.curr = ctrl->mem.base; + + kfree(ctrl->out); + ctrl->out = NULL; + + kfree(filp->private_data); + filp->private_data = NULL; + } + } + + /* + * it remain afterimage when I play movie using overlay and exit + */ + if (ctrl->fb.is_enable == 1) { + fimc_info2("WIN_OFF for FIMC%d\n", ctrl->id); + ret = fb_blank(registered_fb[ctx->overlay.fb_id], + FB_BLANK_POWERDOWN); + if (ret < 0) { + fimc_err("%s: fb_blank: fb[%d] " \ + "mode=FB_BLANK_POWERDOWN\n", + __func__, ctx->overlay.fb_id); + ret = -EINVAL; + goto release_err; + } + + ctrl->fb.is_enable = 0; + } + + mutex_unlock(&ctrl->lock); + + fimc_info1("%s released.\n", ctrl->name); + + return 0; + +release_err: + mutex_unlock(&ctrl->lock); + return ret; + +} + +static const struct v4l2_file_operations fimc_fops = { + .owner = THIS_MODULE, + .open = fimc_open, + .release = fimc_release, + .ioctl = video_ioctl2, + .read = fimc_read, + .write = fimc_write, + .mmap = fimc_mmap, + .poll = fimc_poll, +}; + +static void fimc_vdev_release(struct video_device *vdev) +{ + kfree(vdev); +} + +struct video_device fimc_video_device[FIMC_DEVICES] = { + [0] = { + .fops = &fimc_fops, + .ioctl_ops = &fimc_v4l2_ops, + .release = fimc_vdev_release, + }, + [1] = { + .fops = &fimc_fops, + .ioctl_ops = &fimc_v4l2_ops, + .release = fimc_vdev_release, + }, + [2] = { + .fops = &fimc_fops, + .ioctl_ops = &fimc_v4l2_ops, + .release = fimc_vdev_release, + }, +}; + +static int fimc_init_global(struct platform_device *pdev) +{ + struct s3c_platform_fimc *pdata; + struct s3c_platform_camera *cam; + int i; + + pdata = to_fimc_plat(&pdev->dev); + + /* Registering external camera modules. re-arrange order to be sure */ + for (i = 0; i < FIMC_MAXCAMS; i++) { + cam = pdata->camera[i]; + if (!cam) + break; + + cam->srclk = clk_get(&pdev->dev, cam->srclk_name); + if (IS_ERR(cam->srclk)) { + dev_err(&pdev->dev, "%s: failed to get mclk source\n", + __func__); + return -EINVAL; + } + + /* mclk */ + cam->clk = clk_get(&pdev->dev, cam->clk_name); + if (IS_ERR(cam->clk)) { + dev_err(&pdev->dev, "%s: failed to get mclk source\n", + __func__); + clk_put(cam->srclk); + return -EINVAL; + } + + clk_put(cam->clk); + clk_put(cam->srclk); + + /* Assign camera device to fimc */ + memcpy(&fimc_dev->camera[i], cam, sizeof(*cam)); + fimc_dev->camera_isvalid[i] = 1; + fimc_dev->camera[i].initialized = 0; + } + + fimc_dev->active_camera = -1; + fimc_dev->initialized = 1; + + return 0; +} + +static int fimc_show_log_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fimc_control *ctrl; + struct platform_device *pdev; + int id = -1; + + char temp[150]; + + pdev = to_platform_device(dev); + id = pdev->id; + ctrl = get_fimc_ctrl(id); + + sprintf(temp, "\t"); + strcat(buf, temp); + if (ctrl->log & FIMC_LOG_DEBUG) { + sprintf(temp, "FIMC_LOG_DEBUG | "); + strcat(buf, temp); + } + + if (ctrl->log & FIMC_LOG_INFO_L2) { + sprintf(temp, "FIMC_LOG_INFO_L2 | "); + strcat(buf, temp); + } + + if (ctrl->log & FIMC_LOG_INFO_L1) { + sprintf(temp, "FIMC_LOG_INFO_L1 | "); + strcat(buf, temp); + } + + if (ctrl->log & FIMC_LOG_WARN) { + sprintf(temp, "FIMC_LOG_WARN | "); + strcat(buf, temp); + } + + if (ctrl->log & FIMC_LOG_ERR) { + sprintf(temp, "FIMC_LOG_ERR\n"); + strcat(buf, temp); + } + + return strlen(buf); +} + +static int fimc_store_log_level(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct fimc_control *ctrl; + struct platform_device *pdev; + + const char *p = buf; + char msg[150] = {0, }; + int id = -1; + u32 match = 0; + + pdev = to_platform_device(dev); + id = pdev->id; + ctrl = get_fimc_ctrl(id); + + while (*p != '\0') { + if (!isspace(*p)) + strncat(msg, p, 1); + p++; + } + + ctrl->log = 0; + printk(KERN_INFO "FIMC.%d log level is set as below.\n", id); + + if (strstr(msg, "FIMC_LOG_ERR") != NULL) { + ctrl->log |= FIMC_LOG_ERR; + match = 1; + printk(KERN_INFO "\tFIMC_LOG_ERR\n"); + } + + if (strstr(msg, "FIMC_LOG_WARN") != NULL) { + ctrl->log |= FIMC_LOG_WARN; + match = 1; + printk(KERN_INFO "\tFIMC_LOG_WARN\n"); + } + + if (strstr(msg, "FIMC_LOG_INFO_L1") != NULL) { + ctrl->log |= FIMC_LOG_INFO_L1; + match = 1; + printk(KERN_INFO "\tFIMC_LOG_INFO_L1\n"); + } + + if (strstr(msg, "FIMC_LOG_INFO_L2") != NULL) { + ctrl->log |= FIMC_LOG_INFO_L2; + match = 1; + printk(KERN_INFO "\tFIMC_LOG_INFO_L2\n"); + } + + if (strstr(msg, "FIMC_LOG_DEBUG") != NULL) { + ctrl->log |= FIMC_LOG_DEBUG; + match = 1; + printk(KERN_INFO "\tFIMC_LOG_DEBUG\n"); + } + + if (!match) { + printk(KERN_INFO "FIMC_LOG_ERR \t: Error condition.\n"); + printk(KERN_INFO "FIMC_LOG_WARN \t: WARNING condition.\n"); + printk(KERN_INFO "FIMC_LOG_INFO_L1 \t: V4L2 API without QBUF, DQBUF.\n"); + printk(KERN_INFO "FIMC_LOG_INFO_L2 \t: V4L2 API QBUF, DQBUF.\n"); + printk(KERN_INFO "FIMC_LOG_DEBUG \t: Queue status report.\n"); + } + + return len; +} + +static DEVICE_ATTR(log_level, 0644, \ + fimc_show_log_level, + fimc_store_log_level); + +static int __devinit fimc_probe(struct platform_device *pdev) +{ + struct s3c_platform_fimc *pdata; + struct fimc_control *ctrl; + struct clk *srclk; + int ret; + + if (!fimc_dev) { + fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL); + if (!fimc_dev) { + dev_err(&pdev->dev, "%s: not enough memory\n", + __func__); + return -ENOMEM; + } + } + + ctrl = fimc_register_controller(pdev); + if (!ctrl) { + printk(KERN_ERR "%s: cannot register fimc\n", __func__); + goto err_alloc; + } + + pdata = to_fimc_plat(&pdev->dev); + if (pdata->cfg_gpio) + pdata->cfg_gpio(pdev); + + /* Get fimc power domain regulator */ + ctrl->regulator = regulator_get(&pdev->dev, "pd"); + if (IS_ERR(ctrl->regulator)) { + fimc_err("%s: failed to get resource %s\n", + __func__, "s3c-fimc"); + return PTR_ERR(ctrl->regulator); + } + + /* fimc source clock */ + srclk = clk_get(&pdev->dev, pdata->srclk_name); + if (IS_ERR(srclk)) { + fimc_err("%s: failed to get source clock of fimc\n", + __func__); + goto err_v4l2; + } + + /* fimc clock */ + ctrl->clk = clk_get(&pdev->dev, pdata->clk_name); + if (IS_ERR(ctrl->clk)) { + fimc_err("%s: failed to get fimc clock source\n", + __func__); + goto err_v4l2; + } + + /* set parent for mclk */ + clk_set_parent(ctrl->clk, srclk); + + /* set rate for mclk */ + clk_set_rate(ctrl->clk, pdata->clk_rate); + + /* V4L2 device-subdev registration */ + ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev); + if (ret) { + fimc_err("%s: v4l2 device register failed\n", __func__); + goto err_fimc; + } + + /* things to initialize once */ + if (!fimc_dev->initialized) { + ret = fimc_init_global(pdev); + if (ret) + goto err_v4l2; + } + + /* video device register */ + ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id); + if (ret) { + fimc_err("%s: cannot register video driver\n", __func__); + goto err_v4l2; + } + + video_set_drvdata(ctrl->vd, ctrl); + + ret = device_create_file(&(pdev->dev), &dev_attr_log_level); + if (ret < 0) { + fimc_err("failed to add sysfs entries\n"); + goto err_global; + } + printk(KERN_INFO "FIMC%d registered successfully\n", ctrl->id); + + return 0; + +err_global: + video_unregister_device(ctrl->vd); + +err_v4l2: + v4l2_device_unregister(&ctrl->v4l2_dev); + +err_fimc: + fimc_unregister_controller(pdev); + +err_alloc: + kfree(fimc_dev); + return -EINVAL; + +} + +static int fimc_remove(struct platform_device *pdev) +{ + fimc_unregister_controller(pdev); + + device_remove_file(&(pdev->dev), &dev_attr_log_level); + + kfree(fimc_dev); + fimc_dev = NULL; + + return 0; +} + +#ifdef CONFIG_PM +static inline void fimc_suspend_out_ctx(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: /* fall through */ + case FIMC_OVLY_NONE_MULTI_BUF: /* fall through */ + case FIMC_OVLY_NONE_SINGLE_BUF: + if (ctx->status == FIMC_STREAMON) { + if (ctx->inq[0] != -1) + fimc_err("%s : %d in queue unstable\n", + __func__, __LINE__); + + fimc_outdev_stop_streaming(ctrl, ctx); + ctx->status = FIMC_ON_SLEEP; + } else if (ctx->status == FIMC_STREAMON_IDLE) { + fimc_outdev_stop_streaming(ctrl, ctx); + ctx->status = FIMC_ON_IDLE_SLEEP; + } else { + ctx->status = FIMC_OFF_SLEEP; + } + + break; + case FIMC_OVLY_NOT_FIXED: + ctx->status = FIMC_OFF_SLEEP; + break; + } +} + +static inline int fimc_suspend_out(struct fimc_control *ctrl) +{ + struct fimc_ctx *ctx; + int i, on_sleep = 0, idle_sleep = 0, off_sleep = 0; + + for (i = 0; i < FIMC_MAX_CTXS; i++) { + ctx = &ctrl->out->ctx[i]; + fimc_suspend_out_ctx(ctrl, ctx); + + switch (ctx->status) { + case FIMC_ON_SLEEP: + on_sleep++; + break; + case FIMC_ON_IDLE_SLEEP: + idle_sleep++; + break; + case FIMC_OFF_SLEEP: + off_sleep++; + break; + default: + break; + } + } + + if (on_sleep) + ctrl->status = FIMC_ON_SLEEP; + else if (idle_sleep) + ctrl->status = FIMC_ON_IDLE_SLEEP; + else + ctrl->status = FIMC_OFF_SLEEP; + + ctrl->out->last_ctx = -1; + + return 0; +} + +static inline int fimc_suspend_cap(struct fimc_control *ctrl) +{ + if (ctrl->cam->id == CAMERA_WB && ctrl->status == FIMC_STREAMON) + fimc_streamoff_capture((void *)ctrl); + ctrl->status = FIMC_ON_SLEEP; + + return 0; +} + +int fimc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct fimc_control *ctrl; + struct s3c_platform_fimc *pdata; + int id; + + id = pdev->id; + ctrl = get_fimc_ctrl(id); + pdata = to_fimc_plat(ctrl->dev); + + if (ctrl->out) + fimc_suspend_out(ctrl); + else if (ctrl->cap) + fimc_suspend_cap(ctrl); + else + ctrl->status = FIMC_OFF_SLEEP; + + if (atomic_read(&ctrl->in_use) && ctrl->status != FIMC_OFF_SLEEP) + fimc_clk_en(ctrl, false); + + return 0; +} + +static inline void fimc_resume_out_ctx(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + int ret = -1; + + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: + if (ctx->status == FIMC_ON_IDLE_SLEEP) { + fimc_outdev_resume_dma(ctrl, ctx); + ret = fimc_outdev_set_ctx_param(ctrl, ctx); + if (ret < 0) + fimc_err("Fail: fimc_outdev_set_ctx_param\n"); + + ctx->status = FIMC_STREAMON_IDLE; + } else if (ctx->status == FIMC_OFF_SLEEP) { + ctx->status = FIMC_STREAMOFF; + } else { + fimc_err("%s: Abnormal (%d)\n", __func__, ctx->status); + } + + break; + case FIMC_OVLY_DMA_MANUAL: + if (ctx->status == FIMC_ON_IDLE_SLEEP) { + ret = fimc_outdev_set_ctx_param(ctrl, ctx); + if (ret < 0) + fimc_err("Fail: fimc_outdev_set_ctx_param\n"); + + ctx->status = FIMC_STREAMON_IDLE; + + } else if (ctx->status == FIMC_OFF_SLEEP) { + ctx->status = FIMC_STREAMOFF; + } else { + fimc_err("%s: Abnormal (%d)\n", __func__, ctx->status); + } + + break; + case FIMC_OVLY_NONE_SINGLE_BUF: /* fall through */ + case FIMC_OVLY_NONE_MULTI_BUF: + if (ctx->status == FIMC_ON_IDLE_SLEEP) { + ret = fimc_outdev_set_ctx_param(ctrl, ctx); + if (ret < 0) + fimc_err("Fail: fimc_outdev_set_ctx_param\n"); + + ctx->status = FIMC_STREAMON_IDLE; + } else if (ctx->status == FIMC_OFF_SLEEP) { + ctx->status = FIMC_STREAMOFF; + } else { + fimc_err("%s: Abnormal (%d)\n", __func__, ctx->status); + } + + break; + default: + ctx->status = FIMC_STREAMOFF; + break; + } +} + +static inline int fimc_resume_out(struct fimc_control *ctrl) +{ + struct fimc_ctx *ctx; + int i; + u32 state = 0; + + for (i = 0; i < FIMC_MAX_CTXS; i++) { + ctx = &ctrl->out->ctx[i]; + fimc_resume_out_ctx(ctrl, ctx); + + switch (ctx->status) { + case FIMC_STREAMON: + state |= FIMC_STREAMON; + break; + case FIMC_STREAMON_IDLE: + state |= FIMC_STREAMON_IDLE; + break; + case FIMC_STREAMOFF: + state |= FIMC_STREAMOFF; + break; + default: + break; + } + } + + if ((state & FIMC_STREAMON) == FIMC_STREAMON) + ctrl->status = FIMC_STREAMON; + else if ((state & FIMC_STREAMON_IDLE) == FIMC_STREAMON_IDLE) + ctrl->status = FIMC_STREAMON_IDLE; + else + ctrl->status = FIMC_STREAMOFF; + + return 0; +} + +static inline int fimc_resume_cap(struct fimc_control *ctrl) +{ + if (ctrl->cam->id == CAMERA_WB) + fimc_streamon_capture((void *)ctrl); + + return 0; +} + +int fimc_resume(struct platform_device *pdev) +{ + struct fimc_control *ctrl; + struct s3c_platform_fimc *pdata; + int id = pdev->id; + + ctrl = get_fimc_ctrl(id); + pdata = to_fimc_plat(ctrl->dev); + + if (atomic_read(&ctrl->in_use) && ctrl->status != FIMC_OFF_SLEEP) + fimc_clk_en(ctrl, true); + + if (ctrl->out) + fimc_resume_out(ctrl); + else if (ctrl->cap) + fimc_resume_cap(ctrl); + else + ctrl->status = FIMC_STREAMOFF; + + return 0; +} +#else +#define fimc_suspend NULL +#define fimc_resume NULL +#endif + +static struct platform_driver fimc_driver = { + .probe = fimc_probe, + .remove = fimc_remove, + .suspend = fimc_suspend, + .resume = fimc_resume, + .driver = { + .name = FIMC_NAME, + .owner = THIS_MODULE, + }, +}; + +static int fimc_register(void) +{ + platform_driver_register(&fimc_driver); + + return 0; +} + +static void fimc_unregister(void) +{ + platform_driver_unregister(&fimc_driver); +} + +late_initcall(fimc_register); +module_exit(fimc_unregister); + +MODULE_AUTHOR("Dongsoo, Kim <dongsoo45.kim@samsung.com>"); +MODULE_AUTHOR("Jinsung, Yang <jsgood.yang@samsung.com>"); +MODULE_AUTHOR("Jonghun, Han <jonghun.han@samsung.com>"); +MODULE_DESCRIPTION("Samsung Camera Interface (FIMC) driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/samsung/fimc/fimc_output.c b/drivers/media/video/samsung/fimc/fimc_output.c new file mode 100644 index 0000000..ebae1ad --- /dev/null +++ b/drivers/media/video/samsung/fimc/fimc_output.c @@ -0,0 +1,2563 @@ +/* linux/drivers/media/video/samsung/fimc/fimc_output.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * V4L2 Output device support file for Samsung Camera Interface (FIMC) 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/slab.h> +#include <linux/bootmem.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/mm.h> +#include <linux/videodev2.h> +#include <linux/videodev2_samsung.h> +#include <media/videobuf-core.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/mman.h> +#include <plat/media.h> +#include <linux/clk.h> + +#include "fimc.h" + +static __u32 fimc_get_pixel_format_type(__u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_RGB565: + return FIMC_RGB; + + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YUV420: + return FIMC_YUV420; + + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_YUV422P: + return FIMC_YUV422; + + default: + return FIMC_YUV444; + } +} + +void fimc_outdev_set_src_addr(struct fimc_control *ctrl, dma_addr_t *base) +{ + fimc_hwset_addr_change_disable(ctrl); + fimc_hwset_input_address(ctrl, base); + fimc_hwset_addr_change_enable(ctrl); +} + +int fimc_outdev_start_camif(void *param) +{ + struct fimc_control *ctrl = (struct fimc_control *)param; + + fimc_hwset_start_scaler(ctrl); + fimc_hwset_enable_capture(ctrl, 0); /* bypass disable */ + fimc_hwset_start_input_dma(ctrl); + + return 0; +} + +static int fimc_outdev_stop_camif(void *param) +{ + struct fimc_control *ctrl = (struct fimc_control *)param; + + fimc_hwset_stop_input_dma(ctrl); + fimc_hwset_disable_autoload(ctrl); + fimc_hwset_stop_scaler(ctrl); + fimc_hwset_disable_capture(ctrl); + fimc_hwset_sw_reset(ctrl); + + fimc_clk_en(ctrl, false); + return 0; +} + +int fimc_outdev_stop_streaming(struct fimc_control *ctrl, struct fimc_ctx *ctx) +{ + int ret = 0; + + fimc_dbg("%s: called\n", __func__); + + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: + if (ctx->status == FIMC_STREAMON_IDLE) + ctx->status = FIMC_STREAMOFF; + else + ctx->status = FIMC_READY_OFF; + break; + case FIMC_OVLY_NONE_SINGLE_BUF: /* fall through */ + case FIMC_OVLY_NONE_MULTI_BUF: + if (ctx->status == FIMC_STREAMON_IDLE) + ctx->status = FIMC_STREAMOFF; + else + ctx->status = FIMC_READY_OFF; + ret = wait_event_timeout(ctrl->wq, + (ctx->status == FIMC_STREAMOFF), + FIMC_ONESHOT_TIMEOUT); + if (ret == 0) { + fimc_dump_context(ctrl, ctx); + fimc_err("fail %s: %d\n", __func__, ctx->ctx_num); + } + + break; + default: + break; + } + + return 0; +} + +int fimc_outdev_resume_dma(struct fimc_control *ctrl, struct fimc_ctx *ctx) +{ + struct v4l2_rect fimd_rect; + struct fb_var_screeninfo var; + struct fb_info *fbinfo; + struct s3cfb_window *win; + int ret = -1, idx; + + fbinfo = registered_fb[ctx->overlay.fb_id]; + win = (struct s3cfb_window *)fbinfo->par; + + memcpy(&var, &fbinfo->var, sizeof(struct fb_var_screeninfo)); + memset(&fimd_rect, 0, sizeof(struct v4l2_rect)); + ret = fimc_fimd_rect(ctrl, ctx, &fimd_rect); + if (ret < 0) { + fimc_err("fimc_fimd_rect fail\n"); + return -EINVAL; + } + + /* set window path & owner */ + win->path = DATA_PATH_DMA; + win->owner = DMA_MEM_OTHER; + win->other_mem_addr = ctx->dst[1].base[FIMC_ADDR_Y]; + win->other_mem_size = ctx->dst[1].length[FIMC_ADDR_Y]; + + /* Update WIN size */ + var.xres_virtual = fimd_rect.width; + var.yres_virtual = fimd_rect.height; + var.xres = fimd_rect.width; + var.yres = fimd_rect.height; + + /* Update WIN position */ + win->x = fimd_rect.left; + win->y = fimd_rect.top; + + var.activate = FB_ACTIVATE_FORCE; + ret = fb_set_var(fbinfo, &var); + if (ret < 0) { + fimc_err("fb_set_var fail (ret=%d)\n", ret); + return -EINVAL; + } + + idx = ctx->outq[0]; + if (idx == -1) { + fimc_err("out going queue is empty.\n"); + return -EINVAL; + } + + win->other_mem_addr = ctx->dst[idx].base[FIMC_ADDR_Y]; + ret = fb_pan_display(fbinfo, &fbinfo->var); + if (ret < 0) { + fimc_err("%s: fb_pan_display fail (ret=%d)\n", __func__, ret); + return -EINVAL; + } + + ctrl->fb.is_enable = 1; + + return 0; +} + +static void fimc_init_out_buf(struct fimc_ctx *ctx) +{ + int i; + + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->src[i].state = VIDEOBUF_IDLE; + ctx->src[i].flags = 0x0; + + ctx->inq[i] = -1; + ctx->outq[i] = -1; + } +} + +static int fimc_outdev_set_src_buf(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + u32 width = ctx->pix.width; + u32 height = ctx->pix.height; + u32 format = ctx->pix.pixelformat; + u32 y_size = width * height; + u32 cb_size = 0, cr_size = 0; + u32 i, size; + dma_addr_t *curr = &ctrl->mem.curr; + + switch (format) { + case V4L2_PIX_FMT_RGB32: + size = PAGE_ALIGN(y_size << 2); + break; + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_YUYV: + size = PAGE_ALIGN(y_size << 1); + break; + case V4L2_PIX_FMT_YUV420: + cb_size = y_size >> 2; + cr_size = y_size >> 2; + size = PAGE_ALIGN(y_size + cb_size + cr_size); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + cb_size = y_size >> 1; + size = PAGE_ALIGN(y_size + cb_size); + break; + case V4L2_PIX_FMT_NV12T: + fimc_get_nv12t_size(width, height, &y_size, &cb_size, 0); + size = PAGE_ALIGN(y_size + cb_size); + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + cb_size = y_size; + size = PAGE_ALIGN(y_size + cb_size); + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", __func__, format); + return -EINVAL; + } + + if ((*curr + size * FIMC_OUTBUFS) > (ctrl->mem.base + ctrl->mem.size)) { + fimc_err("%s: Reserved memory is not sufficient\n", __func__); + return -EINVAL; + } + + /* Initialize source buffer addr */ + switch (format) { + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_RGB32: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_YUYV: + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->src[i].base[FIMC_ADDR_Y] = *curr; + ctx->src[i].length[FIMC_ADDR_Y] = size; + ctx->src[i].base[FIMC_ADDR_CB] = 0; + ctx->src[i].length[FIMC_ADDR_CB] = 0; + ctx->src[i].base[FIMC_ADDR_CR] = 0; + ctx->src[i].length[FIMC_ADDR_CR] = 0; + *curr += size; + } + break; + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: /* fall through */ + case V4L2_PIX_FMT_NV12T: + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->src[i].base[FIMC_ADDR_Y] = *curr; + ctx->src[i].length[FIMC_ADDR_Y] = y_size; + ctx->src[i].base[FIMC_ADDR_CB] = *curr + y_size; + ctx->src[i].length[FIMC_ADDR_CB] = cb_size; + ctx->src[i].base[FIMC_ADDR_CR] = 0; + ctx->src[i].length[FIMC_ADDR_CR] = 0; + *curr += size; + } + break; + case V4L2_PIX_FMT_YUV420: + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->src[i].base[FIMC_ADDR_Y] = *curr; + ctx->src[i].base[FIMC_ADDR_CB] = *curr + y_size; + ctx->src[i].base[FIMC_ADDR_CR] = *curr + y_size + + cb_size; + ctx->src[i].length[FIMC_ADDR_Y] = y_size; + ctx->src[i].length[FIMC_ADDR_CB] = cb_size; + ctx->src[i].length[FIMC_ADDR_CR] = cr_size; + *curr += size; + } + break; + + default: + fimc_err("%s: Invalid pixelformt : %d\n", __func__, format); + return -EINVAL; + } + + return 0; +} + +static int fimc_outdev_set_dst_buf(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + dma_addr_t *curr = &ctrl->mem.curr; + dma_addr_t end; + u32 width = ctrl->fb.lcd_hres; + u32 height = ctrl->fb.lcd_vres; + u32 i, size; + + end = ctrl->mem.base + ctrl->mem.size; + size = PAGE_ALIGN(width * height * 4); + + if ((*curr + (size * FIMC_OUTBUFS)) > end) { + fimc_err("%s: Reserved memory is not sufficient\n", __func__); + return -EINVAL; + } + + /* Initialize destination buffer addr */ + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->dst[i].base[FIMC_ADDR_Y] = *curr; + ctx->dst[i].length[FIMC_ADDR_Y] = size; + ctx->dst[i].base[FIMC_ADDR_CB] = 0; + ctx->dst[i].length[FIMC_ADDR_CB] = 0; + ctx->dst[i].base[FIMC_ADDR_CR] = 0; + ctx->dst[i].length[FIMC_ADDR_CR] = 0; + *curr += size; + } + + return 0; +} + +static int fimc_set_rot_degree(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + int degree) +{ + switch (degree) { + case 0: /* fall through */ + case 90: /* fall through */ + case 180: /* fall through */ + case 270: + ctx->rotate = degree; + break; + + default: + fimc_err("Invalid rotate value : %d\n", degree); + return -EINVAL; + } + + return 0; +} + +int fimc_outdev_check_param(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct v4l2_rect dst, bound; + u32 rot = 0; + int ret = 0, i, exclusive = 0; + + rot = fimc_mapping_rot_flip(ctx->rotate, ctx->flip); + dst.top = ctx->win.w.top; + dst.left = ctx->win.w.left; + dst.width = ctx->win.w.width; + dst.height = ctx->win.w.height; + + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: + if (rot & FIMC_ROT) { + bound.width = ctrl->fb.lcd_vres; + bound.height = ctrl->fb.lcd_hres; + } else { + bound.width = ctrl->fb.lcd_hres; + bound.height = ctrl->fb.lcd_vres; + } + break; + case FIMC_OVLY_NONE_SINGLE_BUF: /* fall through */ + case FIMC_OVLY_NONE_MULTI_BUF: + bound.width = ctx->fbuf.fmt.width; + bound.height = ctx->fbuf.fmt.height; + break; + + default: + fimc_err("%s: invalid ovelay mode.\n", __func__); + return -EINVAL; + } + + if ((dst.left + dst.width) > bound.width) { + fimc_err("Horizontal position setting is failed\n"); + fimc_err("\tleft = %d, width = %d, bound width = %d,\n", + dst.left, dst.width, bound.width); + ret = -EINVAL; + } else if ((dst.top + dst.height) > bound.height) { + fimc_err("Vertical position setting is failed\n"); + fimc_err("\ttop = %d, height = %d, bound height = %d,\n", + dst.top, dst.height, bound.height); + ret = -EINVAL; + } + + if ((ctx->status != FIMC_STREAMOFF) && + (ctx->status != FIMC_READY_ON) && + (ctx->status != FIMC_ON_IDLE_SLEEP)) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + /* check other open instance */ + for (i = 0; i < FIMC_MAX_CTXS; i++) { + switch (ctrl->out->ctx[i].overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: + exclusive++; + break; + case FIMC_OVLY_NONE_SINGLE_BUF: /* fall through */ + case FIMC_OVLY_NONE_MULTI_BUF: /* fall through */ + case FIMC_OVLY_NOT_FIXED: + break; + } + } + + if (exclusive > 1) { + for (i = 0; i < FIMC_MAX_CTXS; i++) + fimc_err("%s: ctx %d mode = %d", __func__, i, + ctrl->out->ctx[i].overlay.mode); + return -EBUSY; + } + + return ret; +} + +static void fimc_outdev_set_src_format(struct fimc_control *ctrl, + u32 pixfmt, enum v4l2_field field) +{ + fimc_hwset_input_burst_cnt(ctrl, 4); + fimc_hwset_input_colorspace(ctrl, pixfmt); + fimc_hwset_input_yuv(ctrl, pixfmt); + fimc_hwset_input_rgb(ctrl, pixfmt); + fimc_hwset_intput_field(ctrl, field); + fimc_hwset_ext_rgb(ctrl, 1); + fimc_hwset_input_addr_style(ctrl, pixfmt); +} + +static void fimc_outdev_set_dst_format(struct fimc_control *ctrl, + struct v4l2_pix_format *pixfmt) +{ + fimc_hwset_output_colorspace(ctrl, pixfmt->pixelformat); + fimc_hwset_output_yuv(ctrl, pixfmt->pixelformat); + fimc_hwset_output_rgb(ctrl, pixfmt->pixelformat); + fimc_hwset_output_scan(ctrl, pixfmt); + fimc_hwset_output_addr_style(ctrl, pixfmt->pixelformat); +} + +static void fimc_outdev_set_format(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct v4l2_pix_format pixfmt; + memset(&pixfmt, 0, sizeof(pixfmt)); + + fimc_outdev_set_src_format(ctrl, ctx->pix.pixelformat, ctx->pix.field); + + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: /* Non-destructive overlay mode */ + if (ctx->pix.field == V4L2_FIELD_NONE) { + pixfmt.pixelformat = V4L2_PIX_FMT_RGB32; + pixfmt.field = V4L2_FIELD_NONE; + } else if (ctx->pix.field == V4L2_FIELD_INTERLACED_TB) { + pixfmt.pixelformat = V4L2_PIX_FMT_YUV444; + pixfmt.field = V4L2_FIELD_INTERLACED_TB; + } else if (ctx->pix.field == V4L2_FIELD_ANY) { + pixfmt.pixelformat = V4L2_PIX_FMT_RGB32; + pixfmt.field = V4L2_FIELD_NONE; + } + + break; + case FIMC_OVLY_NONE_SINGLE_BUF: /* fall through */ + case FIMC_OVLY_NONE_MULTI_BUF: /* Destructive overlay mode */ + pixfmt.pixelformat = ctx->fbuf.fmt.pixelformat; + pixfmt.field = V4L2_FIELD_NONE; + + break; + default: + fimc_err("Invalid overlay mode %d\n", ctx->overlay.mode); + break; + } + + fimc_outdev_set_dst_format(ctrl, &pixfmt); +} + +static void fimc_outdev_set_path(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + /* source path */ + fimc_hwset_input_source(ctrl, FIMC_SRC_MSDMA); + + fimc_hwset_disable_lcdfifo(ctrl); + fimc_hwset_disable_autoload(ctrl); +} + +static void fimc_outdev_set_rot(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + u32 rot = ctx->rotate; + u32 flip = ctx->flip; + + fimc_hwset_input_rot(ctrl, 0, 0); + fimc_hwset_input_flip(ctrl, 0, 0); + fimc_hwset_output_rot_flip(ctrl, rot, flip); +} + +static void fimc_outdev_set_src_dma_offset(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct v4l2_rect bound, crop; + u32 pixfmt = ctx->pix.pixelformat; + + bound.width = ctx->pix.width; + bound.height = ctx->pix.height; + + crop.left = ctx->crop.left; + crop.top = ctx->crop.top; + crop.width = ctx->crop.width; + crop.height = ctx->crop.height; + + fimc_hwset_input_offset(ctrl, pixfmt, &bound, &crop); +} + +static int fimc4x_outdev_check_src_size(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + struct v4l2_rect *real, + struct v4l2_rect *org) +{ + /* No Input Rotator */ + if (real->height < 8) { + fimc_err("SRC Real_H: Min 8\n"); + return -EINVAL; + } + + if (real->width < 16) { + fimc_err("SRC Real_W: Min 16\n"); + return -EINVAL; + } + + if (real->width > ctrl->limit->real_w_no_rot) { + fimc_err("SRC REAL_W: Real_W <= %d\n", + ctrl->limit->real_w_no_rot); + return -EINVAL; + } + + if (org->height < real->height) { + fimc_err("SRC Org_H: larger than Real_H\n"); + return -EINVAL; + } + + if (org->width < real->width) { + fimc_err("SRC Org_W: Org_W >= Real_W\n"); + return -EINVAL; + } + + if (ctx->sc.pre_vratio) { + if (real->height % ctx->sc.pre_vratio) { + fimc_err("SRC Real_H: multiple of pre_vratio!\n"); + return -EINVAL; + } + } + + if (real->width % 16) { + fimc_err("SRC Real_W: multiple of 16 !\n"); + return -EINVAL; + } + + if (ctx->sc.pre_hratio) { + if (real->width % (ctx->sc.pre_hratio * 4)) { + fimc_err("SRC Real_W: multiple of 4 * pre_hratio!\n"); + return -EINVAL; + } + } + + if (org->width % 16) { + fimc_err("SRC Org_W: multiple of 16\n"); + return -EINVAL; + } + + if (org->height < 8) { + fimc_err("SRC Org_H: Min 8\n"); + return -EINVAL; + } + + return 0; +} + +static int fimc50_outdev_check_src_size(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + struct v4l2_rect *real, + struct v4l2_rect *org) +{ + u32 pixelformat = ctx->pix.pixelformat; + + /* No Input Rotator */ + if (real->height < 8) { + fimc_err("SRC Real_H: Min 8\n"); + return -EINVAL; + } + + if (real->width < 16) { + fimc_err("SRC Real_W: Min 16\n"); + return -EINVAL; + } + + if (real->width > ctrl->limit->real_w_no_rot) { + fimc_err("SRC REAL_W: Real_W <= %d\n", + ctrl->limit->real_w_no_rot); + return -EINVAL; + } + + if (org->height < real->height) { + fimc_err("SRC Org_H: larger than Real_H\n"); + return -EINVAL; + } + + if (org->width < real->width) { + fimc_err("SRC Org_W: Org_W >= Real_W\n"); + return -EINVAL; + } + + if (ctx->pix.field == V4L2_FIELD_INTERLACED_TB) { + switch (pixelformat) { + case V4L2_PIX_FMT_YUV444: /* fall through */ + case V4L2_PIX_FMT_RGB32: + if (real->height % 2) { + fimc_err("SRC Real_H: multiple of 2\n"); + return -EINVAL; + } + case V4L2_PIX_FMT_YUV422P: + if (real->height % 2) { + fimc_err("SRC Real_H: multiple of 2\n"); + return -EINVAL; + } else if (real->width % 2) { + fimc_err("SRC Real_H: multiple of 2\n"); + return -EINVAL; + } + case V4L2_PIX_FMT_YVU420: + if (real->height % 4) { + fimc_err("SRC Real_H: multiple of 4\n"); + return -EINVAL; + } else if (real->width % 2) { + fimc_err("SRC Real_H: multiple of 2\n"); + return -EINVAL; + } + } + } else if (ctx->pix.field == V4L2_FIELD_NONE) { + if (pixelformat == V4L2_PIX_FMT_YUV422P) { + if (real->height % 2) { + fimc_err("SRC Real_H: multiple of 2\n"); + return -EINVAL; + } else if (real->width % 2) { + fimc_err("SRC Real_H: multiple of 2\n"); + return -EINVAL; + } + } + } + + return 0; +} + +static int fimc_outdev_set_src_dma_size(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + struct v4l2_rect real, org; + int ret = 0; + + real.width = ctx->crop.width; + real.height = ctx->crop.height; + org.width = ctx->pix.width; + org.height = ctx->pix.height; + + if (pdata->hw_ver == 0x50) + ret = fimc50_outdev_check_src_size(ctrl, ctx, &real, &org); + else + ret = fimc4x_outdev_check_src_size(ctrl, ctx, &real, &org); + + if (ret < 0) + return ret; + + fimc_hwset_org_input_size(ctrl, org.width, org.height); + fimc_hwset_real_input_size(ctrl, real.width, real.height); + + return 0; +} + +static void fimc_outdev_set_dst_dma_offset(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct v4l2_rect bound, win; + struct v4l2_rect *w = &ctx->win.w; + u32 pixfmt = ctx->fbuf.fmt.pixelformat; + + memset(&bound, 0, sizeof(bound)); + memset(&win, 0, sizeof(win)); + + switch (ctx->rotate) { + case 0: + bound.width = ctx->fbuf.fmt.width; + bound.height = ctx->fbuf.fmt.height; + + win.left = w->left; + win.top = w->top; + win.width = w->width; + win.height = w->height; + + break; + case 90: + bound.width = ctx->fbuf.fmt.height; + bound.height = ctx->fbuf.fmt.width; + + win.left = ctx->fbuf.fmt.height - (w->height + w->top); + win.top = w->left; + win.width = w->height; + win.height = w->width; + + break; + case 180: + bound.width = ctx->fbuf.fmt.width; + bound.height = ctx->fbuf.fmt.height; + + win.left = ctx->fbuf.fmt.width - (w->left + w->width); + win.top = ctx->fbuf.fmt.height - (w->top + w->height); + win.width = w->width; + win.height = w->height; + + break; + case 270: + bound.width = ctx->fbuf.fmt.height; + bound.height = ctx->fbuf.fmt.width; + + win.left = ctx->win.w.top; + win.top = ctx->fbuf.fmt.width - (w->left + w->width); + win.width = w->height; + win.height = w->width; + + break; + default: + fimc_err("Rotation degree is invalid\n"); + break; + } + + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: + memset(&bound, 0, sizeof(bound)); + memset(&win, 0, sizeof(win)); + fimc_hwset_output_offset(ctrl, pixfmt, &bound, &win); + break; + default: + fimc_hwset_output_offset(ctrl, pixfmt, &bound, &win); + break; + } + + fimc_dbg("bound:width(%d), height(%d)\n", bound.width, bound.height); + fimc_dbg("win:width(%d), height(%d)\n", win.width, win.height); + fimc_dbg("win:top(%d), left(%d)\n", win.top, win.left); +} + +static int fimc_outdev_check_dst_size(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + struct v4l2_rect *real, + struct v4l2_rect *org) +{ + u32 rot = ctx->rotate; + __u32 pixel_type; + + pixel_type = fimc_get_pixel_format_type(ctx->fbuf.fmt.pixelformat); + + if (FIMC_YUV420 == pixel_type && real->height % 2) { + fimc_err("DST Real_H: even number for YUV420 formats\n"); + return -EINVAL; + } + + if ((rot == 90) || (rot == 270)) { + /* Use Output Rotator */ + if (org->height < real->width) { + fimc_err("DST Org_H: Org_H(%d) >= Real_W(%d)\n", + org->height, real->width); + return -EINVAL; + } + + if (org->width < real->height) { + fimc_err("DST Org_W: Org_W(%d) >= Real_H(%d)\n", + org->width, real->height); + return -EINVAL; + } + + if (real->height > ctrl->limit->trg_h_rot) { + fimc_err("DST REAL_H: Real_H <= %d\n", + ctrl->limit->trg_h_rot); + return -EINVAL; + } + } else { + /* No Output Rotator */ + if (org->height < 8) { + fimc_err("DST Org_H: Min 8\n"); + return -EINVAL; + } + + if (org->height < real->height) { + fimc_err("DST Org_H: Org_H >= Real_H\n"); + return -EINVAL; + } + + if (org->width % 8) { + fimc_err("DST Org_W: multiple of 8\n"); + return -EINVAL; + } + + if (org->width < real->width) { + fimc_err("DST Org_W: Org_W >= Real_W\n"); + return -EINVAL; + } + + if (real->height > ctrl->limit->trg_h_no_rot) { + fimc_err("DST REAL_H: Real_H <= %d\n", + ctrl->limit->trg_h_no_rot); + return -EINVAL; + } + } + + return 0; +} + +static int fimc_outdev_set_dst_dma_size(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct v4l2_rect org, real; + int ret = -1; + + memset(&org, 0, sizeof(org)); + memset(&real, 0, sizeof(real)); + + switch (ctx->overlay.mode) { + case FIMC_OVLY_NONE_MULTI_BUF: /* fall through */ + case FIMC_OVLY_NONE_SINGLE_BUF: + real.width = ctx->win.w.width; + real.height = ctx->win.w.height; + + switch (ctx->rotate) { + case 0: /* fall through */ + case 180: + org.width = ctx->fbuf.fmt.width; + org.height = ctx->fbuf.fmt.height; + break; + case 90: /* fall through */ + case 270: + org.width = ctx->fbuf.fmt.height; + org.height = ctx->fbuf.fmt.width; + break; + default: + fimc_err("Rotation degree is invalid\n"); + break; + } + + break; + + case FIMC_OVLY_DMA_MANUAL: /* fall through */ + case FIMC_OVLY_DMA_AUTO: + real.width = ctx->win.w.width; + real.height = ctx->win.w.height; + + switch (ctx->rotate) { + case 0: /* fall through */ + case 180: + org.width = ctx->win.w.width; + org.height = ctx->win.w.height; + break; + case 90: /* fall through */ + case 270: + org.width = ctx->win.w.height; + org.height = ctx->win.w.width; + break; + default: + fimc_err("Rotation degree is invalid\n"); + break; + } + + break; + default: + break; + } + + fimc_dbg("DST org: width(%d), height(%d)\n", org.width, org.height); + fimc_dbg("DST real: width(%d), height(%d)\n", real.width, real.height); + + ret = fimc_outdev_check_dst_size(ctrl, ctx, &real, &org); + if (ret < 0) + return ret; + + fimc_hwset_output_size(ctrl, real.width, real.height); + fimc_hwset_output_area(ctrl, real.width, real.height); + fimc_hwset_org_output_size(ctrl, org.width, org.height); + fimc_hwset_ext_output_size(ctrl, real.width, real.height); + + return 0; +} + +static void fimc_outdev_calibrate_scale_info(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + struct v4l2_rect *src, + struct v4l2_rect *dst) +{ + /* OUTPUT ROTATOR */ + src->width = ctx->crop.width; + src->height = ctx->crop.height; + dst->width = ctx->win.w.width; + dst->height = ctx->win.w.height; + + fimc_dbg("src->width(%d), src->height(%d)\n", src->width, src->height); + fimc_dbg("dst->width(%d), dst->height(%d)\n", dst->width, dst->height); +} + +static int fimc_outdev_check_scaler(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + struct v4l2_rect *src, + struct v4l2_rect *dst) +{ + u32 pixels = 0, dstfmt = 0; + + /* Check scaler limitation */ + if (ctx->sc.pre_dst_width > ctrl->limit->pre_dst_w) { + fimc_err("FIMC%d : MAX PreDstWidth is %d\n", + ctrl->id, ctrl->limit->pre_dst_w); + return -EDOM; + } + + /* SRC width double boundary check */ + switch (ctx->pix.pixelformat) { + case V4L2_PIX_FMT_RGB32: + pixels = 1; + break; + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: /* fall through */ + case V4L2_PIX_FMT_RGB565: + pixels = 2; + break; + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV12T: + pixels = 8; + break; + default: + fimc_err("Invalid color format\n"); + return -EINVAL; + } + + if (src->width % pixels) { + fimc_err("source width multiple of %d pixels\n", pixels); + return -EDOM; + } + + /* DST width double boundary check */ + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: + dstfmt = V4L2_PIX_FMT_RGB32; + break; + case FIMC_OVLY_NONE_SINGLE_BUF: /* fall through */ + case FIMC_OVLY_NONE_MULTI_BUF: + dstfmt = ctx->fbuf.fmt.pixelformat; + break; + default: + break; + } + + switch (dstfmt) { + case V4L2_PIX_FMT_RGB32: + pixels = 1; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: + pixels = 2; + break; + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV12T: + pixels = 8; + break; + default: + fimc_err("Invalid color format\n"); + return -EINVAL; + } + + if (dst->width % pixels) { + fimc_err("source width multiple of %d pixels\n", pixels); + return -EDOM; + } + + return 0; +} + +static int fimc_outdev_set_scaler(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + struct v4l2_rect src, dst; + int ret = 0; + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + + memset(&src, 0, sizeof(src)); + memset(&dst, 0, sizeof(dst)); + + fimc_outdev_calibrate_scale_info(ctrl, ctx, &src, &dst); + + ret = fimc_get_scaler_factor(src.width, dst.width, + &ctx->sc.pre_hratio, &ctx->sc.hfactor); + if (ret < 0) { + fimc_err("Fail : Out of Width scale range\n"); + return ret; + } + + ret = fimc_get_scaler_factor(src.height, dst.height, + &ctx->sc.pre_vratio, &ctx->sc.vfactor); + if (ret < 0) { + fimc_err("Fail : Out of Height scale range\n"); + return ret; + } + + ctx->sc.pre_dst_width = src.width / ctx->sc.pre_hratio; + ctx->sc.pre_dst_height = src.height / ctx->sc.pre_vratio; + + if (pdata->hw_ver == 0x50) { + ctx->sc.main_hratio = (src.width << 14) / + (dst.width << ctx->sc.hfactor); + ctx->sc.main_vratio = (src.height << 14) / + (dst.height << ctx->sc.vfactor); + } else { + ctx->sc.main_hratio = (src.width << 8) / + (dst.width << ctx->sc.hfactor); + ctx->sc.main_vratio = (src.height << 8) / + (dst.height << ctx->sc.vfactor); + } + + fimc_dbg("pre_hratio(%d), hfactor(%d), pre_vratio(%d), vfactor(%d)\n", + ctx->sc.pre_hratio, ctx->sc.hfactor, + ctx->sc.pre_vratio, ctx->sc.vfactor); + + + fimc_dbg("pre_dst_width(%d), main_hratio(%d), " + "pre_dst_height(%d), main_vratio(%d)\n", + ctx->sc.pre_dst_width, ctx->sc.main_hratio, + ctx->sc.pre_dst_height, ctx->sc.main_vratio); + + ctx->sc.bypass = 0; /* Input DMA cannot support scaler bypass. */ + ctx->sc.scaleup_h = (dst.width >= src.width) ? 1 : 0; + ctx->sc.scaleup_v = (dst.height >= src.height) ? 1 : 0; + ctx->sc.shfactor = 10 - (ctx->sc.hfactor + ctx->sc.vfactor); + + if (pdata->hw_ver != 0x50) { + ret = fimc_outdev_check_scaler(ctrl, ctx, &src, &dst); + if (ret < 0) + return ret; + } + + fimc_hwset_prescaler(ctrl, &ctx->sc); + fimc_hwset_scaler(ctrl, &ctx->sc); + + return 0; +} + +int fimc_outdev_set_ctx_param(struct fimc_control *ctrl, struct fimc_ctx *ctx) +{ + int ret; + + if (ctrl->status == FIMC_READY_ON || ctrl->status == FIMC_STREAMON_IDLE) + fimc_hwset_enable_irq(ctrl, 0, 1); + + fimc_outdev_set_format(ctrl, ctx); + fimc_outdev_set_path(ctrl, ctx); + fimc_outdev_set_rot(ctrl, ctx); + + fimc_outdev_set_src_dma_offset(ctrl, ctx); + ret = fimc_outdev_set_src_dma_size(ctrl, ctx); + if (ret < 0) + return ret; + + fimc_outdev_set_dst_dma_offset(ctrl, ctx); + + ret = fimc_outdev_set_dst_dma_size(ctrl, ctx); + if (ret < 0) + return ret; + + ret = fimc_outdev_set_scaler(ctrl, ctx); + if (ret < 0) + return ret; + + return 0; +} + +int fimc_fimd_rect(const struct fimc_control *ctrl, + const struct fimc_ctx *ctx, + struct v4l2_rect *fimd_rect) +{ + switch (ctx->rotate) { + case 0: + fimd_rect->left = ctx->win.w.left; + fimd_rect->top = ctx->win.w.top; + fimd_rect->width = ctx->win.w.width; + fimd_rect->height = ctx->win.w.height; + + break; + + case 90: + fimd_rect->left = ctrl->fb.lcd_hres - + (ctx->win.w.top + ctx->win.w.height); + fimd_rect->top = ctx->win.w.left; + fimd_rect->width = ctx->win.w.height; + fimd_rect->height = ctx->win.w.width; + + break; + + case 180: + fimd_rect->left = ctrl->fb.lcd_hres - + (ctx->win.w.left + ctx->win.w.width); + fimd_rect->top = ctrl->fb.lcd_vres - + (ctx->win.w.top + ctx->win.w.height); + fimd_rect->width = ctx->win.w.width; + fimd_rect->height = ctx->win.w.height; + + break; + + case 270: + fimd_rect->left = ctx->win.w.top; + fimd_rect->top = ctrl->fb.lcd_vres - + (ctx->win.w.left + ctx->win.w.width); + fimd_rect->width = ctx->win.w.height; + fimd_rect->height = ctx->win.w.width; + + break; + + default: + fimc_err("Rotation degree is invalid\n"); + return -EINVAL; + + break; + } + + return 0; +} + +int fimc_outdev_overlay_buf(struct file *filp, + struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + int ret = 0, i; + struct fimc_overlay_buf *buf; + + buf = &ctx->overlay.buf; + + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->overlay.req_idx = i; + buf->size[i] = ctx->dst[i].length[0]; + buf->phy_addr[i] = ctx->dst[i].base[0]; + buf->vir_addr[i] = do_mmap(filp, 0, buf->size[i], + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + if (buf->vir_addr[i] == -EINVAL) { + fimc_err("%s: fail\n", __func__); + return -EINVAL; + } + + fimc_dbg("idx : %d, size(0x%08x), phy_addr(0x%08x), " + "vir_addr(0x%08x)\n", i, buf->size[i], + buf->phy_addr[i], buf->vir_addr[i]); + } + + ctx->overlay.req_idx = -1; + + return ret; +} + +int fimc_reqbufs_output(void *fh, struct v4l2_requestbuffers *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_ctx *ctx; + struct fimc_overlay_buf *buf; + struct mm_struct *mm = current->mm; + enum fimc_overlay_mode mode; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + int ret = -1, i; + + ctx = &ctrl->out->ctx[ctx_id]; + buf = &ctx->overlay.buf; + mode = ctx->overlay.mode; + + fimc_info1("%s: called\n", __func__); + + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + if (ctx->is_requested == 1 && b->count != 0) { + fimc_err("Buffers were already requested\n"); + return -EBUSY; + } + + if (b->count > FIMC_OUTBUFS) { + fimc_warn("The buffer count is modified by driver " + "from %d to %d\n", b->count, FIMC_OUTBUFS); + b->count = FIMC_OUTBUFS; + } + + fimc_init_out_buf(ctx); + ctx->is_requested = 0; + + if (b->count == 0) { + ctrl->mem.curr = ctrl->mem.base; + + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: /* fall through */ + case FIMC_OVLY_DMA_MANUAL: + for (i = 0; i < FIMC_OUTBUFS; i++) { + if (buf->vir_addr[i]) { + ret = do_munmap(mm, + buf->vir_addr[i], + buf->size[i]); + if (ret < 0) + fimc_err("%s: do_munmap fail. " + "vir_addr[%d](0x%08x)\n", + __func__, i, buf->vir_addr[i]); + } + } + break; + default: + break; + } + } else { + /* initialize source buffers */ + if (b->memory == V4L2_MEMORY_MMAP) { + ret = fimc_outdev_set_src_buf(ctrl, ctx); + ctx->overlay.req_idx = FIMC_MMAP_IDX; + if (ret) + return ret; + } else if (b->memory == V4L2_MEMORY_USERPTR) { + if (mode == FIMC_OVLY_DMA_AUTO) + ctx->overlay.req_idx = FIMC_USERPTR_IDX; + } + ctx->is_requested = 1; + } + + ctx->buf_num = b->count; + + return 0; +} + +int fimc_querybuf_output(void *fh, struct v4l2_buffer *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_ctx *ctx; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + u32 buf_length = 0; + + fimc_info1("%s: called\n", __func__); + + ctx = &ctrl->out->ctx[ctx_id]; + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + if (b->index >= ctx->buf_num) { + fimc_err("The index is out of bounds. You requested %d buffers." + "But requested index is %d\n", ctx->buf_num, b->index); + return -EINVAL; + } + + b->flags = ctx->src[b->index].flags; + b->m.offset = b->index * PAGE_SIZE; + buf_length = ctx->src[b->index].length[FIMC_ADDR_Y] + + ctx->src[b->index].length[FIMC_ADDR_CB] + + ctx->src[b->index].length[FIMC_ADDR_CR]; + b->length = PAGE_ALIGN(buf_length); + + return 0; +} + +int fimc_g_ctrl_output(void *fh, struct v4l2_control *c) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + ctx = &ctrl->out->ctx[ctx_id]; + + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + switch (c->id) { + case V4L2_CID_ROTATION: + c->value = ctx->rotate; + break; + + case V4L2_CID_HFLIP: + if (ctx->flip & V4L2_CID_HFLIP) + c->value = 1; + else + c->value = 0; + break; + + case V4L2_CID_VFLIP: + if (ctx->flip & V4L2_CID_VFLIP) + c->value = 1; + else + c->value = 0; + break; + + case V4L2_CID_OVERLAY_VADDR0: + c->value = ctx->overlay.buf.vir_addr[0]; + break; + + case V4L2_CID_OVERLAY_VADDR1: + c->value = ctx->overlay.buf.vir_addr[1]; + break; + + case V4L2_CID_OVERLAY_VADDR2: + c->value = ctx->overlay.buf.vir_addr[2]; + break; + + case V4L2_CID_OVERLAY_AUTO: + if (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO) + c->value = 1; + else + c->value = 0; + break; + + case V4L2_CID_RESERVED_MEM_BASE_ADDR: + c->value = ctrl->mem.base; + if (2 == ctrl->id) { + /* Clearing the buffer for FIMC-2 + * This is required because the same buffer is used + * for both Camcorder recording and HDMI display. + */ + char *fimc_mem = NULL; + fimc_mem = (char *) ioremap(ctrl->mem.base, \ + ctrl->mem.size); + if (fimc_mem) { + memset(fimc_mem, 0x00, ctrl->mem.size); + iounmap(fimc_mem); + } + } + break; + + case V4L2_CID_FIMC_VERSION: + c->value = pdata->hw_ver; + break; + + default: + fimc_err("Invalid control id: %d\n", c->id); + return -EINVAL; + } + + return 0; +} + +static int fimc_set_dst_info(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + struct fimc_buf *fimc_buf) +{ + struct fimc_buf *buf; + int i; + + for (i = 0; i < ctx->buf_num; i++) { + buf = &fimc_buf[i]; + + ctx->dst[i].base[FIMC_ADDR_Y] = buf->base[FIMC_ADDR_Y]; + ctx->dst[i].length[FIMC_ADDR_Y] = buf->length[FIMC_ADDR_Y]; + + ctx->dst[i].base[FIMC_ADDR_CB] = buf->base[FIMC_ADDR_CB]; + ctx->dst[i].length[FIMC_ADDR_CB] = buf->length[FIMC_ADDR_CB]; + + ctx->dst[i].base[FIMC_ADDR_CR] = buf->base[FIMC_ADDR_CR]; + ctx->dst[i].length[FIMC_ADDR_CR] = buf->length[FIMC_ADDR_CR]; + } + + for (i = ctx->buf_num; i < FIMC_OUTBUFS; i++) { + ctx->dst[i].base[FIMC_ADDR_Y] = 0; + ctx->dst[i].length[FIMC_ADDR_Y] = 0; + + ctx->dst[i].base[FIMC_ADDR_CB] = 0; + ctx->dst[i].length[FIMC_ADDR_CB] = 0; + + ctx->dst[i].base[FIMC_ADDR_CR] = 0; + ctx->dst[i].length[FIMC_ADDR_CR] = 0; + } + + /* for debugging */ + for (i = 0; i < FIMC_OUTBUFS; i++) { + fimc_dbg("dst[%d]: base[0]=0x%08x, size[0]=0x%08x\n", + i, ctx->dst[i].base[0], ctx->dst[i].length[0]); + + fimc_dbg("dst[%d]: base[1]=0x%08x, size[1]=0x%08x\n", + i, ctx->dst[i].base[1], ctx->dst[i].length[2]); + + fimc_dbg("dst[%d]: base[2]=0x%08x, size[2]=0x%08x\n", + i, ctx->dst[i].base[1], ctx->dst[i].length[2]); + } + + return 0; +} +int fimc_s_ctrl_output(struct file *filp, void *fh, struct v4l2_control *c) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + int ret = 0; + + ctx = &ctrl->out->ctx[ctx_id]; + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + switch (c->id) { + case V4L2_CID_ROTATION: + ret = fimc_set_rot_degree(ctrl, ctx, c->value); + + break; + case V4L2_CID_HFLIP: + if (c->value) + ctx->flip |= FIMC_XFLIP; + else + ctx->flip &= ~FIMC_XFLIP; + + break; + case V4L2_CID_VFLIP: + if (c->value) + ctx->flip |= FIMC_YFLIP; + else + ctx->flip &= ~FIMC_YFLIP; + + break; + case V4L2_CID_OVERLAY_AUTO: + if (c->value == 1) { + ctx->overlay.mode = FIMC_OVLY_DMA_AUTO; + } else { + ctx->overlay.mode = FIMC_OVLY_DMA_MANUAL; + ret = fimc_outdev_set_dst_buf(ctrl, ctx); + fimc_outdev_overlay_buf(filp, ctrl, ctx); + } + + break; + case V4L2_CID_OVLY_MODE: + ctx->overlay.mode = c->value; + + break; + case V4L2_CID_DST_INFO: + ret = fimc_set_dst_info(ctrl, ctx, + (struct fimc_buf *)c->value); + break; + default: + fimc_err("Invalid control id: %d\n", c->id); + ret = -EINVAL; + } + + return ret; +} + +int fimc_cropcap_output(void *fh, struct v4l2_cropcap *a) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + u32 is_rotate = 0, max_w = 0, max_h = 0, pixelformat; + + fimc_info1("%s: called\n", __func__); + + ctx = &ctrl->out->ctx[ctx_id]; + pixelformat = ctx->pix.pixelformat; + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + is_rotate = fimc_mapping_rot_flip(ctx->rotate, ctx->flip); + switch (pixelformat) { + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV12T: /* fall through */ + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: /* fall through */ + case V4L2_PIX_FMT_YUV420: + max_w = FIMC_SRC_MAX_W; + max_h = FIMC_SRC_MAX_H; + case V4L2_PIX_FMT_RGB32: /* fall through */ + case V4L2_PIX_FMT_RGB565: /* fall through */ + if (is_rotate & FIMC_ROT) { /* Landscape mode */ + max_w = ctrl->fb.lcd_vres; + max_h = ctrl->fb.lcd_hres; + } else { /* Portrait */ + max_w = ctrl->fb.lcd_hres; + max_h = ctrl->fb.lcd_vres; + } + + break; + default: + fimc_warn("Supported format : \ + V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, \ + V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_VYUY, \ + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV12T, \ + V4L2_PIX_FMT_NV21, V4L2_PIX_FMT_RGB32, \ + V4L2_PIX_FMT_RGB565\n"); + fimc_warn("%s: Received pixel format = %x\n", + __func__, pixelformat); + return -EINVAL; + } + + /* crop bounds */ + ctx->cropcap.bounds.left = 0; + ctx->cropcap.bounds.top = 0; + ctx->cropcap.bounds.width = max_w; + ctx->cropcap.bounds.height = max_h; + + /* crop default values */ + ctx->cropcap.defrect.left = 0; + ctx->cropcap.defrect.top = 0; + ctx->cropcap.defrect.width = max_w; + ctx->cropcap.defrect.height = max_h; + + /* crop pixel aspec values */ + /* To Do : Have to modify but I don't know the meaning. */ + ctx->cropcap.pixelaspect.numerator = 16; + ctx->cropcap.pixelaspect.denominator = 9; + + a->bounds = ctx->cropcap.bounds; + a->defrect = ctx->cropcap.defrect; + a->pixelaspect = ctx->cropcap.pixelaspect; + + return 0; +} + +int fimc_g_crop_output(void *fh, struct v4l2_crop *a) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + + ctx = &ctrl->out->ctx[ctx_id]; + + fimc_info1("%s: called\n", __func__); + + mutex_lock(&ctrl->v4l2_lock); + a->c.left = ctx->crop.left; + a->c.top = ctx->crop.top; + a->c.width = ctx->crop.width; + a->c.height = ctx->crop.height; + mutex_unlock(&ctrl->v4l2_lock); + + return 0; +} + +int fimc_s_crop_output(void *fh, struct v4l2_crop *a) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + + fimc_info1("%s: called: left(%d), top(%d), width(%d), height(%d),\n", + __func__, a->c.left, a->c.top, a->c.width, a->c.height); + + ctx = &ctrl->out->ctx[ctx_id]; + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + /* Check arguments : widht and height */ + if ((a->c.width < 0) || (a->c.height < 0)) { + fimc_err("The crop rect must be bigger than 0\n"); + return -EINVAL; + } + + if ((a->c.width > FIMC_SRC_MAX_W) || (a->c.height > FIMC_SRC_MAX_H)) { + fimc_err("The crop width/height must be smaller than " + "%d and %d\n", FIMC_SRC_MAX_W, FIMC_SRC_MAX_H); + return -EINVAL; + } + + /* Check arguments : left and top */ + if ((a->c.left < 0) || (a->c.top < 0)) { + fimc_err("The crop left, top must be bigger than 0\n"); + return -EINVAL; + } + + if ((a->c.left > FIMC_SRC_MAX_W) || (a->c.top > FIMC_SRC_MAX_H)) { + fimc_err("The crop left, top must be smaller than %d, %d\n", + FIMC_SRC_MAX_W, FIMC_SRC_MAX_H); + return -EINVAL; + } + + if ((a->c.left + a->c.width) > FIMC_SRC_MAX_W) { + fimc_err("The crop rect must be in bound rect\n"); + return -EINVAL; + } + + if ((a->c.top + a->c.height) > FIMC_SRC_MAX_H) { + fimc_err("The crop rect must be in bound rect\n"); + return -EINVAL; + } + + ctx->crop.left = a->c.left; + ctx->crop.top = a->c.top; + ctx->crop.width = a->c.width; + ctx->crop.height = a->c.height; + + return 0; +} + +int fimc_streamon_output(void *fh) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + int ret = -1; + + fimc_info1("%s: called\n", __func__); + + ctx = &ctrl->out->ctx[ctx_id]; + if (ctx->overlay.mode == FIMC_OVLY_NOT_FIXED) + ctx->overlay.mode = FIMC_OVLY_MODE; + + /* initialize destination buffers */ + if (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO) { + ret = fimc_outdev_set_dst_buf(ctrl, ctx); + if (ret) + return ret; + } + + ret = fimc_outdev_check_param(ctrl, ctx); + if (ret < 0) { + fimc_err("Fail: fimc_outdev_check_param\n"); + return ret; + } + + ctx->status = FIMC_READY_ON; + if (ctrl->status == FIMC_STREAMOFF) + ctrl->status = FIMC_READY_ON; + + return ret; +} + +void fimc_outdev_init_idxs(struct fimc_control *ctrl) +{ + ctrl->out->idxs.prev.ctx = -1; + ctrl->out->idxs.prev.idx = -1; + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + ctrl->out->idxs.next.ctx = -1; + ctrl->out->idxs.next.idx = -1; +} + +int fimc_streamoff_output(void *fh) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + int ret = -1, i = 0, off_cnt = 0; + + fimc_info1("%s: called\n", __func__); + + ctx = &ctrl->out->ctx[ctx_id]; + ret = fimc_outdev_stop_streaming(ctrl, ctx); + if (ret < 0) { + fimc_err("Fail: fimc_outdev_stop_streaming\n"); + return -EINVAL; + } + + ret = fimc_init_in_queue(ctrl, ctx); + if (ret < 0) { + fimc_err("Fail: fimc_init_in_queue\n"); + return -EINVAL; + } + + ret = fimc_init_out_queue(ctrl, ctx); + if (ret < 0) { + fimc_err("Fail: fimc_init_out_queue\n"); + return -EINVAL; + } + + /* Make all buffers DQUEUED state. */ + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->src[i].state = VIDEOBUF_IDLE; + ctx->src[i].flags = V4L2_BUF_FLAG_MAPPED; + } + + ctx->status = FIMC_STREAMOFF; + + if (ctrl->out->last_ctx == ctx->ctx_num) + ctrl->out->last_ctx = -1; + + if (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO) { + ctrl->mem.curr = ctx->dst[0].base[FIMC_ADDR_Y]; + + for (i = 0; i < FIMC_OUTBUFS; i++) { + ctx->dst[i].base[FIMC_ADDR_Y] = 0; + ctx->dst[i].length[FIMC_ADDR_Y] = 0; + + ctx->dst[i].base[FIMC_ADDR_CB] = 0; + ctx->dst[i].length[FIMC_ADDR_CB] = 0; + + ctx->dst[i].base[FIMC_ADDR_CR] = 0; + ctx->dst[i].length[FIMC_ADDR_CR] = 0; + } + } + + /* check all ctx to change ctrl->status from streamon to streamoff */ + for (i = 0; i < FIMC_MAX_CTXS; i++) { + if (ctrl->out->ctx[i].status == FIMC_STREAMOFF) + off_cnt++; + } + + if (off_cnt == FIMC_MAX_CTXS) { + ctrl->status = FIMC_STREAMOFF; + fimc_outdev_init_idxs(ctrl); + fimc_outdev_stop_camif(ctrl); + } + + if (ctx_id == ctrl->out->last_ctx) + ctrl->out->last_ctx = -1; + + mutex_lock(&ctrl->lock); + if (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO && ctrl->fb.is_enable == 1) { + fimc_info2("WIN_OFF for FIMC%d\n", ctrl->id); + ret = fb_blank(registered_fb[ctx->overlay.fb_id], + FB_BLANK_POWERDOWN); + if (ret < 0) { + fimc_err("%s: fb_blank: fb[%d] " \ + "mode=FB_BLANK_POWERDOWN\n", + __func__, ctx->overlay.fb_id); + mutex_unlock(&ctrl->lock); + return -EINVAL; + } + + ctrl->fb.is_enable = 0; + } + mutex_unlock(&ctrl->lock); + + return 0; +} + + +int fimc_output_set_dst_addr(struct fimc_control *ctrl, + struct fimc_ctx *ctx, int idx) +{ + struct fimc_buf_set buf_set; /* destination addr */ + u32 format = ctx->fbuf.fmt.pixelformat; + u32 width = ctx->fbuf.fmt.width; + u32 height = ctx->fbuf.fmt.height; + u32 y_size = width * height; + u32 c_size = y_size >> 2; + int i; + + memset(&buf_set, 0x00, sizeof(buf_set)); + + if (V4L2_PIX_FMT_NV12T == format) + fimc_get_nv12t_size(width, height, &y_size, &c_size, ctx->rotate); + + switch (format) { + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + if (ctx->overlay.mode == FIMC_OVLY_NONE_SINGLE_BUF) + buf_set.base[FIMC_ADDR_Y] = + (dma_addr_t)ctx->fbuf.base; + else + buf_set.base[FIMC_ADDR_Y] = + ctx->dst[idx].base[FIMC_ADDR_Y]; + break; + case V4L2_PIX_FMT_YUV420: + if (ctx->overlay.mode == FIMC_OVLY_NONE_SINGLE_BUF) { + buf_set.base[FIMC_ADDR_Y] = + (dma_addr_t)ctx->fbuf.base; + buf_set.base[FIMC_ADDR_CB] = + buf_set.base[FIMC_ADDR_Y] + y_size; + buf_set.base[FIMC_ADDR_CR] = + buf_set.base[FIMC_ADDR_CB] + c_size; + } else { + buf_set.base[FIMC_ADDR_Y] = + ctx->dst[idx].base[FIMC_ADDR_Y]; + buf_set.base[FIMC_ADDR_CB] = + ctx->dst[idx].base[FIMC_ADDR_CB]; + buf_set.base[FIMC_ADDR_CR] = + ctx->dst[idx].base[FIMC_ADDR_CR]; + } + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12T: + if (ctx->overlay.mode == FIMC_OVLY_NONE_SINGLE_BUF) { + buf_set.base[FIMC_ADDR_Y] = + (dma_addr_t)ctx->fbuf.base; + buf_set.base[FIMC_ADDR_CB] = + buf_set.base[FIMC_ADDR_Y] + y_size; + } else { + buf_set.base[FIMC_ADDR_Y] = + ctx->dst[idx].base[FIMC_ADDR_Y]; + buf_set.base[FIMC_ADDR_CB] = + ctx->dst[idx].base[FIMC_ADDR_CB]; + } + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", \ + __func__, format); + return -EINVAL; + } + + for (i = 0; i < FIMC_PHYBUFS; i++) + fimc_hwset_output_address(ctrl, &buf_set, i); + + return 0; +} + + +static int fimc_qbuf_output_single_buf(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + int idx) +{ + int ret = -1; + + fimc_outdev_set_src_addr(ctrl, ctx->src[idx].base); + + ret = fimc_output_set_dst_addr(ctrl, ctx, idx); + if (ret < 0) { + fimc_err("%s: Fail: fimc_output_set_dst_addr\n", __func__); + return -EINVAL; + } + + ctrl->out->idxs.active.idx = idx; + ctrl->out->idxs.active.ctx = ctx->ctx_num; + + ctrl->status = FIMC_STREAMON; + ctx->status = FIMC_STREAMON; + + ret = fimc_outdev_start_camif(ctrl); + if (ret < 0) { + fimc_err("Fail: fimc_start_camif\n"); + return -EINVAL; + } + + return 0; +} + +static int fimc_qbuf_output_multi_buf(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + int idx) +{ + int ret = -1; + + fimc_outdev_set_src_addr(ctrl, ctx->src[idx].base); + + fimc_output_set_dst_addr(ctrl, ctx, idx); + if (ret < 0) { + fimc_err("%s: Fail: fimc_output_set_dst_addr\n", __func__); + return -EINVAL; + } + + ret = fimc_outdev_start_camif(ctrl); + if (ret < 0) { + fimc_err("Fail: fimc_start_camif\n"); + return -EINVAL; + } + + ctrl->out->idxs.active.idx = idx; + ctrl->out->idxs.active.ctx = ctx->ctx_num; + + ctrl->status = FIMC_STREAMON; + ctx->status = FIMC_STREAMON; + + return 0; +} + +static int fimc_qbuf_output_dma_auto(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + int idx) +{ + struct fb_var_screeninfo var; + struct fb_info *fbinfo; + struct s3cfb_window *win; + struct v4l2_rect fimd_rect; + struct fimc_buf_set buf_set; /* destination addr */ + int ret = -1, i; + + switch (ctx->status) { + case FIMC_READY_ON: + fbinfo = registered_fb[ctx->overlay.fb_id]; + win = (struct s3cfb_window *)fbinfo->par; + + memcpy(&var, &fbinfo->var, sizeof(struct fb_var_screeninfo)); + memset(&fimd_rect, 0, sizeof(struct v4l2_rect)); + ret = fimc_fimd_rect(ctrl, ctx, &fimd_rect); + if (ret < 0) { + fimc_err("fimc_fimd_rect fail\n"); + return -EINVAL; + } + + /* set window path & owner */ + win->path = DATA_PATH_DMA; + win->owner = DMA_MEM_OTHER; + win->other_mem_addr = ctx->dst[1].base[FIMC_ADDR_Y]; + win->other_mem_size = ctx->dst[1].length[FIMC_ADDR_Y]; + + /* Update WIN size */ + var.xres_virtual = fimd_rect.width; + var.yres_virtual = fimd_rect.height; + var.xres = fimd_rect.width; + var.yres = fimd_rect.height; + + /* Update WIN position */ + win->x = fimd_rect.left; + win->y = fimd_rect.top; + + var.activate = FB_ACTIVATE_FORCE; + ret = fb_set_var(fbinfo, &var); + if (ret < 0) { + fimc_err("fb_set_var fail (ret=%d)\n", ret); + return -EINVAL; + } + + /* fall through */ + + case FIMC_STREAMON_IDLE: + fimc_outdev_set_src_addr(ctrl, ctx->src[idx].base); + + memset(&buf_set, 0x00, sizeof(buf_set)); + buf_set.base[FIMC_ADDR_Y] = ctx->dst[idx].base[FIMC_ADDR_Y]; + + for (i = 0; i < FIMC_PHYBUFS; i++) + fimc_hwset_output_address(ctrl, &buf_set, i); + + ret = fimc_outdev_start_camif(ctrl); + if (ret < 0) { + fimc_err("Fail: fimc_start_camif\n"); + return -EINVAL; + } + + ctrl->out->idxs.active.idx = idx; + ctrl->out->idxs.active.ctx = ctx->ctx_num; + + ctrl->status = FIMC_STREAMON; + ctx->status = FIMC_STREAMON; + + break; + + default: + break; + } + + return 0; +} + +static int fimc_qbuf_output_dma_manual(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + int idx) +{ + struct fimc_buf_set buf_set; /* destination addr */ + int ret = -1, i; + + fimc_outdev_set_src_addr(ctrl, ctx->src[idx].base); + + memset(&buf_set, 0x00, sizeof(buf_set)); + buf_set.base[FIMC_ADDR_Y] = ctx->dst[idx].base[FIMC_ADDR_Y]; + + for (i = 0; i < FIMC_PHYBUFS; i++) + fimc_hwset_output_address(ctrl, &buf_set, i); + + ret = fimc_outdev_start_camif(ctrl); + if (ret < 0) { + fimc_err("Fail: fimc_start_camif\n"); + return -EINVAL; + } + + ctrl->out->idxs.active.idx = idx; + ctrl->out->idxs.active.ctx = ctx->ctx_num; + + ctrl->status = FIMC_STREAMON; + ctx->status = FIMC_STREAMON; + + return 0; +} + +static int fimc_update_in_queue_addr(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + u32 idx, dma_addr_t *addr) +{ + if (idx >= FIMC_OUTBUFS) { + fimc_err("%s: Failed\n", __func__); + return -EINVAL; + } + + ctx->src[idx].base[FIMC_ADDR_Y] = addr[FIMC_ADDR_Y]; + ctx->src[idx].base[FIMC_ADDR_CB] = addr[FIMC_ADDR_CB]; + ctx->src[idx].base[FIMC_ADDR_CR] = addr[FIMC_ADDR_CR]; + + return 0; +} + +int fimc_qbuf_output(void *fh, struct v4l2_buffer *b) +{ + struct fimc_buf *buf = (struct fimc_buf *)b->m.userptr; + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + int idx, ctx_num; + int ret = -1; + + ctx = &ctrl->out->ctx[ctx_id]; + fimc_info2("ctx(%d) queued idx = %d\n", ctx->ctx_num, b->index); + + if (b->index >= ctx->buf_num) { + fimc_err("The index is out of bounds. " + "You requested %d buffers. " + "But you set the index as %d\n", + ctx->buf_num, b->index); + return -EINVAL; + } + + /* Check the buffer state if the state is VIDEOBUF_IDLE. */ + if (ctx->src[b->index].state != VIDEOBUF_IDLE) { + fimc_err("The index(%d) buffer must be dequeued state(%d)\n", + b->index, ctx->src[b->index].state); + return -EINVAL; + } + + if (b->memory == V4L2_MEMORY_USERPTR) { + ret = fimc_update_in_queue_addr(ctrl, ctx, b->index, buf->base); + if (ret < 0) + return ret; + } + + /* Attach the buffer to the incoming queue. */ + ret = fimc_push_inq(ctrl, ctx, b->index); + if (ret < 0) { + fimc_err("Fail: fimc_push_inq\n"); + return -EINVAL; + } + + if ((ctrl->status == FIMC_READY_ON) || + (ctrl->status == FIMC_STREAMON_IDLE)) { + ret = fimc_pop_inq(ctrl, &ctx_num, &idx); + if (ret < 0) { + fimc_err("Fail: fimc_pop_inq\n"); + return -EINVAL; + } + + fimc_clk_en(ctrl, true); + + ctx = &ctrl->out->ctx[ctx_num]; + if (ctx_num != ctrl->out->last_ctx) { + ctrl->out->last_ctx = ctx->ctx_num; + fimc_outdev_set_ctx_param(ctrl, ctx); + } + + switch (ctx->overlay.mode) { + case FIMC_OVLY_DMA_AUTO: + ret = fimc_qbuf_output_dma_auto(ctrl, ctx, idx); + break; + case FIMC_OVLY_DMA_MANUAL: + ret = fimc_qbuf_output_dma_manual(ctrl, ctx, idx); + break; + case FIMC_OVLY_NONE_SINGLE_BUF: + ret = fimc_qbuf_output_single_buf(ctrl, ctx, idx); + break; + case FIMC_OVLY_NONE_MULTI_BUF: + ret = fimc_qbuf_output_multi_buf(ctrl, ctx, idx); + break; + default: + break; + } + } + + return ret; +} + +int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b) +{ + struct fimc_ctx *ctx; + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + int idx = -1, ret = -1; + + ctx = &ctrl->out->ctx[ctx_id]; + ret = fimc_pop_outq(ctrl, ctx, &idx); + if (ret < 0) { + ret = wait_event_timeout(ctrl->wq, (ctx->outq[0] != -1), + FIMC_DQUEUE_TIMEOUT); + if (ret == 0) { + fimc_dump_context(ctrl, ctx); + fimc_err("[0] out_queue is empty\n"); + ctx->status = FIMC_STREAMON_IDLE; + return -EAGAIN; + } else if (ret == -ERESTARTSYS) { + fimc_print_signal(ctrl); + } else { + /* Normal case */ + ret = fimc_pop_outq(ctrl, ctx, &idx); + if (ret < 0) { + fimc_err("[1] out_queue is empty\n"); + fimc_dump_context(ctrl, ctx); + return -EINVAL; + } + } + } + + mutex_lock(&ctrl->lock); + if (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO && ctrl->fb.is_enable == 0) { + ret = fb_blank(registered_fb[ctx->overlay.fb_id], + FB_BLANK_UNBLANK); + if (ret < 0) { + fimc_err("%s: fb_blank: fb[%d] " \ + "mode=FB_BLANK_UNBLANK\n", + __func__, ctx->overlay.fb_id); + mutex_unlock(&ctrl->lock); + return -EINVAL; + } + ctrl->fb.is_enable = 1; + } + mutex_unlock(&ctrl->lock); + + b->index = idx; + + fimc_info2("ctx(%d) dqueued idx = %d\n", ctx->ctx_num, b->index); + + return ret; +} + +int fimc_g_fmt_vid_out(struct file *filp, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct fimc_outinfo *out = ctrl->out; + struct fimc_ctx *ctx; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + int i, j; + + fimc_info1("%s: called\n", __func__); + + if (ctrl->cap) { + fimc_err("%s: fimc is already used for capture mode\n", + __func__); + return -EINVAL; + } + + if (!out) { + out = kzalloc(sizeof(*out), GFP_KERNEL); + if (!out) { + fimc_err("%s: no memory for outdev info\n", __func__); + return -ENOMEM; + } + ctrl->out = out; + + /* init: struct fimc_outinfo */ + out->last_ctx = -1; + + spin_lock_init(&ctrl->out->lock_in); + spin_lock_init(&ctrl->out->lock_out); + + for (i = 0; i < FIMC_INQUEUES; i++) { + ctrl->out->inq[i].ctx = -1; + ctrl->out->inq[i].idx = -1; + } + + for (i = 0; i < FIMC_MAX_CTXS; i++) { + ctx = &ctrl->out->ctx[i]; + ctx->ctx_num = i; + ctx->overlay.mode = FIMC_OVLY_NOT_FIXED; + ctx->status = FIMC_STREAMOFF; + + for (j = 0; j < FIMC_OUTBUFS; j++) { + ctx->inq[j] = -1; + ctx->outq[j] = -1; + } + } + + ctrl->out->idxs.prev.ctx = -1; + ctrl->out->idxs.prev.idx = -1; + ctrl->out->idxs.active.ctx = -1; + ctrl->out->idxs.active.idx = -1; + ctrl->out->idxs.next.ctx = -1; + ctrl->out->idxs.next.idx = -1; + } + + f->fmt.pix = ctrl->out->ctx[ctx_id].pix; + + return 0; +} + +int fimc_try_fmt_vid_out(struct file *filp, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct fimc_ctx *ctx; + u32 format = f->fmt.pix.pixelformat; + + fimc_info1("%s: called. width(%d), height(%d)\n", __func__, + f->fmt.pix.width, f->fmt.pix.height); + + ctx = &ctrl->out->ctx[ctx_id]; + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + /* Check pixel format */ + switch (format) { + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: /* fall through */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV12T: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_RGB32: /* fall through */ + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_YUV420: + break; + default: + fimc_warn("Supported format : \ + V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, \ + V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_VYUY, \ + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV12T, \ + V4L2_PIX_FMT_NV21, V4L2_PIX_FMT_RGB32, \ + V4L2_PIX_FMT_RGB565\n"); + fimc_warn("Changed format : V4L2_PIX_FMT_RGB32\n"); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; + return -EINVAL; + } + + /* Fill the return value. */ + switch (format) { + case V4L2_PIX_FMT_RGB32: + f->fmt.pix.bytesperline = f->fmt.pix.width << 2; + break; + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: /* fall through */ + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_RGB565: + f->fmt.pix.bytesperline = f->fmt.pix.width << 1; + break; + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV12T: + f->fmt.pix.bytesperline = (f->fmt.pix.width * 3) >> 1; + break; + + default: + /* dummy value*/ + f->fmt.pix.bytesperline = f->fmt.pix.width; + } + + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +int fimc_s_fmt_vid_out(struct file *filp, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct fimc_ctx *ctx; + int ret = -1; + + fimc_info1("%s: called\n", __func__); + + /* Check stream status */ + ctx = &ctrl->out->ctx[ctx_id]; + if (ctx->status != FIMC_STREAMOFF) { + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + ret = fimc_try_fmt_vid_out(filp, fh, f); + if (ret < 0) + return ret; + + ctx->pix = f->fmt.pix; + + return ret; +} + +int fimc_init_in_queue(struct fimc_control *ctrl, struct fimc_ctx *ctx) +{ + struct fimc_idx swap_queue[FIMC_INQUEUES]; + int swap_cnt = 0, i; + unsigned long spin_flags; + + spin_lock_irqsave(&ctrl->out->lock_in, spin_flags); + + /* init incoming queue */ + for (i = 0; i < FIMC_OUTBUFS; i++) + ctx->inq[i] = -1; + + /* init common incoming queue */ + for (i = 0; i < FIMC_INQUEUES; i++) { + if (ctrl->out->inq[i].ctx != ctx->ctx_num) { + swap_queue[swap_cnt].ctx = ctrl->out->inq[i].ctx; + swap_queue[swap_cnt].idx = ctrl->out->inq[i].idx; + swap_cnt++; + } + + ctrl->out->inq[i].ctx = -1; + ctrl->out->inq[i].idx = -1; + } + + /* restore common incoming queue */ + for (i = 0; i < swap_cnt; i++) { + ctrl->out->inq[i].ctx = swap_queue[i].ctx; + ctrl->out->inq[i].idx = swap_queue[i].idx; + } + + spin_unlock_irqrestore(&ctrl->out->lock_in, spin_flags); + + return 0; +} + +int fimc_init_out_queue(struct fimc_control *ctrl, struct fimc_ctx *ctx) +{ + unsigned long spin_flags; + int i; + + spin_lock_irqsave(&ctrl->out->lock_out, spin_flags); + + /* Init incoming queue */ + for (i = 0; i < FIMC_OUTBUFS; i++) + ctx->outq[i] = -1; + + spin_unlock_irqrestore(&ctrl->out->lock_out, spin_flags); + + return 0; +} + +int fimc_push_inq(struct fimc_control *ctrl, struct fimc_ctx *ctx, int idx) +{ + struct fimc_idx swap_common_inq[FIMC_INQUEUES]; + int swap_queue[FIMC_OUTBUFS]; + int i; + unsigned long spin_flags; + + fimc_dbg("%s: idx = %d\n", __func__, idx); + + if (ctrl->out->inq[FIMC_INQUEUES-1].idx != -1) { + fimc_err("FULL: common incoming queue\n"); + return -EBUSY; + } + + spin_lock_irqsave(&ctrl->out->lock_in, spin_flags); + + /* ctx own incoming queue */ + /* Backup original queue */ + for (i = 0; i < FIMC_OUTBUFS; i++) + swap_queue[i] = ctx->inq[i]; + + /* Attach new idx */ + ctx->inq[0] = idx; + ctx->src[idx].state = VIDEOBUF_QUEUED; + ctx->src[idx].flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED; + + /* Shift the origonal queue */ + for (i = 1; i < FIMC_OUTBUFS; i++) + ctx->inq[i] = swap_queue[i-1]; + + /* Common incoming queue */ + /* Backup original queue */ + for (i = 0; i < FIMC_INQUEUES; i++) { + swap_common_inq[i].ctx = ctrl->out->inq[i].ctx; + swap_common_inq[i].idx = ctrl->out->inq[i].idx; + } + + /* Attach new idx */ + ctrl->out->inq[0].ctx = ctx->ctx_num; + ctrl->out->inq[0].idx = idx; + + /* Shift the origonal queue */ + for (i = 1; i < FIMC_INQUEUES; i++) { + ctrl->out->inq[i].ctx = swap_common_inq[i-1].ctx; + ctrl->out->inq[i].idx = swap_common_inq[i-1].idx; + } + + spin_unlock_irqrestore(&ctrl->out->lock_in, spin_flags); + + return 0; +} + +int fimc_pop_inq(struct fimc_control *ctrl, int *ctx_num, int *idx) +{ + struct fimc_ctx *ctx; + unsigned long spin_flags; + int i, ret = 0; + int ctx_idx = -1; + + spin_lock_irqsave(&ctrl->out->lock_in, spin_flags); + + /* find valid index from common incoming queue */ + for (i = (FIMC_INQUEUES-1); i >= 0; i--) { + if (ctrl->out->inq[i].ctx != -1) { + *ctx_num = ctrl->out->inq[i].ctx; + *idx = ctrl->out->inq[i].idx; + ctrl->out->inq[i].ctx = -1; + ctrl->out->inq[i].idx = -1; + break; + } + } + + /* common incoming queue is empty. */ + if (i < 0) { + spin_unlock_irqrestore(&ctrl->out->lock_in, spin_flags); + return -EINVAL; + } + + /* find valid index from incoming queue. */ + ctx = &ctrl->out->ctx[*ctx_num]; + for (i = (FIMC_OUTBUFS-1); i >= 0; i--) { + if (ctx->inq[i] != -1) { + ctx_idx = ctx->inq[i]; + ctx->inq[i] = -1; + ctx->src[ctx_idx].state = VIDEOBUF_ACTIVE; + ctx->src[ctx_idx].flags = V4L2_BUF_FLAG_MAPPED; + break; + } + } + + if (*idx != ctx_idx) + fimc_err("common inq(%d) vs inq(%d) mismatch\n", *idx, ctx_idx); + + /* incoming queue is empty. */ + if (i < 0) + ret = -EINVAL; + else + fimc_dbg("%s: index = %d\n", __func__, *idx); + + spin_unlock_irqrestore(&ctrl->out->lock_in, spin_flags); + + return ret; +} + +int fimc_push_outq(struct fimc_control *ctrl, struct fimc_ctx *ctx, int idx) +{ + unsigned long spin_flags; + int swap_queue[FIMC_OUTBUFS]; + int i; + + fimc_dbg("%s: index = %d\n", __func__, idx); + + spin_lock_irqsave(&ctrl->out->lock_out, spin_flags); + + /* Backup original queue */ + for (i = 0; i < FIMC_OUTBUFS; i++) + swap_queue[i] = ctx->outq[i]; + + /* Attach new index */ + ctx->outq[0] = idx; + ctx->src[idx].state = VIDEOBUF_DONE; + ctx->src[idx].flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; + + /* Shift the origonal queue */ + for (i = 1; i < FIMC_OUTBUFS; i++) + ctx->outq[i] = swap_queue[i-1]; + + spin_unlock_irqrestore(&ctrl->out->lock_out, spin_flags); + + return 0; +} + +int fimc_pop_outq(struct fimc_control *ctrl, struct fimc_ctx *ctx, int *idx) +{ + unsigned long spin_flags; + int i, ret = 0; + + spin_lock_irqsave(&ctrl->out->lock_out, spin_flags); + + /* Find last valid idx in outgoing queue. */ + for (i = (FIMC_OUTBUFS-1); i >= 0; i--) { + if (ctx->outq[i] != -1) { + *idx = ctx->outq[i]; + ctx->outq[i] = -1; + ctx->src[*idx].state = VIDEOBUF_IDLE; + ctx->src[*idx].flags = V4L2_BUF_FLAG_MAPPED; + break; + } + } + + /* outgoing queue is empty. */ + if (i < 0) { + ret = -EINVAL; + fimc_dbg("%s: outgoing queue : %d, %d, %d\n", __func__, + ctx->outq[0], ctx->outq[1], ctx->outq[2]); + } else + fimc_dbg("%s: idx = %d\n", __func__, *idx); + + + spin_unlock_irqrestore(&ctrl->out->lock_out, spin_flags); + + return ret; +} + +void fimc_dump_context(struct fimc_control *ctrl, struct fimc_ctx *ctx) +{ + int i = 0; + + fimc_err("ctx%d, ctrl->status: %d, ctx->status: %d\n", + ctx->ctx_num, ctrl->status, ctx->status); + + for (i = 0; i < FIMC_INQUEUES; i++) + fimc_err("ctrl->inq[%d]: ctx(%d) idx(%d)\n", + i, ctrl->out->inq[i].ctx, ctrl->out->inq[i].idx); + + for (i = 0; i < FIMC_OUTBUFS; i++) + fimc_err("inq[%d] = %d\n", i, ctx->inq[i]); + + for (i = 0; i < FIMC_OUTBUFS; i++) + fimc_err("outq[%d] = %d\n", i, ctx->outq[i]); + + fimc_err("state : prev.ctx(%d), prev.idx(%d) " + "active.ctx(%d), active.idx(%d) " + "next.ctx(%d), next.idx(%d)\n", + ctrl->out->idxs.prev.ctx, ctrl->out->idxs.prev.idx, + ctrl->out->idxs.active.ctx, ctrl->out->idxs.active.idx, + ctrl->out->idxs.next.ctx, ctrl->out->idxs.next.idx); +} + +void fimc_print_signal(struct fimc_control *ctrl) +{ + if (signal_pending(current)) { + fimc_dbg(".pend=%.8lx shpend=%.8lx\n", + current->pending.signal.sig[0], + current->signal->shared_pending.signal.sig[0]); + } else { + fimc_dbg(":pend=%.8lx shpend=%.8lx\n", + current->pending.signal.sig[0], + current->signal->shared_pending.signal.sig[0]); + } +} diff --git a/drivers/media/video/samsung/fimc/fimc_overlay.c b/drivers/media/video/samsung/fimc/fimc_overlay.c new file mode 100644 index 0000000..ff43c2e --- /dev/null +++ b/drivers/media/video/samsung/fimc/fimc_overlay.c @@ -0,0 +1,312 @@ +/* linux/drivers/media/video/samsung/fimc/fimc_overlay.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * V4L2 Overlay device support file for Samsung Camera Interface (FIMC) 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/slab.h> +#include <linux/bootmem.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <plat/media.h> + +#include "fimc.h" + +int fimc_try_fmt_overlay(struct file *filp, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct fimc_ctx *ctx; + + u32 is_rotate = 0; + ctx = &ctrl->out->ctx[ctx_id]; + + fimc_info1("%s: top(%d) left(%d) width(%d) height(%d)\n", __func__, + f->fmt.win.w.top, f->fmt.win.w.left, + f->fmt.win.w.width, f->fmt.win.w.height); + + if (ctx->overlay.mode == FIMC_OVLY_NONE_SINGLE_BUF || + (ctx->overlay.mode == FIMC_OVLY_NONE_MULTI_BUF)) + return 0; + + /* Check Overlay Size : Overlay size must be smaller than LCD size. */ + is_rotate = fimc_mapping_rot_flip(ctx->rotate, ctx->flip); + if (is_rotate & FIMC_ROT) { /* Landscape mode */ + if (f->fmt.win.w.width > ctrl->fb.lcd_vres) { + fimc_warn("The width is changed %d -> %d\n", + f->fmt.win.w.width, ctrl->fb.lcd_vres); + f->fmt.win.w.width = ctrl->fb.lcd_vres; + } + + if (f->fmt.win.w.height > ctrl->fb.lcd_hres) { + fimc_warn("The height is changed %d -> %d\n", + f->fmt.win.w.height, ctrl->fb.lcd_hres); + f->fmt.win.w.height = ctrl->fb.lcd_hres; + } + } else { /* Portrait mode */ + if (f->fmt.win.w.width > ctrl->fb.lcd_hres) { + fimc_warn("The width is changed %d -> %d\n", + f->fmt.win.w.width, ctrl->fb.lcd_hres); + f->fmt.win.w.width = ctrl->fb.lcd_hres; + } + + if (f->fmt.win.w.height > ctrl->fb.lcd_vres) { + fimc_warn("The height is changed %d -> %d\n", + f->fmt.win.w.height, ctrl->fb.lcd_vres); + f->fmt.win.w.height = ctrl->fb.lcd_vres; + } + } + + return 0; +} + +int fimc_g_fmt_vid_overlay(struct file *filp, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct fimc_ctx *ctx; + + ctx = &ctrl->out->ctx[ctx_id]; + + fimc_info1("%s: called\n", __func__); + + f->fmt.win = ctx->win; + + return 0; +} + +static int fimc_check_pos(struct fimc_control *ctrl, + struct fimc_ctx *ctx, + struct v4l2_format *f) +{ + if (ctx->win.w.width != f->fmt.win.w.width) { + fimc_err("%s: cannot change width\n", __func__); + return -EINVAL; + } else if (ctx->win.w.height != f->fmt.win.w.height) { + fimc_err("%s: cannot change height\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int fimc_change_fifo_position(struct fimc_control *ctrl, + struct fimc_ctx *ctx) { + struct v4l2_rect fimd_rect; + struct fb_info *fbinfo; + struct s3cfb_window *win; + int ret = -1; + + fbinfo = registered_fb[ctx->overlay.fb_id]; + + memset(&fimd_rect, 0, sizeof(struct v4l2_rect)); + + ret = fimc_fimd_rect(ctrl, ctx, &fimd_rect); + if (ret < 0) { + fimc_err("fimc_fimd_rect fail\n"); + return -EINVAL; + } + + /* Update WIN position */ + win->x = fimd_rect.left; + win->y = fimd_rect.top; + + fbinfo->var.activate = FB_ACTIVATE_FORCE; + ret = fb_set_var(fbinfo, &fbinfo->var); + if (ret < 0) { + fimc_err("fb_set_var fail (ret=%d)\n", ret); + return -EINVAL; + } + + return 0; +} + +int fimc_s_fmt_vid_overlay(struct file *filp, void *fh, struct v4l2_format *f) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct fimc_ctx *ctx; + int ret = -1; + ctx = &ctrl->out->ctx[ctx_id]; + + fimc_info1("%s: called\n", __func__); + + switch (ctx->status) { + case FIMC_STREAMON: + ret = fimc_check_pos(ctrl, ctx, f); + if (ret < 0) { + fimc_err("When FIMC is running, " + "you can only move the position.\n"); + return -EBUSY; + } + + ret = fimc_try_fmt_overlay(filp, fh, f); + if (ret < 0) + return ret; + + ctx->win = f->fmt.win; + fimc_change_fifo_position(ctrl, ctx); + + break; + case FIMC_STREAMOFF: + ret = fimc_try_fmt_overlay(filp, fh, f); + if (ret < 0) + return ret; + ctx->win = f->fmt.win; + + break; + + default: + fimc_err("FIMC is running\n"); + return -EBUSY; + } + + return ret; +} + +int fimc_g_fbuf(struct file *filp, void *fh, struct v4l2_framebuffer *fb) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct fimc_ctx *ctx; + u32 bpp = 1, format; + + ctx = &ctrl->out->ctx[ctx_id]; + + fimc_info1("%s: called\n", __func__); + + fb->capability = ctx->fbuf.capability; + fb->flags = 0; + fb->base = ctx->fbuf.base; + + fb->fmt.width = ctx->fbuf.fmt.width; + fb->fmt.height = ctx->fbuf.fmt.height; + fb->fmt.pixelformat = ctx->fbuf.fmt.pixelformat; + format = ctx->fbuf.fmt.pixelformat; + + switch (format) { + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: + bpp = 1; + break; + case V4L2_PIX_FMT_RGB565: + bpp = 2; + break; + case V4L2_PIX_FMT_RGB32: + bpp = 4; + break; + } + + ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp; + fb->fmt.bytesperline = ctx->fbuf.fmt.bytesperline; + fb->fmt.sizeimage = ctx->fbuf.fmt.sizeimage; + fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; + fb->fmt.priv = 0; + + return 0; +} + +int fimc_s_fbuf(struct file *filp, void *fh, struct v4l2_framebuffer *fb) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; + struct fimc_ctx *ctx; + u32 bpp = 1; + u32 format = fb->fmt.pixelformat; + ctx = &ctrl->out->ctx[ctx_id]; + + fimc_info1("%s: called. width(%d), height(%d)\n", + __func__, fb->fmt.width, fb->fmt.height); + + ctx->fbuf.capability = V4L2_FBUF_CAP_EXTERNOVERLAY; + ctx->fbuf.flags = 0; + ctx->fbuf.base = fb->base; + + if (ctx->overlay.mode == FIMC_OVLY_NONE_MULTI_BUF) { + ctx->fbuf.fmt.width = fb->fmt.width; + ctx->fbuf.fmt.height = fb->fmt.height; + ctx->fbuf.fmt.pixelformat = fb->fmt.pixelformat; + + switch (format) { + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: + bpp = 1; + break; + case V4L2_PIX_FMT_RGB565: + bpp = 2; + break; + case V4L2_PIX_FMT_RGB32: + bpp = 4; + break; + } + + ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp; + ctx->fbuf.fmt.sizeimage = fb->fmt.sizeimage; + ctx->fbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; + ctx->fbuf.fmt.priv = 0; + } else if (fb->base) { + ctx->fbuf.fmt.width = fb->fmt.width; + ctx->fbuf.fmt.height = fb->fmt.height; + ctx->fbuf.fmt.pixelformat = fb->fmt.pixelformat; + + switch (format) { + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: + bpp = 1; + break; + case V4L2_PIX_FMT_RGB565: + bpp = 2; + break; + case V4L2_PIX_FMT_RGB32: + bpp = 4; + break; + } + + ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp; + ctx->fbuf.fmt.sizeimage = fb->fmt.sizeimage; + ctx->fbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; + ctx->fbuf.fmt.priv = 0; + + ctx->overlay.mode = FIMC_OVLY_NONE_SINGLE_BUF; + } else { + int i; + struct s3cfb_window *win = NULL; + ctx->overlay.fb_id = -1; + + for (i = 0; i < num_registered_fb; i++) { + win = (struct s3cfb_window *)registered_fb[i]->par; + if (win->id == ctrl->id) { + ctx->overlay.fb_id = i; + fimc_info2("%s: overlay.fb_id = %d\n", + __func__, ctx->overlay.fb_id); + break; + } + } + + if (-1 == ctx->overlay.fb_id) { + fimc_err("%s: fb[%d] is not registered. " \ + "must be registered for overlay\n", + __func__, ctrl->id); + return -1; + } + + if (1 == win->enabled) { + fimc_err("%s: fb[%d] is already being used. " \ + "must be not used for overlay\n", + __func__, ctrl->id); + return -1; + } + + ctx->overlay.mode = FIMC_OVLY_NOT_FIXED; + } + + return 0; +} diff --git a/drivers/media/video/samsung/fimc/fimc_regs.c b/drivers/media/video/samsung/fimc/fimc_regs.c new file mode 100644 index 0000000..227945a --- /dev/null +++ b/drivers/media/video/samsung/fimc/fimc_regs.c @@ -0,0 +1,1801 @@ +/* linux/drivers/media/video/samsung/fimc/fimc_regs.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Register interface file for Samsung Camera Interface (FIMC) 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/delay.h> +#include <linux/gpio.h> +#include <linux/videodev2.h> +#include <linux/videodev2_samsung.h> +#include <linux/io.h> +#include <mach/map.h> +#include <plat/regs-fimc.h> +#include <plat/fimc.h> + +#include "fimc.h" + +/* struct fimc_limit: Limits for FIMC */ +struct fimc_limit fimc40_limits[FIMC_DEVICES] = { + { + .pre_dst_w = 3264, + .bypass_w = 8192, + .trg_h_no_rot = 3264, + .trg_h_rot = 1280, + .real_w_no_rot = 8192, + .real_h_rot = 1280, + }, { + .pre_dst_w = 1280, + .bypass_w = 8192, + .trg_h_no_rot = 1280, + .trg_h_rot = 8192, + .real_w_no_rot = 8192, + .real_h_rot = 768, + }, { + .pre_dst_w = 1440, + .bypass_w = 8192, + .trg_h_no_rot = 1440, + .trg_h_rot = 0, + .real_w_no_rot = 8192, + .real_h_rot = 0, + }, +}; + +struct fimc_limit fimc43_limits[FIMC_DEVICES] = { + { + .pre_dst_w = 4224, + .bypass_w = 8192, + .trg_h_no_rot = 4224, + .trg_h_rot = 1920, + .real_w_no_rot = 8192, + .real_h_rot = 1920, + }, { + .pre_dst_w = 4224, + .bypass_w = 8192, + .trg_h_no_rot = 4224, + .trg_h_rot = 1920, + .real_w_no_rot = 8192, + .real_h_rot = 1920, + }, { + .pre_dst_w = 1920, + .bypass_w = 8192, + .trg_h_no_rot = 1920, + .trg_h_rot = 1280, + .real_w_no_rot = 8192, + .real_h_rot = 1280, + }, +}; + +struct fimc_limit fimc50_limits[FIMC_DEVICES] = { + { + .pre_dst_w = 4224, + .bypass_w = 8192, + .trg_h_no_rot = 4224, + .trg_h_rot = 1920, + .real_w_no_rot = 8192, + .real_h_rot = 1920, + }, { + .pre_dst_w = 4224, + .bypass_w = 8192, + .trg_h_no_rot = 4224, + .trg_h_rot = 1920, + .real_w_no_rot = 8192, + .real_h_rot = 1920, + }, { + .pre_dst_w = 1920, + .bypass_w = 8192, + .trg_h_no_rot = 1920, + .trg_h_rot = 1280, + .real_w_no_rot = 8192, + .real_h_rot = 1280, + }, +}; + +int fimc_hwset_camera_source(struct fimc_control *ctrl) +{ + struct s3c_platform_camera *cam = ctrl->cam; + u32 cfg = 0; + + /* for now, we support only ITU601 8 bit mode */ + cfg |= S3C_CISRCFMT_ITU601_8BIT; + cfg |= cam->order422; + + if (cam->type == CAM_TYPE_ITU) + cfg |= cam->fmt; + + cfg |= S3C_CISRCFMT_SOURCEHSIZE(cam->width); + cfg |= S3C_CISRCFMT_SOURCEVSIZE(cam->height); + + writel(cfg, ctrl->regs + S3C_CISRCFMT); + + return 0; +} + +int fimc_hwset_enable_irq(struct fimc_control *ctrl, int overflow, int level) +{ + u32 cfg = readl(ctrl->regs + S3C_CIGCTRL); + + cfg &= ~(S3C_CIGCTRL_IRQ_OVFEN | S3C_CIGCTRL_IRQ_LEVEL); + cfg |= S3C_CIGCTRL_IRQ_ENABLE; + + if (overflow) + cfg |= S3C_CIGCTRL_IRQ_OVFEN; + + if (level) + cfg |= S3C_CIGCTRL_IRQ_LEVEL; + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc_hwset_disable_irq(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIGCTRL); + + cfg &= ~(S3C_CIGCTRL_IRQ_OVFEN | S3C_CIGCTRL_IRQ_ENABLE); + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc_hwset_clear_irq(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIGCTRL); + + cfg |= S3C_CIGCTRL_IRQ_CLR; + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc_hwset_output_area_size(struct fimc_control *ctrl, u32 size) +{ + u32 cfg = 0; + + cfg = S3C_CITAREA_TARGET_AREA(size); + + writel(cfg, ctrl->regs + S3C_CITAREA); + + return 0; +} + +void fimc_wait_disable_capture(struct fimc_control *ctrl) +{ + unsigned long timeo = jiffies + 20; /* timeout of 100 ms */ + u32 cfg; + + if (!ctrl || !ctrl->cap || + ctrl->cap->fmt.colorspace == V4L2_COLORSPACE_JPEG) + return; + + while (time_before(jiffies, timeo)) { + cfg = readl(ctrl->regs + S3C_CISTATUS); + + if (0 == (cfg & S3C_CISTATUS_IMGCPTEN)) + break; + + msleep(10); + } + + dev_dbg(ctrl->dev, "IMGCPTEN: Wait time = %d ms\n", + jiffies_to_msecs(jiffies - timeo + 20)); + + return; +} + +int fimc_hwset_image_effect(struct fimc_control *ctrl) +{ + u32 cfg = 0; + + if (ctrl->fe.ie_on) { + if (ctrl->fe.ie_after_sc) + cfg |= S3C_CIIMGEFF_IE_SC_AFTER; + + cfg |= S3C_CIIMGEFF_FIN(ctrl->fe.fin); + + if (ctrl->fe.fin == FIMC_EFFECT_FIN_ARBITRARY_CBCR) + cfg |= S3C_CIIMGEFF_PAT_CB(ctrl->fe.pat_cb) | + S3C_CIIMGEFF_PAT_CR(ctrl->fe.pat_cr); + + cfg |= S3C_CIIMGEFF_IE_ENABLE; + } + + writel(cfg, ctrl->regs + S3C_CIIMGEFF); + + return 0; +} + +int fimc_hwset_shadow_enable(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIGCTRL); + + cfg &= ~S3C_CIGCTRL_SHADOW_DISABLE; + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc_hwset_shadow_disable(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIGCTRL); + + cfg |= S3C_CIGCTRL_SHADOW_DISABLE; + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +static void fimc_reset_cfg(struct fimc_control *ctrl) +{ + int i; + u32 cfg[][2] = { + { 0x018, 0x00000000 }, { 0x01c, 0x00000000 }, + { 0x020, 0x00000000 }, { 0x024, 0x00000000 }, + { 0x028, 0x00000000 }, { 0x02c, 0x00000000 }, + { 0x030, 0x00000000 }, { 0x034, 0x00000000 }, + { 0x038, 0x00000000 }, { 0x03c, 0x00000000 }, + { 0x040, 0x00000000 }, { 0x044, 0x00000000 }, + { 0x048, 0x00000000 }, { 0x04c, 0x00000000 }, + { 0x050, 0x00000000 }, { 0x054, 0x00000000 }, + { 0x058, 0x18000000 }, { 0x05c, 0x00000000 }, + { 0x0c0, 0x00000000 }, { 0x0c4, 0xffffffff }, + { 0x0d0, 0x00100080 }, { 0x0d4, 0x00000000 }, + { 0x0d8, 0x00000000 }, { 0x0dc, 0x00000000 }, + { 0x0f8, 0x00000000 }, { 0x0fc, 0x04000000 }, + { 0x168, 0x00000000 }, { 0x16c, 0x00000000 }, + { 0x170, 0x00000000 }, { 0x174, 0x00000000 }, + { 0x178, 0x00000000 }, { 0x17c, 0x00000000 }, + { 0x180, 0x00000000 }, { 0x184, 0x00000000 }, + { 0x188, 0x00000000 }, { 0x18c, 0x00000000 }, + { 0x194, 0x0000001e }, + }; + + for (i = 0; i < sizeof(cfg) / 8; i++) + writel(cfg[i][1], ctrl->regs + cfg[i][0]); +} + +int fimc_hwset_reset(struct fimc_control *ctrl) +{ + u32 cfg = 0; + + cfg = readl(ctrl->regs + S3C_CISRCFMT); + cfg |= S3C_CISRCFMT_ITU601_8BIT; + writel(cfg, ctrl->regs + S3C_CISRCFMT); + + /* s/w reset */ + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg |= (S3C_CIGCTRL_SWRST); + writel(cfg, ctrl->regs + S3C_CIGCTRL); + mdelay(1); + + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg &= ~S3C_CIGCTRL_SWRST; + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + /* in case of ITU656, CISRCFMT[31] should be 0 */ + if ((ctrl->cap != NULL) && (ctrl->cam->fmt == ITU_656_YCBCR422_8BIT)) { + cfg = readl(ctrl->regs + S3C_CISRCFMT); + cfg &= ~S3C_CISRCFMT_ITU601_8BIT; + writel(cfg, ctrl->regs + S3C_CISRCFMT); + } + + fimc_reset_cfg(ctrl); + + return 0; +} + +int fimc_hwset_sw_reset(struct fimc_control *ctrl) +{ + u32 cfg = 0; + + /* s/w reset */ + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg |= (S3C_CIGCTRL_SWRST); + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg &= ~S3C_CIGCTRL_SWRST; + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc_hwset_clksrc(struct fimc_control *ctrl, int src_clk) +{ + u32 cfg = readl(ctrl->regs + S3C_MISC_FIMC); + cfg &= ~S3C_CLKSRC_HCLK_MASK; + + if (src_clk == FIMC_HCLK) + cfg |= S3C_CLKSRC_HCLK; + else if (src_clk == FIMC_SCLK) + cfg |= S3C_CLKSRC_SCLK; + + writel(cfg, ctrl->regs + S3C_MISC_FIMC); + return 0; +} + +int fimc_hwget_overflow_state(struct fimc_control *ctrl) +{ + u32 cfg, status, flag; + + status = readl(ctrl->regs + S3C_CISTATUS); + flag = S3C_CISTATUS_OVFIY | S3C_CISTATUS_OVFICB | S3C_CISTATUS_OVFICR; + + if (status & flag) { + cfg = readl(ctrl->regs + S3C_CIWDOFST); + cfg |= (S3C_CIWDOFST_CLROVFIY | S3C_CIWDOFST_CLROVFICB | + S3C_CIWDOFST_CLROVFICR); + writel(cfg, ctrl->regs + S3C_CIWDOFST); + + cfg = readl(ctrl->regs + S3C_CIWDOFST); + cfg &= ~(S3C_CIWDOFST_CLROVFIY | S3C_CIWDOFST_CLROVFICB | + S3C_CIWDOFST_CLROVFICR); + writel(cfg, ctrl->regs + S3C_CIWDOFST); + + return 1; + } + + return 0; +} + +int fimc_hwset_camera_offset(struct fimc_control *ctrl) +{ + struct s3c_platform_camera *cam = ctrl->cam; + struct v4l2_rect *rect = &cam->window; + u32 cfg, h1, h2, v1, v2; + + if (!cam) { + fimc_err("%s: no active camera\n", __func__); + return -ENODEV; + } + + h1 = rect->left; + h2 = cam->width - rect->width - rect->left; + v1 = rect->top; + v2 = cam->height - rect->height - rect->top; + + cfg = readl(ctrl->regs + S3C_CIWDOFST); + cfg &= ~(S3C_CIWDOFST_WINHOROFST_MASK | S3C_CIWDOFST_WINVEROFST_MASK); + cfg |= S3C_CIWDOFST_WINHOROFST(h1); + cfg |= S3C_CIWDOFST_WINVEROFST(v1); + cfg |= S3C_CIWDOFST_WINOFSEN; + writel(cfg, ctrl->regs + S3C_CIWDOFST); + + cfg = 0; + cfg |= S3C_CIWDOFST2_WINHOROFST2(h2); + cfg |= S3C_CIWDOFST2_WINVEROFST2(v2); + writel(cfg, ctrl->regs + S3C_CIWDOFST2); + + return 0; +} + +int fimc_hwset_camera_polarity(struct fimc_control *ctrl) +{ + struct s3c_platform_camera *cam = ctrl->cam; + u32 cfg; + + if (!cam) { + fimc_err("%s: no active camera\n", __func__); + return -ENODEV; + } + + cfg = readl(ctrl->regs + S3C_CIGCTRL); + + cfg &= ~(S3C_CIGCTRL_INVPOLPCLK | S3C_CIGCTRL_INVPOLVSYNC | + S3C_CIGCTRL_INVPOLHREF | S3C_CIGCTRL_INVPOLHSYNC); + + if (cam->inv_pclk) + cfg |= S3C_CIGCTRL_INVPOLPCLK; + + if (cam->inv_vsync) + cfg |= S3C_CIGCTRL_INVPOLVSYNC; + + if (cam->inv_href) + cfg |= S3C_CIGCTRL_INVPOLHREF; + + if (cam->inv_hsync) + cfg |= S3C_CIGCTRL_INVPOLHSYNC; + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc40_hwset_camera_type(struct fimc_control *ctrl) +{ + struct s3c_platform_camera *cam = ctrl->cam; + u32 cfg; + + if (!cam) { + fimc_err("%s: no active camera\n", __func__); + return -ENODEV; + } + + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg &= ~(S3C_CIGCTRL_TESTPATTERN_MASK | S3C_CIGCTRL_SELCAM_ITU_MASK | + S3C_CIGCTRL_SELCAM_FIMC_MASK); + + /* Interface selection */ + if (cam->type == CAM_TYPE_MIPI) { + cfg |= S3C_CIGCTRL_SELCAM_FIMC_MIPI; + writel(cam->fmt, ctrl->regs + S3C_CSIIMGFMT); + } else if (cam->type == CAM_TYPE_ITU) { + if (cam->id == CAMERA_PAR_A) + cfg |= S3C_CIGCTRL_SELCAM_ITU_A; + else + cfg |= S3C_CIGCTRL_SELCAM_ITU_B; + /* switch to ITU interface */ + cfg |= S3C_CIGCTRL_SELCAM_FIMC_ITU; + } else { + fimc_err("%s: invalid camera bus type selected\n", + __func__); + return -EINVAL; + } + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc43_hwset_camera_type(struct fimc_control *ctrl) +{ + struct s3c_platform_camera *cam = ctrl->cam; + u32 cfg; + + if (!cam) { + fimc_err("%s: no active camera\n", __func__); + return -ENODEV; + } + + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg &= ~(S3C_CIGCTRL_TESTPATTERN_MASK | S3C_CIGCTRL_SELCAM_ITU_MASK | + S3C_CIGCTRL_SELCAM_MIPI_MASK | S3C_CIGCTRL_SELCAM_FIMC_MASK | + S3C_CIGCTRL_SELWB_CAMIF_MASK); + + /* Interface selection */ + if (cam->id == CAMERA_WB) { + cfg |= S3C_CIGCTRL_SELWB_CAMIF_WRITEBACK; + } else if (cam->type == CAM_TYPE_MIPI) { + cfg |= S3C_CIGCTRL_SELCAM_FIMC_MIPI; + + /* C110/V210 Support only MIPI A support */ + cfg |= S3C_CIGCTRL_SELCAM_MIPI_A; + + /* FIXME: Temporary MIPI CSIS Data 32 bit aligned */ + if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG) + writel((MIPI_USER_DEF_PACKET_1 | (0x1 << 8)), + ctrl->regs + S3C_CSIIMGFMT); + else + writel(cam->fmt | (0x1 << 8), + ctrl->regs + S3C_CSIIMGFMT); + } else if (cam->type == CAM_TYPE_ITU) { + if (cam->id == CAMERA_PAR_A) + cfg |= S3C_CIGCTRL_SELCAM_ITU_A; + else + cfg |= S3C_CIGCTRL_SELCAM_ITU_B; + /* switch to ITU interface */ + cfg |= S3C_CIGCTRL_SELCAM_FIMC_ITU; + } else { + fimc_err("%s: invalid camera bus type selected\n", __func__); + return -EINVAL; + } + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc_hwset_camera_type(struct fimc_control *ctrl) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + + switch (pdata->hw_ver) { + case 0x40: + fimc40_hwset_camera_type(ctrl); + break; + case 0x43: + case 0x45: + fimc43_hwset_camera_type(ctrl); + break; + default: + fimc43_hwset_camera_type(ctrl); + break; + } + + return 0; +} + + +int fimc_hwset_jpeg_mode(struct fimc_control *ctrl, bool enable) +{ + u32 cfg; + cfg = readl(ctrl->regs + S3C_CIGCTRL); + + if (enable) + cfg |= S3C_CIGCTRL_CAM_JPEG; + else + cfg &= ~S3C_CIGCTRL_CAM_JPEG; + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + + return 0; +} + +int fimc_hwset_output_size(struct fimc_control *ctrl, int width, int height) +{ + u32 cfg = readl(ctrl->regs + S3C_CITRGFMT); + + cfg &= ~(S3C_CITRGFMT_TARGETH_MASK | S3C_CITRGFMT_TARGETV_MASK); + + cfg |= S3C_CITRGFMT_TARGETHSIZE(width); + cfg |= S3C_CITRGFMT_TARGETVSIZE(height); + + writel(cfg, ctrl->regs + S3C_CITRGFMT); + + return 0; +} + +int fimc_hwset_output_colorspace(struct fimc_control *ctrl, u32 pixelformat) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + u32 cfg; + + if (pdata->hw_ver != 0x40) { + if (pixelformat == V4L2_PIX_FMT_YUV444) { + cfg = readl(ctrl->regs + S3C_CIEXTEN); + cfg |= S3C_CIEXTEN_YUV444_OUT; + writel(cfg, ctrl->regs + S3C_CIEXTEN); + + return 0; + } else { + cfg = readl(ctrl->regs + S3C_CIEXTEN); + cfg &= ~S3C_CIEXTEN_YUV444_OUT; + writel(cfg, ctrl->regs + S3C_CIEXTEN); + } + } + + cfg = readl(ctrl->regs + S3C_CITRGFMT); + cfg &= ~S3C_CITRGFMT_OUTFORMAT_MASK; + + switch (pixelformat) { + case V4L2_PIX_FMT_JPEG: + break; + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_RGB32: + cfg |= S3C_CITRGFMT_OUTFORMAT_RGB; + break; + + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_YVYU: + cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE; + break; + + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: /* fall through */ + case V4L2_PIX_FMT_YUV422P: + cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422; + break; + + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV12T: /* fall through */ + case V4L2_PIX_FMT_NV21: + cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR420; + break; + + default: + fimc_err("%s: invalid pixel format\n", __func__); + break; + } + + writel(cfg, ctrl->regs + S3C_CITRGFMT); + + return 0; +} + +int fimc_hwset_output_rot_flip(struct fimc_control *ctrl, u32 rot, u32 flip) +{ + u32 cfg, val; + + cfg = readl(ctrl->regs + S3C_CITRGFMT); + cfg &= ~S3C_CITRGFMT_FLIP_MASK; + cfg &= ~S3C_CITRGFMT_OUTROT90_CLOCKWISE; + + val = fimc_mapping_rot_flip(rot, flip); + + if (val & FIMC_ROT) + cfg |= S3C_CITRGFMT_OUTROT90_CLOCKWISE; + + if (val & FIMC_XFLIP) + cfg |= S3C_CITRGFMT_FLIP_X_MIRROR; + + if (val & FIMC_YFLIP) + cfg |= S3C_CITRGFMT_FLIP_Y_MIRROR; + + writel(cfg, ctrl->regs + S3C_CITRGFMT); + + return 0; +} + +int fimc_hwset_output_area(struct fimc_control *ctrl, u32 width, u32 height) +{ + u32 cfg = 0; + + cfg = S3C_CITAREA_TARGET_AREA(width * height); + writel(cfg, ctrl->regs + S3C_CITAREA); + + return 0; +} + +int fimc_hwset_enable_lastirq(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIOCTRL); + + cfg |= S3C_CIOCTRL_LASTIRQ_ENABLE; + writel(cfg, ctrl->regs + S3C_CIOCTRL); + + return 0; +} + +int fimc_hwset_disable_lastirq(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIOCTRL); + + cfg &= ~S3C_CIOCTRL_LASTIRQ_ENABLE; + writel(cfg, ctrl->regs + S3C_CIOCTRL); + + return 0; +} + +int fimc_hwset_prescaler(struct fimc_control *ctrl, struct fimc_scaler *sc) +{ + u32 cfg = 0, shfactor; + + shfactor = 10 - (sc->hfactor + sc->vfactor); + + cfg |= S3C_CISCPRERATIO_SHFACTOR(shfactor); + cfg |= S3C_CISCPRERATIO_PREHORRATIO(sc->pre_hratio); + cfg |= S3C_CISCPRERATIO_PREVERRATIO(sc->pre_vratio); + + writel(cfg, ctrl->regs + S3C_CISCPRERATIO); + + cfg = 0; + cfg |= S3C_CISCPREDST_PREDSTWIDTH(sc->pre_dst_width); + cfg |= S3C_CISCPREDST_PREDSTHEIGHT(sc->pre_dst_height); + + writel(cfg, ctrl->regs + S3C_CISCPREDST); + + return 0; +} + +int fimc_hwset_output_address(struct fimc_control *ctrl, + struct fimc_buf_set *bs, int id) +{ + writel(bs->base[FIMC_ADDR_Y], ctrl->regs + S3C_CIOYSA(id)); + writel(bs->base[FIMC_ADDR_CB], ctrl->regs + S3C_CIOCBSA(id)); + writel(bs->base[FIMC_ADDR_CR], ctrl->regs + S3C_CIOCRSA(id)); + + return 0; +} + +int fimc_hwset_output_yuv(struct fimc_control *ctrl, u32 pixelformat) +{ + u32 cfg; + + cfg = readl(ctrl->regs + S3C_CIOCTRL); + cfg &= ~(S3C_CIOCTRL_ORDER2P_MASK | S3C_CIOCTRL_ORDER422_MASK | + S3C_CIOCTRL_YCBCR_PLANE_MASK); + + switch (pixelformat) { + /* 1 plane formats */ + case V4L2_PIX_FMT_YUYV: + cfg |= S3C_CIOCTRL_ORDER422_YCBYCR; + break; + + case V4L2_PIX_FMT_UYVY: + cfg |= S3C_CIOCTRL_ORDER422_CBYCRY; + break; + + case V4L2_PIX_FMT_VYUY: + cfg |= S3C_CIOCTRL_ORDER422_CRYCBY; + break; + + case V4L2_PIX_FMT_YVYU: + cfg |= S3C_CIOCTRL_ORDER422_YCRYCB; + break; + + /* 2 plane formats */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV12T: /* fall through */ + case V4L2_PIX_FMT_NV16: + cfg |= S3C_CIOCTRL_ORDER2P_LSB_CBCR; + cfg |= S3C_CIOCTRL_YCBCR_2PLANE; + break; + + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV61: + cfg |= S3C_CIOCTRL_ORDER2P_LSB_CRCB; + cfg |= S3C_CIOCTRL_YCBCR_2PLANE; + break; + + /* 3 plane formats */ + case V4L2_PIX_FMT_YUV422P: /* fall through */ + case V4L2_PIX_FMT_YUV420: + cfg |= S3C_CIOCTRL_YCBCR_3PLANE; + break; + } + + writel(cfg, ctrl->regs + S3C_CIOCTRL); + + return 0; +} + +int fimc_hwset_output_scan(struct fimc_control *ctrl, + struct v4l2_pix_format *fmt) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + u32 cfg; + + /* nothing to do: FIMC40 not supported interlaced and weave output */ + if (pdata->hw_ver == 0x40) + return 0; + + cfg = readl(ctrl->regs + S3C_CISCCTRL); + cfg &= ~S3C_CISCCTRL_SCAN_MASK; + + if (fmt->field == V4L2_FIELD_INTERLACED || + fmt->field == V4L2_FIELD_INTERLACED_TB) + cfg |= S3C_CISCCTRL_INTERLACE; + else + cfg |= S3C_CISCCTRL_PROGRESSIVE; + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + cfg = readl(ctrl->regs + S3C_CIOCTRL); + cfg &= ~S3C_CIOCTRL_WEAVE_MASK; + + if ((ctrl->cap) && (fmt->field == V4L2_FIELD_INTERLACED_TB)) + cfg |= S3C_CIOCTRL_WEAVE_OUT; + + writel(cfg, ctrl->regs + S3C_CIOCTRL); + + return 0; +} + +int fimc_hwset_input_rot(struct fimc_control *ctrl, u32 rot, u32 flip) +{ + u32 cfg, val; + + cfg = readl(ctrl->regs + S3C_CITRGFMT); + cfg &= ~S3C_CITRGFMT_INROT90_CLOCKWISE; + + val = fimc_mapping_rot_flip(rot, flip); + + if (val & FIMC_ROT) + cfg |= S3C_CITRGFMT_INROT90_CLOCKWISE; + + writel(cfg, ctrl->regs + S3C_CITRGFMT); + + return 0; +} + +int fimc40_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + + cfg &= ~(S3C_CISCCTRL_SCALERBYPASS | + S3C_CISCCTRL_SCALEUP_H | S3C_CISCCTRL_SCALEUP_V | + S3C_CISCCTRL_MAIN_V_RATIO_MASK | + S3C_CISCCTRL_MAIN_H_RATIO_MASK | + S3C_CISCCTRL_CSCR2Y_WIDE | + S3C_CISCCTRL_CSCY2R_WIDE); + +#ifdef CONFIG_VIDEO_FIMC_RANGE_WIDE + cfg |= (S3C_CISCCTRL_CSCR2Y_WIDE | S3C_CISCCTRL_CSCY2R_WIDE); +#endif + + if (sc->bypass) + cfg |= S3C_CISCCTRL_SCALERBYPASS; + + if (sc->scaleup_h) + cfg |= S3C_CISCCTRL_SCALEUP_H; + + if (sc->scaleup_v) + cfg |= S3C_CISCCTRL_SCALEUP_V; + + cfg |= S3C_CISCCTRL_MAINHORRATIO(sc->main_hratio); + cfg |= S3C_CISCCTRL_MAINVERRATIO(sc->main_vratio); + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc43_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + u32 cfg_ext = readl(ctrl->regs + S3C_CIEXTEN); + + cfg &= ~(S3C_CISCCTRL_SCALERBYPASS | + S3C_CISCCTRL_SCALEUP_H | S3C_CISCCTRL_SCALEUP_V | + S3C_CISCCTRL_MAIN_V_RATIO_MASK | + S3C_CISCCTRL_MAIN_H_RATIO_MASK | + S3C_CISCCTRL_CSCR2Y_WIDE | + S3C_CISCCTRL_CSCY2R_WIDE); + +#ifdef CONFIG_VIDEO_FIMC_RANGE_WIDE + cfg |= (S3C_CISCCTRL_CSCR2Y_WIDE | S3C_CISCCTRL_CSCY2R_WIDE); +#endif + + if (sc->bypass) + cfg |= S3C_CISCCTRL_SCALERBYPASS; + + if (sc->scaleup_h) + cfg |= S3C_CISCCTRL_SCALEUP_H; + + if (sc->scaleup_v) + cfg |= S3C_CISCCTRL_SCALEUP_V; + + cfg |= S3C_CISCCTRL_MAINHORRATIO(sc->main_hratio); + cfg |= S3C_CISCCTRL_MAINVERRATIO(sc->main_vratio); + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + cfg_ext &= ~S3C_CIEXTEN_MAINHORRATIO_EXT_MASK; + cfg_ext &= ~S3C_CIEXTEN_MAINVERRATIO_EXT_MASK; + + cfg_ext |= S3C_CIEXTEN_MAINHORRATIO_EXT(sc->main_hratio); + cfg_ext |= S3C_CIEXTEN_MAINVERRATIO_EXT(sc->main_vratio); + + writel(cfg_ext, ctrl->regs + S3C_CIEXTEN); + + return 0; +} + +int fimc50_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + u32 cfg_ext = readl(ctrl->regs + S3C_CIEXTEN); + + cfg &= ~(S3C_CISCCTRL_SCALERBYPASS | + S3C_CISCCTRL_SCALEUP_H | S3C_CISCCTRL_SCALEUP_V | + S3C_CISCCTRL_MAIN_V_RATIO_MASK | + S3C_CISCCTRL_MAIN_H_RATIO_MASK | + S3C_CISCCTRL_CSCR2Y_WIDE | + S3C_CISCCTRL_CSCY2R_WIDE); + +#ifdef CONFIG_VIDEO_FIMC_RANGE_WIDE + cfg |= (S3C_CISCCTRL_CSCR2Y_WIDE | S3C_CISCCTRL_CSCY2R_WIDE); +#endif + + if (sc->bypass) + cfg |= S3C_CISCCTRL_SCALERBYPASS; + + if (sc->scaleup_h) + cfg |= S3C_CISCCTRL_SCALEUP_H; + + if (sc->scaleup_v) + cfg |= S3C_CISCCTRL_SCALEUP_V; + + cfg |= S3C_CISCCTRL_MAINHORRATIO((sc->main_hratio >> 6)); + cfg |= S3C_CISCCTRL_MAINVERRATIO((sc->main_vratio >> 6)); + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + cfg_ext &= ~S3C_CIEXTEN_MAINHORRATIO_EXT_MASK; + cfg_ext &= ~S3C_CIEXTEN_MAINVERRATIO_EXT_MASK; + + cfg_ext |= S3C_CIEXTEN_MAINHORRATIO_EXT(sc->main_hratio); + cfg_ext |= S3C_CIEXTEN_MAINVERRATIO_EXT(sc->main_vratio); + + writel(cfg_ext, ctrl->regs + S3C_CIEXTEN); + + return 0; +} + +int fimc_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + + switch (pdata->hw_ver) { + case 0x40: + fimc40_hwset_scaler(ctrl, sc); + break; + case 0x43: + case 0x45: + fimc43_hwset_scaler(ctrl, sc); + break; + case 0x50: + fimc50_hwset_scaler(ctrl, sc); + break; + default: + fimc43_hwset_scaler(ctrl, sc); + break; + } + + return 0; +} + + +int fimc_hwset_scaler_bypass(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + + cfg |= S3C_CISCCTRL_SCALERBYPASS; + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwset_enable_lcdfifo(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + + cfg |= S3C_CISCCTRL_LCDPATHEN_FIFO; + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwset_disable_lcdfifo(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + + cfg &= ~S3C_CISCCTRL_LCDPATHEN_FIFO; + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwget_frame_count(struct fimc_control *ctrl) +{ + return S3C_CISTATUS_GET_FRAME_COUNT(readl(ctrl->regs + S3C_CISTATUS)); +} + +int fimc_hwget_frame_end(struct fimc_control *ctrl) +{ + unsigned long timeo = jiffies; + u32 cfg; + + timeo += 20; /* waiting for 100ms */ + while (time_before(jiffies, timeo)) { + cfg = readl(ctrl->regs + S3C_CISTATUS); + + if (S3C_CISTATUS_GET_FRAME_END(cfg)) { + cfg &= ~S3C_CISTATUS_FRAMEEND; + writel(cfg, ctrl->regs + S3C_CISTATUS); + break; + } + cond_resched(); + } + + return 0; +} + +int fimc_hwget_last_frame_end(struct fimc_control *ctrl) +{ + unsigned long timeo = jiffies; + u32 cfg; + + timeo += 20; /* waiting for 100ms */ + while (time_before(jiffies, timeo)) { + cfg = readl(ctrl->regs + S3C_CISTATUS); + + if (S3C_CISTATUS_GET_LAST_CAPTURE_END(cfg)) { + cfg &= ~S3C_CISTATUS_LASTCAPTUREEND; + writel(cfg, ctrl->regs + S3C_CISTATUS); + break; + } + cond_resched(); + } + + return 0; +} + +int fimc_hwset_start_scaler(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + + cfg |= S3C_CISCCTRL_SCALERSTART; + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwset_stop_scaler(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + + cfg &= ~S3C_CISCCTRL_SCALERSTART; + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwset_input_rgb(struct fimc_control *ctrl, u32 pixelformat) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + cfg &= ~S3C_CISCCTRL_INRGB_FMT_RGB_MASK; + + if (pixelformat == V4L2_PIX_FMT_RGB32) + cfg |= S3C_CISCCTRL_INRGB_FMT_RGB888; + else if (pixelformat == V4L2_PIX_FMT_RGB565) + cfg |= S3C_CISCCTRL_INRGB_FMT_RGB565; + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwset_intput_field(struct fimc_control *ctrl, enum v4l2_field field) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + u32 cfg; + + if (pdata->hw_ver == 0x40) + return 0; + + cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg &= ~S3C_MSCTRL_FIELD_MASK; + + if (field == V4L2_FIELD_NONE) + cfg |= S3C_MSCTRL_FIELD_NORMAL; + else if (field == V4L2_FIELD_INTERLACED_TB) + cfg |= S3C_MSCTRL_FIELD_WEAVE; + + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; +} + +int fimc_hwset_output_rgb(struct fimc_control *ctrl, u32 pixelformat) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + cfg &= ~S3C_CISCCTRL_OUTRGB_FMT_RGB_MASK; + + if (pixelformat == V4L2_PIX_FMT_RGB32) + cfg |= S3C_CISCCTRL_OUTRGB_FMT_RGB888; + else if (pixelformat == V4L2_PIX_FMT_RGB565) + cfg |= S3C_CISCCTRL_OUTRGB_FMT_RGB565; + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwset_ext_rgb(struct fimc_control *ctrl, int enable) +{ + u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); + cfg &= ~S3C_CISCCTRL_EXTRGB_EXTENSION; + + if (enable) + cfg |= S3C_CISCCTRL_EXTRGB_EXTENSION; + + writel(cfg, ctrl->regs + S3C_CISCCTRL); + + return 0; +} + +int fimc_hwset_enable_capture(struct fimc_control *ctrl, u32 bypass) +{ + u32 cfg = readl(ctrl->regs + S3C_CIIMGCPT); + cfg &= ~S3C_CIIMGCPT_IMGCPTEN_SC; + cfg |= S3C_CIIMGCPT_IMGCPTEN; + + if (!bypass) + cfg |= S3C_CIIMGCPT_IMGCPTEN_SC; + + writel(cfg, ctrl->regs + S3C_CIIMGCPT); + + return 0; +} + +int fimc_hwset_disable_capture(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIIMGCPT); + + cfg &= ~(S3C_CIIMGCPT_IMGCPTEN_SC | S3C_CIIMGCPT_IMGCPTEN); + + writel(cfg, ctrl->regs + S3C_CIIMGCPT); + + return 0; +} + +int fimc_hwset_input_address(struct fimc_control *ctrl, dma_addr_t *base) +{ + writel(base[FIMC_ADDR_Y], ctrl->regs + S3C_CIIYSA0); + writel(base[FIMC_ADDR_CB], ctrl->regs + S3C_CIICBSA0); + writel(base[FIMC_ADDR_CR], ctrl->regs + S3C_CIICRSA0); + + return 0; +} + +int fimc_hwset_enable_autoload(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIREAL_ISIZE); + + cfg |= S3C_CIREAL_ISIZE_AUTOLOAD_ENABLE; + + writel(cfg, ctrl->regs + S3C_CIREAL_ISIZE); + + return 0; +} + +int fimc_hwset_disable_autoload(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIREAL_ISIZE); + + cfg &= ~S3C_CIREAL_ISIZE_AUTOLOAD_ENABLE; + + writel(cfg, ctrl->regs + S3C_CIREAL_ISIZE); + + return 0; +} + +int fimc_hwset_real_input_size(struct fimc_control *ctrl, u32 width, u32 height) +{ + u32 cfg = readl(ctrl->regs + S3C_CIREAL_ISIZE); + cfg &= ~(S3C_CIREAL_ISIZE_HEIGHT_MASK | S3C_CIREAL_ISIZE_WIDTH_MASK); + + cfg |= S3C_CIREAL_ISIZE_WIDTH(width); + cfg |= S3C_CIREAL_ISIZE_HEIGHT(height); + + writel(cfg, ctrl->regs + S3C_CIREAL_ISIZE); + + return 0; +} + +int fimc_hwset_addr_change_enable(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIREAL_ISIZE); + + cfg &= ~S3C_CIREAL_ISIZE_ADDR_CH_DISABLE; + + writel(cfg, ctrl->regs + S3C_CIREAL_ISIZE); + + return 0; +} + +int fimc_hwset_addr_change_disable(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_CIREAL_ISIZE); + + cfg |= S3C_CIREAL_ISIZE_ADDR_CH_DISABLE; + + writel(cfg, ctrl->regs + S3C_CIREAL_ISIZE); + + return 0; +} + +int fimc_hwset_input_burst_cnt(struct fimc_control *ctrl, u32 cnt) +{ + u32 cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg &= ~S3C_MSCTRL_BURST_CNT_MASK; + + if (cnt > 4) + cnt = 4; + else if (cnt == 0) + cnt = 4; + + cfg |= S3C_MSCTRL_SUCCESSIVE_COUNT(cnt); + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; +} + +int fimc_hwset_input_colorspace(struct fimc_control *ctrl, u32 pixelformat) +{ + u32 cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg &= ~S3C_MSCTRL_INFORMAT_RGB; + + /* Color format setting */ + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: /* fall through */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV12T: + cfg |= S3C_MSCTRL_INFORMAT_YCBCR420; + break; + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: + cfg |= S3C_MSCTRL_INFORMAT_YCBCR422_1PLANE; + break; + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: + cfg |= S3C_MSCTRL_INFORMAT_YCBCR422; + break; + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_RGB32: + cfg |= S3C_MSCTRL_INFORMAT_RGB; + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", + __func__, pixelformat); + return -EINVAL; + } + + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; +} + +int fimc_hwset_input_yuv(struct fimc_control *ctrl, u32 pixelformat) +{ + u32 cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg &= ~(S3C_MSCTRL_ORDER2P_SHIFT_MASK | S3C_MSCTRL_C_INT_IN_2PLANE | + S3C_MSCTRL_ORDER422_YCBYCR); + + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + cfg |= S3C_MSCTRL_C_INT_IN_3PLANE; + break; + case V4L2_PIX_FMT_YUYV: /* fall through */ + cfg |= S3C_MSCTRL_ORDER422_YCBYCR; + break; + case V4L2_PIX_FMT_UYVY: + cfg |= S3C_MSCTRL_ORDER422_CBYCRY; + break; + case V4L2_PIX_FMT_YVYU: + cfg |= S3C_MSCTRL_ORDER422_YCRYCB; + break; + case V4L2_PIX_FMT_VYUY: + cfg |= S3C_MSCTRL_ORDER422_CRYCBY; + break; + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV12T: + cfg |= S3C_MSCTRL_ORDER2P_LSB_CBCR; + cfg |= S3C_MSCTRL_C_INT_IN_2PLANE; + break; + case V4L2_PIX_FMT_NV21: + cfg |= S3C_MSCTRL_ORDER2P_LSB_CRCB; + cfg |= S3C_MSCTRL_C_INT_IN_2PLANE; + break; + case V4L2_PIX_FMT_NV16: + cfg |= S3C_MSCTRL_ORDER2P_LSB_CBCR; + cfg |= S3C_MSCTRL_C_INT_IN_2PLANE; + break; + case V4L2_PIX_FMT_NV61: + cfg |= S3C_MSCTRL_ORDER2P_LSB_CRCB; + cfg |= S3C_MSCTRL_C_INT_IN_2PLANE; + break; + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_RGB32: + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", + __func__, pixelformat); + } + + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; +} + +int fimc_hwset_input_flip(struct fimc_control *ctrl, u32 rot, u32 flip) +{ + u32 cfg, val; + + cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg &= ~(S3C_MSCTRL_FLIP_X_MIRROR | S3C_MSCTRL_FLIP_Y_MIRROR); + val = fimc_mapping_rot_flip(rot, flip); + + if (val & FIMC_XFLIP) + cfg |= S3C_MSCTRL_FLIP_X_MIRROR; + + if (val & FIMC_YFLIP) + cfg |= S3C_MSCTRL_FLIP_Y_MIRROR; + + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; +} + +int fimc_hwset_input_source(struct fimc_control *ctrl, enum fimc_input path) +{ + u32 cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg &= ~S3C_MSCTRL_INPUT_MASK; + + if (path == FIMC_SRC_MSDMA) + cfg |= S3C_MSCTRL_INPUT_MEMORY; + else if (path == FIMC_SRC_CAM) + cfg |= S3C_MSCTRL_INPUT_EXTCAM; + + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; + +} + +int fimc_hwset_start_input_dma(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg |= S3C_MSCTRL_ENVID; + + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; +} + +int fimc_hwset_stop_input_dma(struct fimc_control *ctrl) +{ + u32 cfg = readl(ctrl->regs + S3C_MSCTRL); + cfg &= ~S3C_MSCTRL_ENVID; + + writel(cfg, ctrl->regs + S3C_MSCTRL); + + return 0; +} + +void fimc_wait_stop_processing(struct fimc_control *ctrl) +{ + fimc_hwget_frame_end(ctrl); + fimc_hwget_last_frame_end(ctrl); +} + +void fimc_hwset_stop_processing(struct fimc_control *ctrl) +{ + fimc_wait_stop_processing(ctrl); + + fimc_hwset_stop_scaler(ctrl); + fimc_hwset_disable_capture(ctrl); + fimc_hwset_stop_input_dma(ctrl); + + /* We need to wait for sometime after processing is stopped. + * This is required for obtaining clean buffer for DMA processing. */ + fimc_wait_stop_processing(ctrl); +} + +int fimc40_hwset_output_offset(struct fimc_control *ctrl, u32 pixelformat, + struct v4l2_rect *bounds, + struct v4l2_rect *crop) +{ + u32 cfg_y = 0, cfg_cb = 0, cfg_cr = 0; + + if (!crop->left && !crop->top && (bounds->width == crop->width) && + (bounds->height == crop->height)) + return -EINVAL; + + fimc_dbg("%s: left: %d, top: %d, width: %d, height: %d\n", + __func__, crop->left, crop->top, crop->width, crop->height); + + switch (pixelformat) { + /* 1 plane, 32 bits per pixel */ + case V4L2_PIX_FMT_RGB32: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left * 4); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + break; + + /* 1 plane, 16 bits per pixel */ + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_RGB565: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left * 2); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + break; + + /* 2 planes, 16 bits per pixel */ + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left / 2); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top / 2); + break; + + /* 2 planes, 12 bits per pixel */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV12T: /* fall through */ + case V4L2_PIX_FMT_NV21: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left / 4); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top / 4); + break; + + /* 3 planes, 16 bits per pixel */ + case V4L2_PIX_FMT_YUV422P: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left / 2); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top / 2); + cfg_cr |= S3C_CIOCROFF_HORIZONTAL(crop->left / 2); + cfg_cr |= S3C_CIOCROFF_VERTICAL(crop->top / 2); + break; + + /* 3 planes, 12 bits per pixel */ + case V4L2_PIX_FMT_YUV420: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left / 4); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top / 4); + cfg_cr |= S3C_CIOCROFF_HORIZONTAL(crop->left / 4); + cfg_cr |= S3C_CIOCROFF_VERTICAL(crop->top / 4); + break; + + default: + break; + } + + writel(cfg_y, ctrl->regs + S3C_CIOYOFF); + writel(cfg_cb, ctrl->regs + S3C_CIOCBOFF); + writel(cfg_cr, ctrl->regs + S3C_CIOCROFF); + + return 0; +} + +int fimc50_hwset_output_offset(struct fimc_control *ctrl, u32 pixelformat, + struct v4l2_rect *bounds, + struct v4l2_rect *crop) +{ + u32 cfg_y = 0, cfg_cb = 0, cfg_cr = 0; + + if (!crop->left && !crop->top && (bounds->width == crop->width) && + (bounds->height == crop->height)) + return -EINVAL; + + fimc_dbg("%s: left: %d, top: %d, width: %d, height: %d\n", + __func__, crop->left, crop->top, crop->width, crop->height); + + switch (pixelformat) { + /* 1 plane, 32 bits per pixel */ + case V4L2_PIX_FMT_RGB32: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + break; + + /* 1 plane, 16 bits per pixel */ + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_RGB565: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + break; + + /* 2 planes, 16 bits per pixel */ + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top); + break; + + /* 2 planes, 12 bits per pixel */ + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV12T: /* fall through */ + case V4L2_PIX_FMT_NV21: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top); + break; + + /* 3 planes, 16 bits per pixel */ + case V4L2_PIX_FMT_YUV422P: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top); + cfg_cr |= S3C_CIOCROFF_HORIZONTAL(crop->left); + cfg_cr |= S3C_CIOCROFF_VERTICAL(crop->top); + break; + + /* 3 planes, 12 bits per pixel */ + case V4L2_PIX_FMT_YUV420: + cfg_y |= S3C_CIOYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIOYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIOCBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIOCBOFF_VERTICAL(crop->top); + cfg_cr |= S3C_CIOCROFF_HORIZONTAL(crop->left); + cfg_cr |= S3C_CIOCROFF_VERTICAL(crop->top); + break; + + default: + break; + } + + writel(cfg_y, ctrl->regs + S3C_CIOYOFF); + writel(cfg_cb, ctrl->regs + S3C_CIOCBOFF); + writel(cfg_cr, ctrl->regs + S3C_CIOCROFF); + + return 0; +} + +int fimc_hwset_output_offset(struct fimc_control *ctrl, u32 pixelformat, + struct v4l2_rect *bounds, + struct v4l2_rect *crop) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + + if (pdata->hw_ver == 0x50 || pdata->hw_ver == 0x45) + fimc50_hwset_output_offset(ctrl, pixelformat, bounds, crop); + else + fimc40_hwset_output_offset(ctrl, pixelformat, bounds, crop); + + return 0; +} + +int fimc40_hwset_input_offset(struct fimc_control *ctrl, u32 pixelformat, + struct v4l2_rect *bounds, + struct v4l2_rect *crop) +{ + u32 cfg_y = 0, cfg_cb = 0; + + if (crop->left || crop->top || + (bounds->width != crop->width) || + (bounds->height != crop->height)) { + switch (pixelformat) { + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_RGB565: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left * 2); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + break; + case V4L2_PIX_FMT_RGB32: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left * 4); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + break; + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV12T: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIICBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIICBOFF_VERTICAL(crop->top / 2); + + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", + __func__, pixelformat); + } + } + + writel(cfg_y, ctrl->regs + S3C_CIIYOFF); + writel(cfg_cb, ctrl->regs + S3C_CIICBOFF); + + return 0; +} + +int fimc50_hwset_input_offset(struct fimc_control *ctrl, u32 pixelformat, + struct v4l2_rect *bounds, + struct v4l2_rect *crop) +{ + u32 cfg_y = 0, cfg_cb = 0, cfg_cr = 0; + + if (crop->left || crop->top || + (bounds->width != crop->width) || + (bounds->height != crop->height)) { + switch (pixelformat) { + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_RGB565: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + break; + case V4L2_PIX_FMT_RGB32: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + break; + case V4L2_PIX_FMT_NV12: /* fall through*/ + case V4L2_PIX_FMT_NV21: /* fall through*/ + case V4L2_PIX_FMT_NV12T: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIICBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIICBOFF_VERTICAL(crop->top); + break; + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIICBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIICBOFF_VERTICAL(crop->top); + break; + case V4L2_PIX_FMT_YUV420: + cfg_y |= S3C_CIIYOFF_HORIZONTAL(crop->left); + cfg_y |= S3C_CIIYOFF_VERTICAL(crop->top); + cfg_cb |= S3C_CIICBOFF_HORIZONTAL(crop->left); + cfg_cb |= S3C_CIICBOFF_VERTICAL(crop->top); + cfg_cr |= S3C_CIICROFF_HORIZONTAL(crop->left); + cfg_cr |= S3C_CIICROFF_VERTICAL(crop->top); + break; + default: + fimc_err("%s: Invalid pixelformt : %d\n", + __func__, pixelformat); + } + } + + writel(cfg_y, ctrl->regs + S3C_CIIYOFF); + writel(cfg_cb, ctrl->regs + S3C_CIICBOFF); + writel(cfg_cr, ctrl->regs + S3C_CIICROFF); + + return 0; +} + +int fimc_hwset_input_offset(struct fimc_control *ctrl, u32 pixelformat, + struct v4l2_rect *bounds, + struct v4l2_rect *crop) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + + if (pdata->hw_ver == 0x50) + fimc50_hwset_input_offset(ctrl, pixelformat, bounds, crop); + else + fimc40_hwset_input_offset(ctrl, pixelformat, bounds, crop); + + return 0; +} + +int fimc_hwset_org_input_size(struct fimc_control *ctrl, u32 width, u32 height) +{ + u32 cfg = 0; + + cfg |= S3C_ORGISIZE_HORIZONTAL(width); + cfg |= S3C_ORGISIZE_VERTICAL(height); + + writel(cfg, ctrl->regs + S3C_ORGISIZE); + + return 0; +} + +int fimc_hwset_org_output_size(struct fimc_control *ctrl, u32 width, u32 height) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + u32 cfg = 0; + + cfg |= S3C_ORGOSIZE_HORIZONTAL(width); + cfg |= S3C_ORGOSIZE_VERTICAL(height); + + writel(cfg, ctrl->regs + S3C_ORGOSIZE); + + if (pdata->hw_ver != 0x40) { + cfg = readl(ctrl->regs + S3C_CIGCTRL); + cfg &= ~S3C_CIGCTRL_CSC_MASK; + + if (width >= FIMC_HD_WIDTH) + cfg |= S3C_CIGCTRL_CSC_ITU709; + else + cfg |= S3C_CIGCTRL_CSC_ITU601; + + writel(cfg, ctrl->regs + S3C_CIGCTRL); + } + + return 0; +} + +int fimc_hwset_ext_output_size(struct fimc_control *ctrl, u32 width, u32 height) +{ + u32 cfg = readl(ctrl->regs + S3C_CIEXTEN); + + cfg &= ~S3C_CIEXTEN_TARGETH_EXT_MASK; + cfg &= ~S3C_CIEXTEN_TARGETV_EXT_MASK; + cfg |= S3C_CIEXTEN_TARGETH_EXT(width); + cfg |= S3C_CIEXTEN_TARGETV_EXT(height); + + writel(cfg, ctrl->regs + S3C_CIEXTEN); + + return 0; +} + +int fimc_hwset_input_addr_style(struct fimc_control *ctrl, u32 pixelformat) +{ + u32 cfg = readl(ctrl->regs + S3C_CIDMAPARAM); + cfg &= ~S3C_CIDMAPARAM_R_MODE_MASK; + + if (pixelformat == V4L2_PIX_FMT_NV12T) + cfg |= S3C_CIDMAPARAM_R_MODE_64X32; + else + cfg |= S3C_CIDMAPARAM_R_MODE_LINEAR; + + writel(cfg, ctrl->regs + S3C_CIDMAPARAM); + + return 0; +} + +int fimc_hwset_output_addr_style(struct fimc_control *ctrl, u32 pixelformat) +{ + u32 cfg = readl(ctrl->regs + S3C_CIDMAPARAM); + cfg &= ~S3C_CIDMAPARAM_W_MODE_MASK; + + if (pixelformat == V4L2_PIX_FMT_NV12T) + cfg |= S3C_CIDMAPARAM_W_MODE_64X32; + else + cfg |= S3C_CIDMAPARAM_W_MODE_LINEAR; + + writel(cfg, ctrl->regs + S3C_CIDMAPARAM); + + return 0; +} + +int fimc_hw_wait_winoff(struct fimc_control *ctrl) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + u32 cfg = readl(ctrl->regs + S3C_CISTATUS); + u32 status = S3C_CISTATUS_GET_LCD_STATUS(cfg); + int i = FIMC_FIFOOFF_CNT; + + if (pdata->hw_ver == 0x40) + return 0; + + while (status && i--) { + cfg = readl(ctrl->regs + S3C_CISTATUS); + status = S3C_CISTATUS_GET_LCD_STATUS(cfg); + } + + if (i < 1) { + fimc_err("Fail : %s\n", __func__); + return -EBUSY; + } else + return 0; +} + +int fimc_hw_wait_stop_input_dma(struct fimc_control *ctrl) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + u32 cfg = readl(ctrl->regs + S3C_MSCTRL); + u32 status = S3C_MSCTRL_GET_INDMA_STATUS(cfg); + int i = FIMC_FIFOOFF_CNT, j = FIMC_FIFOOFF_CNT; + + if (pdata->hw_ver == 0x40) + return 0; + + while (status && i--) { + cfg = readl(ctrl->regs + S3C_MSCTRL); + status = S3C_MSCTRL_GET_INDMA_STATUS(cfg); + } + + cfg = readl(ctrl->regs + S3C_CISTATUS); + status = S3C_CISTATUS_GET_ENVID_STATUS(cfg); + while (status && j--) { + cfg = readl(ctrl->regs + S3C_CISTATUS); + status = S3C_CISTATUS_GET_ENVID_STATUS(cfg); + } + + if ((i < 1) || (j < 1)) { + fimc_err("Fail : %s\n", __func__); + return -EBUSY; + } else { + return 0; + } +} + +int fimc_hwset_input_lineskip(struct fimc_control *ctrl) +{ + struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); + u32 cfg = 0; + + if (pdata->hw_ver == 0x40) + return 0; + + cfg = S3C_CIILINESKIP(ctrl->sc.skipline); + + writel(cfg, ctrl->regs + S3C_CIILINESKIP_Y); + writel(cfg, ctrl->regs + S3C_CIILINESKIP_CB); + writel(cfg, ctrl->regs + S3C_CIILINESKIP_CR); + + return 0; +} + +int fimc_hw_reset_camera(struct fimc_control *ctrl) +{ + return 0; +} diff --git a/drivers/media/video/samsung/fimc/fimc_v4l2.c b/drivers/media/video/samsung/fimc/fimc_v4l2.c new file mode 100644 index 0000000..73202f4 --- /dev/null +++ b/drivers/media/video/samsung/fimc/fimc_v4l2.c @@ -0,0 +1,303 @@ +/* linux/drivers/media/video/samsung/fimc/fimc_v4l2.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * V4L2 interface support file for Samsung Camera Interface (FIMC) 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/fs.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/videodev2.h> +#include <linux/videodev2_samsung.h> +#include <media/v4l2-ioctl.h> +#include <plat/fimc.h> +#include <linux/clk.h> + +#include "fimc.h" + +static int fimc_querycap(struct file *filp, void *fh, + struct v4l2_capability *cap) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + + fimc_info1("%s: called\n", __func__); + + strcpy(cap->driver, "Samsung FIMC Driver"); + strlcpy(cap->card, ctrl->vd->name, sizeof(cap->card)); + sprintf(cap->bus_info, "FIMC AHB-bus"); + + cap->version = 0; + cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_STREAMING); + + return 0; +} + +static int fimc_reqbufs(struct file *filp, void *fh, + struct v4l2_requestbuffers *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_reqbufs_capture(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_reqbufs_output(fh, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int fimc_querybuf(struct file *filp, void *fh, struct v4l2_buffer *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_querybuf_capture(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_querybuf_output(fh, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +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) { + ret = fimc_g_ctrl_output(fh, c); + } else { + fimc_err("%s: Invalid case\n", __func__); + return -EINVAL; + } + + return ret; +} + +static int fimc_s_ctrl(struct file *filp, void *fh, struct v4l2_control *c) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (ctrl->cap != NULL) { + ret = fimc_s_ctrl_capture(fh, c); + } else if (ctrl->out != NULL) { + ret = fimc_s_ctrl_output(filp, fh, c); + } else { + fimc_err("%s: Invalid case\n", __func__); + return -EINVAL; + } + + return ret; +} + +static int fimc_s_ext_ctrls(struct file *filp, void *fh, + struct v4l2_ext_controls *c) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (ctrl->cap != NULL) { + ret = fimc_s_ext_ctrls_capture(fh, c); + } else { + fimc_err("%s: Invalid case\n", __func__); + return -EINVAL; + } + + return ret; +} + +static int fimc_cropcap(struct file *filp, void *fh, struct v4l2_cropcap *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_cropcap_capture(fh, a); + } else if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_cropcap_output(fh, a); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int fimc_g_crop(struct file *filp, void *fh, struct v4l2_crop *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_g_crop_capture(fh, a); + } else if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_g_crop_output(fh, a); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int fimc_s_crop(struct file *filp, void *fh, struct v4l2_crop *a) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_s_crop_capture(fh, a); + } else if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_s_crop_output(fh, a); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int fimc_streamon(struct file *filp, void *fh, enum v4l2_buf_type i) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct s3c_platform_fimc *pdata; + int ret = -1; + + pdata = to_fimc_plat(ctrl->dev); + + if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_streamon_capture(fh); + } else if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_streamon_output(fh); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int fimc_streamoff(struct file *filp, void *fh, enum v4l2_buf_type i) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + struct s3c_platform_fimc *pdata; + int ret = -1; + + pdata = to_fimc_plat(ctrl->dev); + + if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_streamoff_capture(fh); + } else if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_streamoff_output(fh); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int fimc_qbuf(struct file *filp, void *fh, struct v4l2_buffer *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_qbuf_capture(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_qbuf_output(fh, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +static int fimc_dqbuf(struct file *filp, void *fh, struct v4l2_buffer *b) +{ + struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; + int ret = -1; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = fimc_dqbuf_capture(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ret = fimc_dqbuf_output(fh, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } + + return ret; +} + +const struct v4l2_ioctl_ops fimc_v4l2_ops = { + .vidioc_querycap = fimc_querycap, + .vidioc_reqbufs = fimc_reqbufs, + .vidioc_querybuf = fimc_querybuf, + .vidioc_g_ctrl = fimc_g_ctrl, + .vidioc_s_ctrl = fimc_s_ctrl, + .vidioc_s_ext_ctrls = fimc_s_ext_ctrls, + .vidioc_cropcap = fimc_cropcap, + .vidioc_g_crop = fimc_g_crop, + .vidioc_s_crop = fimc_s_crop, + .vidioc_streamon = fimc_streamon, + .vidioc_streamoff = fimc_streamoff, + .vidioc_qbuf = fimc_qbuf, + .vidioc_dqbuf = fimc_dqbuf, + .vidioc_enum_fmt_vid_cap = fimc_enum_fmt_vid_capture, + .vidioc_g_fmt_vid_cap = fimc_g_fmt_vid_capture, + .vidioc_s_fmt_vid_cap = fimc_s_fmt_vid_capture, + .vidioc_try_fmt_vid_cap = fimc_try_fmt_vid_capture, + .vidioc_enum_input = fimc_enum_input, + .vidioc_g_input = fimc_g_input, + .vidioc_s_input = fimc_s_input, + .vidioc_g_parm = fimc_g_parm, + .vidioc_s_parm = fimc_s_parm, + .vidioc_queryctrl = fimc_queryctrl, + .vidioc_querymenu = fimc_querymenu, + .vidioc_g_fmt_vid_out = fimc_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = fimc_s_fmt_vid_out, + .vidioc_try_fmt_vid_out = fimc_try_fmt_vid_out, + .vidioc_g_fbuf = fimc_g_fbuf, + .vidioc_s_fbuf = fimc_s_fbuf, + .vidioc_try_fmt_vid_overlay = fimc_try_fmt_overlay, + .vidioc_g_fmt_vid_overlay = fimc_g_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = fimc_s_fmt_vid_overlay, +}; diff --git a/drivers/media/video/samsung/jpeg_v2/Kconfig b/drivers/media/video/samsung/jpeg_v2/Kconfig new file mode 100644 index 0000000..291aa90 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/Kconfig @@ -0,0 +1,15 @@ +# +# Configuration for JPEG +# + +config VIDEO_JPEG_V2 + bool "Samsung JPEG driver" + depends on VIDEO_SAMSUNG + default n + ---help--- + This is a JPEG for Samsung S5PV210 + +config VIDEO_JPEG_DEBUG + bool "print JPEG debug message" + depends on VIDEO_JPEG_V2 + default n diff --git a/drivers/media/video/samsung/jpeg_v2/Makefile b/drivers/media/video/samsung/jpeg_v2/Makefile new file mode 100644 index 0000000..b7db901 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_VIDEO_JPEG_V2) += jpg_mem.o jpg_misc.o jpg_opr.o s3c-jpeg.o +EXTRA_CFLAGS += -Idrivers/media/video + diff --git a/drivers/media/video/samsung/jpeg_v2/jpg_conf.h b/drivers/media/video/samsung/jpeg_v2/jpg_conf.h new file mode 100644 index 0000000..99fcb0d --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/jpg_conf.h @@ -0,0 +1,282 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/jpg-conf.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Definition Quantization Table for Jpeg encoder/docoder + * + * 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 __JPG_CONF_H__ +#define __JPG_CONF_H__ + + +const unsigned char qtbl_luminance[4][64] = { + /* level 1 - high quality */ + { + 8, 6, 6, 8, 12, 14, 16, 17, + 6, 6, 6, 8, 10, 13, 12, 15, + 6, 6, 7, 8, 13, 14, 18, 24, + 8, 8, 8, 14, 13, 19, 24, 35, + 12, 10, 13, 13, 20, 26, 34, 39, + 14, 13, 14, 19, 26, 34, 39, 39, + 16, 12, 18, 24, 34, 39, 39, 39, + 17, 15, 24, 35, 39, 39, 39, 39 + }, + + /* level 2 */ + { + 12, 8, 8, 12, 17, 21, 24, 23, + 8, 9, 9, 11, 15, 19, 18, 23, + 8, 9, 10, 12, 19, 20, 27, 36, + 12, 11, 12, 21, 20, 28, 36, 53, + 17, 15, 19, 20, 30, 39, 51, 59, + 21, 19, 20, 28, 39, 51, 59, 59, + 24, 18, 27, 36, 51, 59, 59, 59, + 23, 23, 36, 53, 59, 59, 59, 59 + }, + + /* level 3 */ + { + 16, 11, 11, 16, 23, 27, 31, 30, + 11, 12, 12, 15, 20, 23, 23, 30, + 11, 12, 13, 16, 23, 26, 35, 47, + 16, 15, 16, 23, 26, 37, 47, 64, + 23, 20, 23, 26, 39, 51, 64, 64, + 27, 23, 26, 37, 51, 64, 64, 64, + 31, 23, 35, 47, 64, 64, 64, 64, + 30, 30, 47, 64, 64, 64, 64, 64 + + }, + + /* level 4 - low quality */ + { + 20, 16, 25, 39, 50, 46, 62, 68, + 16, 18, 23, 38, 38, 53, 65, 68, + 25, 23, 31, 38, 53, 65, 68, 68, + 39, 38, 38, 53, 65, 68, 68, 68, + 50, 38, 53, 65, 68, 68, 68, 68, + 46, 53, 65, 68, 68, 68, 68, 68, + 62, 65, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + } + + +}; + +const unsigned char qtbl_chrominance[4][64] = { + /* level 1 - high quality */ + { + 9, 8, 9, 11, 14, 17, 19, 24, + 8, 10, 9, 11, 14, 13, 17, 22, + 9, 9, 13, 14, 13, 15, 23, 26, + 11, 11, 14, 14, 15, 20, 26, 33, + 14, 14, 13, 15, 20, 24, 33, 39, + 17, 13, 15, 20, 24, 32, 39, 39, + 19, 17, 23, 26, 33, 39, 39, 39, + 24, 22, 26, 33, 39, 39, 39, 39 + }, + + /* level 2 */ + { + 13, 11, 13, 16, 20, 20, 29, 37, + 11, 14, 14, 14, 16, 20, 26, 32, + 13, 14, 15, 17, 20, 23, 35, 40, + 16, 14, 17, 21, 23, 30, 40, 50, + 20, 16, 20, 23, 30, 37, 50, 59, + 20, 20, 23, 30, 37, 48, 59, 59, + 29, 26, 35, 40, 50, 59, 59, 59, + 37, 32, 40, 50, 59, 59, 59, 59 + }, + + + /* level 3 */ + { + 17, 15, 17, 21, 20, 26, 38, 48, + 15, 19, 18, 17, 20, 26, 35, 43, + 17, 18, 20, 22, 26, 30, 46, 53, + 21, 17, 22, 28, 30, 39, 53, 64, + 20, 20, 26, 30, 39, 48, 64, 64, + 26, 26, 30, 39, 48, 63, 64, 64, + 38, 35, 46, 53, 64, 64, 64, 64, + 48, 43, 53, 64, 64, 64, 64, 64 + + + }, + + /* level 4 - low quality */ + { + 21, 25, 32, 38, 54, 68, 68, 68, + 25, 28, 24, 38, 54, 68, 68, 68, + 32, 24, 32, 43, 66, 68, 68, 68, + 38, 38, 43, 53, 68, 68, 68, 68, + 54, 54, 66, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + + } + +}; + +const unsigned char qtbl0[64] = { + 0x10, 0x0B, 0x0A, 0x10, 0x18, 0x28, 0x33, 0x3D, + 0x0C, 0x0C, 0x0E, 0x13, 0x1A, 0x3A, 0x3C, 0x37, + 0x0E, 0x0D, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38, + 0x0E, 0x11, 0x16, 0x1D, 0x33, 0x57, 0x50, 0x3E, + 0x12, 0x16, 0x25, 0x38, 0x44, 0x6D, 0x67, 0x4D, + 0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5C, + 0x31, 0x40, 0x4E, 0x57, 0x67, 0x79, 0x78, 0x65, + 0x48, 0x5C, 0x5F, 0x62, 0x70, 0x64, 0x67, 0x63 +}; + +/* Added Quantization Table */ +const unsigned char std_chrominance_quant_tbl_plus[64] = { + 0x11, 0x12, 0x18, 0x2F, 0x63, 0x63, 0x63, 0x63, + 0x12, 0x15, 0x1A, 0x42, 0x63, 0x63, 0x63, 0x63, + 0x18, 0x1A, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x2F, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 +}; + +/* Quantization Table0 */ +unsigned char std_luminance_quant_tbl[64] = { + 1, 1, 2, 1, 1, 2, 2, 2, + 2, 3, 2, 2, 3, 3, 6, 4, + 3, 3, 3, 3, 7, 5, 8, 4, + 6, 8, 8, 10, 9, 8, 7, 11, + 8, 10, 14, 13, 11, 10, 10, 12, + 10, 8, 8, 11, 16, 12, 12, 13, + 15, 15, 15, 15, 9, 11, 16, 17, + 15, 14, 17, 13, 14, 14, 14, 1 +}; + +/* Quantization Table1 */ +unsigned char std_chrominance_quant_tbl[64] = { + 4, 4, 4, 5, 4, 5, 9, 5, + 5, 9, 15, 10, 8, 10, 15, 26, + 19, 9, 9, 19, 26, 26, 26, 26, + 13, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26 +}; + +/* Huffman Table */ +unsigned char hdctbl0[16] = { + 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 +}; + +unsigned char hdctblg0[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb +}; + +unsigned char hactbl0[16] = { + 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d +}; + +const unsigned char hactblg0[162] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +/* Huffman Table0 */ +unsigned char len_dc_luminance[16] = { + 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 +}; + +unsigned char val_dc_luminance[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + +unsigned char len_ac_luminance[16] = { + 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d +}; + +unsigned char val_ac_luminance[162] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +/* Huffman Table1 */ +unsigned char len_dc_chrominance[16] = { + 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 +}; + +unsigned char val_dc_chrominance[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 +}; + +unsigned char len_ac_chrominance[16] = { + 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 +}; + +unsigned char val_ac_chrominance[162] = { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x81, 0x08, 0x14, 0x42, + 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, + 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, + 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, + 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9 +}; + +#endif diff --git a/drivers/media/video/samsung/jpeg_v2/jpg_mem.c b/drivers/media/video/samsung/jpeg_v2/jpg_mem.c new file mode 100644 index 0000000..5f46b8d --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/jpg_mem.c @@ -0,0 +1,61 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/jpg_mem.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Operation for Jpeg encoder/docoder with memory + * + * 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/io.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/types.h> + +#include "jpg_mem.h" +#include "jpg_misc.h" +#include "jpg_opr.h" + +/* + * Function: phy_to_vir_addr + * Parameters: phy_addr, mem_size + * Return Value: vir_addr + * Implementation Notes: memory mapping from physical addr to virtual addr + */ +void *phy_to_vir_addr(unsigned int phy_addr, int mem_size) +{ + void *reserved_mem; + + reserved_mem = (void *)ioremap((unsigned long)phy_addr, (int)mem_size); + + if (reserved_mem == NULL) { + jpg_err("phyical to virtual memory mapping was failed!\r\n"); + return NULL; + } + + return reserved_mem; +} + +void *mem_move(void *dst, const void *src, unsigned int size) +{ + return memmove(dst, src, size); +} + +void *mem_alloc(unsigned int size) +{ + void *alloc_mem; + + alloc_mem = kmalloc((int)size, GFP_KERNEL); + + if (alloc_mem == NULL) { + jpg_err("memory allocation failed!\r\n"); + return NULL; + } + + return alloc_mem; +} diff --git a/drivers/media/video/samsung/jpeg_v2/jpg_mem.h b/drivers/media/video/samsung/jpeg_v2/jpg_mem.h new file mode 100644 index 0000000..3beb549 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/jpg_mem.h @@ -0,0 +1,111 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/jpg_mem.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Definition for Operation of Jpeg encoder/docoder with memory + * + * 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 __JPG_MEM_H__ +#define __JPG_MEM_H__ + +#include "jpg_misc.h" + +#include <linux/version.h> +#include <plat/media.h> +#include <mach/media.h> + +#define JPG_REG_BASE_ADDR (0xFB600000) + +#define jpg_data_base_addr \ + (unsigned int)s5p_get_media_memory_bank(S5P_MDEV_JPEG, 0) +#define jpg_reserved_mem_size \ + ((unsigned int)s5p_get_media_memsize_bank(S5P_MDEV_JPEG, 0)) + +#define COEF1_RGB_2_YUV 0x4d971e +#define COEF2_RGB_2_YUV 0x2c5783 +#define COEF3_RGB_2_YUV 0x836e13 + +/* + * JPEG HW Register Macro Definition + */ +#define JPG_1BIT_MASK 1 +#define JPG_4BIT_MASK 0xF + +/* SubSampling_Mode Mask is JPGMOD Register [2:0] bits mask */ +#define JPG_SMPL_MODE_MASK 0x07 + +/* Restart Interval value in JPGDRI Register is 2*/ +#define JPG_RESTART_INTRAVEL 2 + +/* HCLK_JPEG is CLK_GATE_D1_1 Register 5th bit */ +#define JPG_HCLK_JPEG_BIT 5 +/* SubSampling_Mode is JPGMOD Register 0th bit */ +#define JPG_SMPL_MODE_BIT 0 +/* Quantization Table #1 is JPGQHNO Register 8th bit */ +#define JPG_QUANT_TABLE1_BIT 8 +/* Quantization Table #2 is JPGQHNO Register 10th bit */ +#define JPG_QUANT_TABLE2_BIT 10 +/* Quantization Table #3 is JPGQHNO Register 12th bit */ +#define JPG_QUANT_TABLE3_BIT 12 +/* Mode Sel is JPGCMOD Register 5th bit */ +#define JPG_MODE_SEL_BIT 5 + +#define JPG_DECODE (0x1 << 3) +#define JPG_ENCODE (0x0 << 3) + +#define JPG_RESERVE_ZERO (0b000 << 2) + +#define ENABLE_MOTION_ENC (0x1<<3) +#define DISABLE_MOTION_ENC (0x0<<3) + +#define ENABLE_MOTION_DEC (0x1<<0) +#define DISABLE_MOTION_DEC (0x0<<0) + +#define ENABLE_HW_DEC (0x1<<2) +#define DISABLE_HW_DEC (0x0<<2) + +#define INCREMENTAL_DEC (0x1<<3) +#define NORMAL_DEC (0x0<<3) +#define YCBCR_MEMORY (0x1<<5) + +#define ENABLE_IRQ (0xf<<3) + +struct jpegv2_limits { + unsigned int max_main_width; + unsigned int max_main_height; + unsigned int max_thumb_width; + unsigned int max_thumb_height; +}; + +struct jpegv2_buf { + unsigned int main_stream_start; + unsigned int main_stream_size; + unsigned int main_frame_start; + unsigned int main_frame_size; + unsigned int thumb_stream_start; + unsigned int thumb_stream_size; + unsigned int thumb_frame_start; + unsigned int thumb_frame_size; + unsigned int total_buf_size; +}; + +struct s5pc110_jpg_ctx { + unsigned int jpg_data_addr; + unsigned int img_data_addr; + unsigned int jpg_thumb_data_addr; + unsigned int img_thumb_data_addr; + int caller_process; + struct jpegv2_limits *limits; + struct jpegv2_buf *bufinfo; +}; + +void *phy_to_vir_addr(unsigned int phy_addr, int mem_size); +void *mem_move(void *dst, const void *src, unsigned int size); +void *mem_alloc(unsigned int size); +#endif + diff --git a/drivers/media/video/samsung/jpeg_v2/jpg_misc.c b/drivers/media/video/samsung/jpeg_v2/jpg_misc.c new file mode 100644 index 0000000..964baf6 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/jpg_misc.c @@ -0,0 +1,81 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/jpg_misc.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Operation for Jpeg encoder/docoder with mutex + * + * 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 <stdarg.h> +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> + +#include <linux/version.h> + +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/wait.h> + +#include "jpg_misc.h" +#include "jpg_mem.h" + +static struct mutex *h_mutex; + +/* + * Function: create_jpg_mutex + * Implementation Notes: Create Mutex handle + */ +struct mutex *create_jpg_mutex(void) +{ + h_mutex = kmalloc(sizeof(struct mutex), GFP_KERNEL); + + if (h_mutex == NULL) + return NULL; + + mutex_init(h_mutex); + + return h_mutex; +} + +/* + * Function: lock_jpg_mutex + * Implementation Notes: lock mutex + */ +unsigned long lock_jpg_mutex(void) +{ + mutex_lock(h_mutex); + return 1; +} + +/* + * Function: unlock_jpg_mutex + * Implementation Notes: unlock mutex +*/ +unsigned long unlock_jpg_mutex(void) +{ + mutex_unlock(h_mutex); + + return 1; +} + + +/* + * Function: delete_jpg_mutex + * Implementation Notes: delete mutex handle + */ +void delete_jpg_mutex(void) +{ + if (h_mutex == NULL) + return; + + mutex_destroy(h_mutex); +} + diff --git a/drivers/media/video/samsung/jpeg_v2/jpg_misc.h b/drivers/media/video/samsung/jpeg_v2/jpg_misc.h new file mode 100644 index 0000000..31422d2 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/jpg_misc.h @@ -0,0 +1,27 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/jpg_misc.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Definition for Operation of Jpeg encoder/docoder with mutex + * + * 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 __JPG_MISC_H__ +#define __JPG_MISC_H__ + +#include <linux/types.h> + +enum BOOL {FALSE, TRUE}; + +#define INT_TIMEOUT 1000 + +struct mutex *create_jpg_mutex(void); +unsigned long lock_jpg_mutex(void); +unsigned long unlock_jpg_mutex(void); +void delete_jpg_mutex(void); + +#endif diff --git a/drivers/media/video/samsung/jpeg_v2/jpg_opr.c b/drivers/media/video/samsung/jpeg_v2/jpg_opr.c new file mode 100644 index 0000000..51a7979 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/jpg_opr.c @@ -0,0 +1,320 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/jpg_opr.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Operation for Jpeg encoder/docoder + * + * 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/delay.h> +#include <linux/io.h> + +#include "jpg_mem.h" +#include "jpg_misc.h" +#include "jpg_opr.h" +#include "jpg_conf.h" + +#include "regs-jpeg.h" + +enum { + UNKNOWN, + BASELINE = 0xC0, + EXTENDED_SEQ = 0xC1, + PROGRESSIVE = 0xC2 +} jpg_sof_marker; + +enum jpg_return_status wait_for_interrupt(void) +{ + if (interruptible_sleep_on_timeout(&wait_queue_jpeg, \ + INT_TIMEOUT) == 0) { + jpg_err("waiting for interrupt is timeout\n"); + } + + return jpg_irq_reason; +} + +enum jpg_return_status decode_jpg(struct s5pc110_jpg_ctx *jpg_ctx, + struct jpg_dec_proc_param *dec_param) +{ + int ret; + enum sample_mode sample_mode; + unsigned int width, height; + jpg_dbg("enter decode_jpg function\n"); + + if (jpg_ctx) + reset_jpg(jpg_ctx); + else { + jpg_err("jpg ctx is NULL\n"); + return JPG_FAIL; + } + +/* set jpeg clock register : power on */ + writel(readl(s3c_jpeg_base + S3C_JPEG_CLKCON_REG) | + (S3C_JPEG_CLKCON_REG_POWER_ON_ACTIVATE), + s3c_jpeg_base + S3C_JPEG_CLKCON_REG); + /* set jpeg mod register : decode */ + writel(readl(s3c_jpeg_base + S3C_JPEG_MOD_REG) | + (S3C_JPEG_MOD_REG_PROC_DEC), + s3c_jpeg_base + S3C_JPEG_MOD_REG); + /* set jpeg interrupt setting register */ + writel(readl(s3c_jpeg_base + S3C_JPEG_INTSE_REG) | + (S3C_JPEG_INTSE_REG_RSTM_INT_EN | + S3C_JPEG_INTSE_REG_DATA_NUM_INT_EN | + S3C_JPEG_INTSE_REG_FINAL_MCU_NUM_INT_EN), + s3c_jpeg_base + S3C_JPEG_INTSE_REG); + /* set jpeg deocde ouput format register */ + writel(readl(s3c_jpeg_base + S3C_JPEG_OUTFORM_REG) & + ~(S3C_JPEG_OUTFORM_REG_YCBCY420), + s3c_jpeg_base + S3C_JPEG_OUTFORM_REG); + writel(readl(s3c_jpeg_base + S3C_JPEG_OUTFORM_REG) | + (dec_param->out_format << 0), + s3c_jpeg_base + S3C_JPEG_OUTFORM_REG); + + /* set the address of compressed input data */ + writel(jpg_ctx->img_data_addr, s3c_jpeg_base + S3C_JPEG_IMGADR_REG); + + /* set the address of decompressed image */ + writel(jpg_ctx->jpg_data_addr, s3c_jpeg_base + S3C_JPEG_JPGADR_REG); + + /* start decoding */ + writel(readl(s3c_jpeg_base + S3C_JPEG_JRSTART_REG) | + S3C_JPEG_JRSTART_REG_ENABLE, + s3c_jpeg_base + S3C_JPEG_JSTART_REG); + + ret = wait_for_interrupt(); + + if (ret != OK_ENC_OR_DEC) { + jpg_err("jpg decode error(%d)\n", ret); + return JPG_FAIL; + } + + sample_mode = get_sample_type(jpg_ctx); + jpg_dbg("sample_mode : %d\n", sample_mode); + + if (sample_mode == JPG_SAMPLE_UNKNOWN) { + jpg_err("jpg has invalid sample_mode\r\n"); + return JPG_FAIL; + } + + dec_param->sample_mode = sample_mode; + + get_xy(jpg_ctx, &width, &height); + jpg_dbg("decode size:: width : %d height : %d\n", width, height); + + dec_param->data_size = get_yuv_size(dec_param->out_format, + width, height); + dec_param->width = width; + dec_param->height = height; + + return JPG_SUCCESS; +} + +void reset_jpg(struct s5pc110_jpg_ctx *jpg_ctx) +{ + jpg_dbg("s3c_jpeg_base %p\n", s3c_jpeg_base); + writel(S3C_JPEG_SW_RESET_REG_ENABLE, + s3c_jpeg_base + S3C_JPEG_SW_RESET_REG); + + do { + writel(S3C_JPEG_SW_RESET_REG_ENABLE, + s3c_jpeg_base + S3C_JPEG_SW_RESET_REG); + } while (((readl(s3c_jpeg_base + S3C_JPEG_SW_RESET_REG)) + & S3C_JPEG_SW_RESET_REG_ENABLE) + == S3C_JPEG_SW_RESET_REG_ENABLE); +} + +enum sample_mode get_sample_type(struct s5pc110_jpg_ctx *jpg_ctx) +{ + unsigned long jpgMode; + enum sample_mode sample_mode = JPG_SAMPLE_UNKNOWN; + + jpgMode = readl(s3c_jpeg_base + S3C_JPEG_MOD_REG); + + sample_mode = + ((jpgMode & JPG_SMPL_MODE_MASK) == JPG_444) ? JPG_444 : + ((jpgMode & JPG_SMPL_MODE_MASK) == JPG_422) ? JPG_422 : + ((jpgMode & JPG_SMPL_MODE_MASK) == JPG_420) ? JPG_420 : + ((jpgMode & JPG_SMPL_MODE_MASK) == JPG_400) ? JPG_400 : + ((jpgMode & JPG_SMPL_MODE_MASK) == JPG_411) ? JPG_411 : + JPG_SAMPLE_UNKNOWN; + + return sample_mode; +} + +void get_xy(struct s5pc110_jpg_ctx *jpg_ctx, unsigned int *x, unsigned int *y) +{ + *x = (readl(s3c_jpeg_base + S3C_JPEG_X_U_REG)<<8)| + readl(s3c_jpeg_base + S3C_JPEG_X_L_REG); + *y = (readl(s3c_jpeg_base + S3C_JPEG_Y_U_REG)<<8)| + readl(s3c_jpeg_base + S3C_JPEG_Y_L_REG); +} + +unsigned int get_yuv_size(enum out_mode out_format, + unsigned int width, unsigned int height) +{ + switch (out_format) { + case YCBCR_422: + + if (width % 16 != 0) + width += 16 - (width % 16); + + if (height % 8 != 0) + height += 8 - (height % 8); + + break; + + case YCBCR_420: + + if (width % 16 != 0) + width += 16 - (width % 16); + + if (height % 16 != 0) + height += 16 - (height % 16); + + break; + + case YCBCR_SAMPLE_UNKNOWN: + break; + } + + jpg_dbg("get_yuv_size width(%d) height(%d)\n", width, height); + + switch (out_format) { + case YCBCR_422: + return width * height * 2; + case YCBCR_420: + return (width * height) + (width * height >> 1); + default: + return 0; + } +} + +enum jpg_return_status encode_jpg(struct s5pc110_jpg_ctx *jpg_ctx, + struct jpg_enc_proc_param *enc_param) +{ + + unsigned int i, ret; + unsigned int cmd_val; + + if (enc_param->width <= 0 + || enc_param->width > jpg_ctx->limits->max_main_width + || enc_param->height <= 0 + || enc_param->height > jpg_ctx->limits->max_main_height) { + jpg_err("::encoder : width: %d, height: %d\n", + enc_param->width, enc_param->height); + jpg_err("::encoder : invalid width/height\n"); + return JPG_FAIL; + } + + /* SW reset */ + if (jpg_ctx) + reset_jpg(jpg_ctx); + else { + jpg_err("::jpg ctx is NULL\n"); + return JPG_FAIL; + } + /* set jpeg clock register : power on */ + writel(readl(s3c_jpeg_base + S3C_JPEG_CLKCON_REG) | + (S3C_JPEG_CLKCON_REG_POWER_ON_ACTIVATE), + s3c_jpeg_base + S3C_JPEG_CLKCON_REG); + /* set jpeg mod register : encode */ + writel(readl(s3c_jpeg_base + S3C_JPEG_CMOD_REG) | + (enc_param->in_format << JPG_MODE_SEL_BIT), + s3c_jpeg_base + S3C_JPEG_CMOD_REG); + cmd_val = (enc_param->sample_mode == JPG_422) ? + (S3C_JPEG_MOD_REG_SUBSAMPLE_422) : + (S3C_JPEG_MOD_REG_SUBSAMPLE_420); + + writel(cmd_val | S3C_JPEG_MOD_REG_PROC_ENC, + s3c_jpeg_base + S3C_JPEG_MOD_REG); + + /* set DRI(Define Restart Interval) */ + writel(JPG_RESTART_INTRAVEL, s3c_jpeg_base + S3C_JPEG_DRI_L_REG); + writel((JPG_RESTART_INTRAVEL>>8), s3c_jpeg_base + S3C_JPEG_DRI_U_REG); + + writel(S3C_JPEG_QHTBL_REG_QT_NUM1, s3c_jpeg_base + S3C_JPEG_QTBL_REG); + writel(0x00, s3c_jpeg_base + S3C_JPEG_HTBL_REG); + + /* Horizontal resolution */ + writel((enc_param->width>>8), s3c_jpeg_base + S3C_JPEG_X_U_REG); + writel(enc_param->width, s3c_jpeg_base + S3C_JPEG_X_L_REG); + + /* Vertical resolution */ + writel((enc_param->height>>8), s3c_jpeg_base + S3C_JPEG_Y_U_REG); + writel(enc_param->height, s3c_jpeg_base + S3C_JPEG_Y_L_REG); + + jpg_dbg("enc_param->enc_type : %d\n", enc_param->enc_type); + + if (enc_param->enc_type == JPG_MAIN) { + jpg_dbg("encode image size width: %d, height: %d\n", + enc_param->width, enc_param->height); + writel(jpg_ctx->img_data_addr, + s3c_jpeg_base + S3C_JPEG_IMGADR_REG); + writel(jpg_ctx->jpg_data_addr, + s3c_jpeg_base + S3C_JPEG_JPGADR_REG); + } else { /* thumbnail encoding */ + jpg_dbg("thumb image size width: %d, height: %d\n", + enc_param->width, enc_param->height); + writel(jpg_ctx->img_thumb_data_addr, + s3c_jpeg_base + S3C_JPEG_IMGADR_REG); + writel(jpg_ctx->jpg_thumb_data_addr, + s3c_jpeg_base + S3C_JPEG_JPGADR_REG); + } + + /* Coefficient value 1~3 for RGB to YCbCr */ + writel(COEF1_RGB_2_YUV, s3c_jpeg_base + S3C_JPEG_COEF1_REG); + writel(COEF2_RGB_2_YUV, s3c_jpeg_base + S3C_JPEG_COEF2_REG); + writel(COEF3_RGB_2_YUV, s3c_jpeg_base + S3C_JPEG_COEF3_REG); + + /* Quantiazation and Huffman Table setting */ + for (i = 0; i < 64; i++) { + writel((unsigned int)qtbl_luminance[enc_param->quality][i], + s3c_jpeg_base + S3C_JPEG_QTBL0_REG + (i*0x04)); + } + for (i = 0; i < 64; i++) { + writel((unsigned int)qtbl_chrominance[enc_param->quality][i], + s3c_jpeg_base + S3C_JPEG_QTBL1_REG + (i*0x04)); + } + for (i = 0; i < 16; i++) { + writel((unsigned int)hdctbl0[i], + s3c_jpeg_base + S3C_JPEG_HDCTBL0_REG + (i*0x04)); + } + for (i = 0; i < 12; i++) { + writel((unsigned int)hdctblg0[i], + s3c_jpeg_base + S3C_JPEG_HDCTBLG0_REG + (i*0x04)); + } + for (i = 0; i < 16; i++) { + writel((unsigned int)hactbl0[i], + s3c_jpeg_base + S3C_JPEG_HACTBL0_REG + (i*0x04)); + } + for (i = 0; i < 162; i++) { + writel((unsigned int)hactblg0[i], + s3c_jpeg_base + S3C_JPEG_HACTBLG0_REG + (i*0x04)); + } + writel(readl(s3c_jpeg_base + S3C_JPEG_INTSE_REG) | + (S3C_JPEG_INTSE_REG_RSTM_INT_EN | + S3C_JPEG_INTSE_REG_DATA_NUM_INT_EN | + S3C_JPEG_INTSE_REG_FINAL_MCU_NUM_INT_EN), + s3c_jpeg_base + S3C_JPEG_INTSE_REG); + + writel(readl(s3c_jpeg_base + S3C_JPEG_JSTART_REG) | + S3C_JPEG_JSTART_REG_ENABLE, + s3c_jpeg_base + S3C_JPEG_JSTART_REG); + ret = wait_for_interrupt(); + + if (ret != OK_ENC_OR_DEC) { + jpg_err("jpeg encoding error(%d)\n", ret); + return JPG_FAIL; + } + + enc_param->file_size = readl(s3c_jpeg_base + S3C_JPEG_CNT_U_REG) << 16; + enc_param->file_size |= readl(s3c_jpeg_base + S3C_JPEG_CNT_M_REG) << 8; + enc_param->file_size |= readl(s3c_jpeg_base + S3C_JPEG_CNT_L_REG); + + return JPG_SUCCESS; + +} diff --git a/drivers/media/video/samsung/jpeg_v2/jpg_opr.h b/drivers/media/video/samsung/jpeg_v2/jpg_opr.h new file mode 100644 index 0000000..b8c21d0 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/jpg_opr.h @@ -0,0 +1,158 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/jpg_opr.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Definition for Operation of Jpeg encoder/docoder + * + * 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 __JPG_OPR_H__ +#define __JPG_OPR_H__ + +#include <linux/interrupt.h> + +extern void __iomem *s3c_jpeg_base; +extern int jpg_irq_reason; + +/* debug macro */ +#define JPG_DEBUG(fmt, ...) \ + do { \ + printk(KERN_DEBUG \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + + +#define JPG_WARN(fmt, ...) \ + do { \ + printk(KERN_WARNING \ + fmt, ##__VA_ARGS__); \ + } while (0) + + + +#define JPG_ERROR(fmt, ...) \ + do { \ + printk(KERN_ERR \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + + + +#ifdef CONFIG_VIDEO_JPEG_DEBUG +#define jpg_dbg(fmt, ...) JPG_DEBUG(fmt, ##__VA_ARGS__) +#else +#define jpg_dbg(fmt, ...) +#endif + +#define jpg_warn(fmt, ...) JPG_WARN(fmt, ##__VA_ARGS__) +#define jpg_err(fmt, ...) JPG_ERROR(fmt, ##__VA_ARGS__) + +extern wait_queue_head_t wait_queue_jpeg; + +enum jpg_return_status { + JPG_FAIL, + JPG_SUCCESS, + OK_HD_PARSING, + ERR_HD_PARSING, + OK_ENC_OR_DEC, + ERR_ENC_OR_DEC, + ERR_UNKNOWN +}; + +enum image_type { + JPG_RGB16, + JPG_YCBYCR, + JPG_TYPE_UNKNOWN +}; + +enum sample_mode { + JPG_444, + JPG_422, + JPG_420, + JPG_400, + RESERVED1, + RESERVED2, + JPG_411, + JPG_SAMPLE_UNKNOWN +}; + +enum out_mode { + YCBCR_422, + YCBCR_420, + YCBCR_SAMPLE_UNKNOWN +}; + +enum in_mode { + JPG_MODESEL_YCBCR = 1, + JPG_MODESEL_RGB, + JPG_MODESEL_UNKNOWN +}; + +enum encode_type { + JPG_MAIN, + JPG_THUMBNAIL +}; + +enum image_quality_type { + JPG_QUALITY_LEVEL_1 = 0, /*high quality*/ + JPG_QUALITY_LEVEL_2, + JPG_QUALITY_LEVEL_3, + JPG_QUALITY_LEVEL_4 /*low quality*/ +}; + +struct jpg_dec_proc_param { + enum sample_mode sample_mode; + enum encode_type dec_type; + enum out_mode out_format; + unsigned int width; + unsigned int height; + unsigned int data_size; + unsigned int file_size; +}; + +struct jpg_enc_proc_param { + enum sample_mode sample_mode; + enum encode_type enc_type; + enum in_mode in_format; + enum image_quality_type quality; + unsigned int width; + unsigned int height; + unsigned int data_size; + unsigned int file_size; +}; + +struct jpg_args { + char *in_buf; + char *phy_in_buf; + int in_buf_size; + char *out_buf; + char *phy_out_buf; + int out_buf_size; + char *in_thumb_buf; + char *phy_in_thumb_buf; + int in_thumb_buf_size; + char *out_thumb_buf; + char *phy_out_thumb_buf; + int out_thumb_buf_size; + char *mapped_addr; + struct jpg_dec_proc_param *dec_param; + struct jpg_enc_proc_param *enc_param; + struct jpg_enc_proc_param *thumb_enc_param; +}; + +void reset_jpg(struct s5pc110_jpg_ctx *jpg_ctx); +enum jpg_return_status decode_jpg(struct s5pc110_jpg_ctx *jpg_ctx, \ + struct jpg_dec_proc_param *dec_param); +enum jpg_return_status encode_jpg(struct s5pc110_jpg_ctx *jpg_ctx, \ + struct jpg_enc_proc_param *enc_param); +enum jpg_return_status wait_for_interrupt(void); +enum sample_mode get_sample_type(struct s5pc110_jpg_ctx *jpg_ctx); +void get_xy(struct s5pc110_jpg_ctx *jpg_ctx, unsigned int *x, unsigned int *y); +unsigned int get_yuv_size(enum out_mode out_format, \ + unsigned int width, unsigned int height); + +#endif diff --git a/drivers/media/video/samsung/jpeg_v2/regs-jpeg.h b/drivers/media/video/samsung/jpeg_v2/regs-jpeg.h new file mode 100644 index 0000000..55bd2eb --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/regs-jpeg.h @@ -0,0 +1,143 @@ +/* linux/drivers/media/video/samsung/jpeg/regs-jpeg.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Register definition file for Samsung JPEG Encoder/Decoder + * + * 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_ARM_REGS_S3C_JPEG_H +#define __ASM_ARM_REGS_S3C_JPEG_H + +/* JPEG Registers part */ +#define S3C_JPEG_REG(x) ((x)) + +/* Sub-sampling Mode Register */ +#define S3C_JPEG_MOD_REG S3C_JPEG_REG(0x00) +/* Operation Status Register */ +#define S3C_JPEG_OPR_REG S3C_JPEG_REG(0x04) +/* Quantization Table Number Register and Huffman Table Number Register */ +#define S3C_JPEG_QTBL_REG S3C_JPEG_REG(0x08) +/* Huffman Table Number Register */ +#define S3C_JPEG_HTBL_REG S3C_JPEG_REG(0x0c) +#define S3C_JPEG_DRI_U_REG S3C_JPEG_REG(0x10) /* MCU, which inserts RST marker(upper 8bit) */ +#define S3C_JPEG_DRI_L_REG S3C_JPEG_REG(0x14) /* MCU, which inserts RST marker(lower 8bit) */ +#define S3C_JPEG_Y_U_REG S3C_JPEG_REG(0x18) /* Vertical Resolution (upper 8bit) */ +#define S3C_JPEG_Y_L_REG S3C_JPEG_REG(0x1c) /* Vertical Resolution (lower 8bit) */ +#define S3C_JPEG_X_U_REG S3C_JPEG_REG(0x20) /* Horizontal Resolution (upper 8bit) */ +#define S3C_JPEG_X_L_REG S3C_JPEG_REG(0x24) /* Horizontal Resolution (lower 8bit) */ +#define S3C_JPEG_CNT_U_REG S3C_JPEG_REG(0x28) /* The amount of the compressed data in bytes (upper 8bit) */ +#define S3C_JPEG_CNT_M_REG S3C_JPEG_REG(0x2c) /* The amount of the compressed data in bytes (middle 8bit) */ +#define S3C_JPEG_CNT_L_REG S3C_JPEG_REG(0x30) /* The amount of the compressed data in bytes (lowerz 8bit) */ +#define S3C_JPEG_INTSE_REG S3C_JPEG_REG(0x34) /* Interrupt setting register */ +#define S3C_JPEG_INTST_REG S3C_JPEG_REG(0x38) /* Interrupt status */ + +#define S3C_JPEG_COM_REG S3C_JPEG_REG(0x4c) /* Command register */ + +#define S3C_JPEG_IMGADR_REG S3C_JPEG_REG(0x50) /* Source or destination image addresss */ + +#define S3C_JPEG_JPGADR_REG S3C_JPEG_REG(0x58) /* Source or destination JPEG file address */ +#define S3C_JPEG_COEF1_REG S3C_JPEG_REG(0x5c) /* Coefficient values for RGB <-> YCbCr converter */ +#define S3C_JPEG_COEF2_REG S3C_JPEG_REG(0x60) /* Coefficient values for RGB <-> YCbCr converter */ +#define S3C_JPEG_COEF3_REG S3C_JPEG_REG(0x64) /* Coefficient values for RGB <-> YCbCr converter */ + +#define S3C_JPEG_CMOD_REG S3C_JPEG_REG(0x68) /* Mode selection and core clock setting */ +#define S3C_JPEG_CLKCON_REG S3C_JPEG_REG(0x6c) /* Power on/off and clock down control */ + +#define S3C_JPEG_JSTART_REG S3C_JPEG_REG(0x70) /* Start compression or decompression */ +#define S3C_JPEG_JRSTART_REG S3C_JPEG_REG(0x74) /* Restart decompression after header analysis */ +#define S3C_JPEG_SW_RESET_REG S3C_JPEG_REG(0x78) /* S/W reset */ + +#define S3C_JPEG_TIMER_SE_REG S3C_JPEG_REG(0x7c) /* Internal timer setting register */ +#define S3C_JPEG_TIMER_ST_REG S3C_JPEG_REG(0x80) /* Internal timer status register */ +#define S3C_JPEG_COMSTAT_REG S3C_JPEG_REG(0x84) /* Command status register */ +#define S3C_JPEG_OUTFORM_REG S3C_JPEG_REG(0x88) /* Output color format of decompression */ +#define S3C_JPEG_VERSION_REG S3C_JPEG_REG(0x8c) /* Version register */ + +#define S3C_JPEG_ENC_STREAM_INTSE_REG S3C_JPEG_REG(0x98) /* Compressed stream size interrupt setting register */ +#define S3C_JPEG_ENC_STREAM_INTST_REG S3C_JPEG_REG(0x9c) /* Compressed stream size interrupt status register */ + +#define S3C_JPEG_QTBL0_REG S3C_JPEG_REG(0x400) /* Quantization table 0 */ +#define S3C_JPEG_QTBL1_REG S3C_JPEG_REG(0x500) /* Quantization table 1 */ +#define S3C_JPEG_QTBL2_REG S3C_JPEG_REG(0x600) /* Quantization table 2 */ +#define S3C_JPEG_QTBL3_REG S3C_JPEG_REG(0x700) /* Quantization table 3 */ + +#define S3C_JPEG_HDCTBL0_REG S3C_JPEG_REG(0x800) /* DC huffman table 0 */ +#define S3C_JPEG_HDCTBLG0_REG S3C_JPEG_REG(0x840) /* DC huffman table group 0 */ +#define S3C_JPEG_HACTBL0_REG S3C_JPEG_REG(0x880) /* AC huffman table 0 */ +#define S3C_JPEG_HACTBLG0_REG S3C_JPEG_REG(0x8c0) /* AC huffman table group 0 */ +#define S3C_JPEG_HDCTBL1_REG S3C_JPEG_REG(0xc00) /* DC huffman table 1 */ +#define S3C_JPEG_HDCTBLG1_REG S3C_JPEG_REG(0xc40) /* DC huffman table group 1 */ +#define S3C_JPEG_HACTBL1_REG S3C_JPEG_REG(0xc80) /* AC huffman table 1 */ +#define S3C_JPEG_HACTBLG1_REG S3C_JPEG_REG(0xcc0) /* AC huffman table group 1 */ + +/* JPEG Mode Register bit */ +#define S3C_JPEG_MOD_REG_PROC_ENC (0<<3) +#define S3C_JPEG_MOD_REG_PROC_DEC (1<<3) + +#define S3C_JPEG_MOD_REG_SUBSAMPLE_444 (0<<0) +#define S3C_JPEG_MOD_REG_SUBSAMPLE_422 (1<<0) +#define S3C_JPEG_MOD_REG_SUBSAMPLE_420 (2<<0) +#define S3C_JPEG_MOD_REG_SUBSAMPLE_GRAY (3<<0) + +/* JPEG Operation Status Register bit */ +#define S3C_JPEG_OPR_REG_OPERATE (1<<0) +#define S3C_JPEG_OPR_REG_NO_OPERATE (0<<0) + +/* Quantization Table And Huffman Table Number Register bit */ +#define S3C_JPEG_QHTBL_REG_QT_NUM4 (1<<6) +#define S3C_JPEG_QHTBL_REG_QT_NUM3 (1<<4) +#define S3C_JPEG_QHTBL_REG_QT_NUM2 (1<<2) +#define S3C_JPEG_QHTBL_REG_QT_NUM1 (1<<0) + +#define S3C_JPEG_QHTBL_REG_HT_NUM4_AC (1<<7) +#define S3C_JPEG_QHTBL_REG_HT_NUM4_DC (1<<6) +#define S3C_JPEG_QHTBL_REG_HT_NUM3_AC (1<<5) +#define S3C_JPEG_QHTBL_REG_HT_NUM3_DC (1<<4) +#define S3C_JPEG_QHTBL_REG_HT_NUM2_AC (1<<3) +#define S3C_JPEG_QHTBL_REG_HT_NUM2_DC (1<<2) +#define S3C_JPEG_QHTBL_REG_HT_NUM1_AC (1<<1) +#define S3C_JPEG_QHTBL_REG_HT_NUM1_DC (1<<0) + + +/* JPEG Color Mode Register bit */ +#define S3C_JPEG_CMOD_REG_MOD_SEL_RGB (2<<5) +#define S3C_JPEG_CMOD_REG_MOD_SEL_YCBCR422 (1<<5) +#define S3C_JPEG_CMOD_REG_MOD_MODE_Y16 (1<<1) +#define S3C_JPEG_CMOD_REG_MOD_MODE_0 (0<<1) + +/* JPEG Clock Control Register bit */ +#define S3C_JPEG_CLKCON_REG_CLK_DOWN_READY_ENABLE (0<<1) +#define S3C_JPEG_CLKCON_REG_CLK_DOWN_READY_DISABLE (1<<1) +#define S3C_JPEG_CLKCON_REG_POWER_ON_ACTIVATE (1<<0) +#define S3C_JPEG_CLKCON_REG_POWER_ON_DISABLE (0<<0) + +/* JPEG Start Register bit */ +#define S3C_JPEG_JSTART_REG_ENABLE (1<<0) + +/* JPEG Rdstart Register bit */ +#define S3C_JPEG_JRSTART_REG_ENABLE (1<<0) + +/* JPEG SW Reset Register bit */ +#define S3C_JPEG_SW_RESET_REG_ENABLE (1<<0) + +/* JPEG Interrupt Setting Register bit */ +#define S3C_JPEG_INTSE_REG_RSTM_INT_EN (1<<7) +#define S3C_JPEG_INTSE_REG_DATA_NUM_INT_EN (1<<6) +#define S3C_JPEG_INTSE_REG_FINAL_MCU_NUM_INT_EN (1<<5) + +/* JPEG Decompression Output Format Register bit */ +#define S3C_JPEG_OUTFORM_REG_YCBCY422 (0<<0) +#define S3C_JPEG_OUTFORM_REG_YCBCY420 (1<<0) + +/* JPEG Decompression Input Stream Size Register bit */ +#define S3C_JPEG_DEC_STREAM_SIZE_REG_PROHIBIT (0x1FFFFFFF<<0) + +/* JPEG Command Register bit */ +#define S3C_JPEG_COM_INT_RELEASE (1<<2) + +#endif /*__ASM_ARM_REGS_S3C_JPEG_H */ diff --git a/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.c b/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.c new file mode 100644 index 0000000..81408b4 --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.c @@ -0,0 +1,613 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Core file for Samsung Jpeg Interface 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/version.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/signal.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/kmod.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/io.h> +#include <asm/page.h> +#include <mach/irqs.h> +#include <linux/semaphore.h> +#include <mach/map.h> +#include <linux/miscdevice.h> +#include <linux/vmalloc.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +#include <linux/version.h> +#include <plat/media.h> +#include <plat/jpeg.h> +#include <mach/media.h> + +#include <linux/time.h> +#include <linux/clk.h> + +#include <plat/clock.h> + +#include "s3c-jpeg.h" +#include "jpg_mem.h" +#include "jpg_misc.h" +#include "jpg_opr.h" +#include "regs-jpeg.h" + +static struct jpegv2_limits s3c_jpeg_limits; +static struct jpegv2_buf s3c_jpeg_bufinfo; + +static struct clk *s3c_jpeg_clk; +static struct regulator *jpeg_pd_regulator; + +static struct resource *s3c_jpeg_mem; +void __iomem *s3c_jpeg_base; +static int irq_no; +static int instanceNo;; +int jpg_irq_reason; +wait_queue_head_t wait_queue_jpeg; + + +DECLARE_WAIT_QUEUE_HEAD(WaitQueue_JPEG); + +static void jpeg_clock_enable(void) +{ + /* power domain enable */ + regulator_enable(jpeg_pd_regulator); + + /* clock enable */ + clk_enable(s3c_jpeg_clk); +} + +static void jpeg_clock_disable(void) +{ + /* clock disable */ + clk_disable(s3c_jpeg_clk); + + /* power domain disable */ + regulator_disable(jpeg_pd_regulator); +} + +irqreturn_t s3c_jpeg_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int int_status; + unsigned int status; + + jpg_dbg("=====enter s3c_jpeg_irq===== \r\n"); + + int_status = readl(s3c_jpeg_base + S3C_JPEG_INTST_REG); + + do { + status = readl(s3c_jpeg_base + S3C_JPEG_OPR_REG); + } while (status); + + writel(S3C_JPEG_COM_INT_RELEASE, s3c_jpeg_base + S3C_JPEG_COM_REG); + jpg_dbg("int_status : 0x%08x status : 0x%08x\n", int_status, status); + + if (int_status) { + switch (int_status) { + case 0x40: + jpg_irq_reason = OK_ENC_OR_DEC; + break; + case 0x20: + jpg_irq_reason = ERR_ENC_OR_DEC; + break; + default: + jpg_irq_reason = ERR_UNKNOWN; + } + + wake_up_interruptible(&wait_queue_jpeg); + } else { + jpg_irq_reason = ERR_UNKNOWN; + wake_up_interruptible(&wait_queue_jpeg); + } + + return IRQ_HANDLED; +} +static int s3c_jpeg_open(struct inode *inode, struct file *file) +{ + struct s5pc110_jpg_ctx *jpg_reg_ctx; + unsigned long ret; + + jpg_dbg("JPG_open \r\n"); + + jpg_reg_ctx = (struct s5pc110_jpg_ctx *) + mem_alloc(sizeof(struct s5pc110_jpg_ctx)); + memset(jpg_reg_ctx, 0x00, sizeof(struct s5pc110_jpg_ctx)); + + ret = lock_jpg_mutex(); + + if (!ret) { + jpg_err("JPG Mutex Lock Fail\r\n"); + unlock_jpg_mutex(); + kfree(jpg_reg_ctx); + return FALSE; + } + + if (instanceNo > MAX_INSTANCE_NUM) { + jpg_err("Instance Number error-JPEG is running, \ + instance number is %d\n", instanceNo); + unlock_jpg_mutex(); + kfree(jpg_reg_ctx); + return FALSE; + } + + instanceNo++; + + /* Initialize the limits of the driver */ + jpg_reg_ctx->limits = &s3c_jpeg_limits; + jpg_reg_ctx->bufinfo = &s3c_jpeg_bufinfo; + + unlock_jpg_mutex(); + + file->private_data = (struct s5pc110_jpg_ctx *)jpg_reg_ctx; + + return 0; +} + + +static int s3c_jpeg_release(struct inode *inode, struct file *file) +{ + unsigned long ret; + struct s5pc110_jpg_ctx *jpg_reg_ctx; + + jpg_dbg("JPG_Close\n"); + + jpg_reg_ctx = (struct s5pc110_jpg_ctx *)file->private_data; + + if (!jpg_reg_ctx) { + jpg_err("JPG Invalid Input Handle\r\n"); + return FALSE; + } + + ret = lock_jpg_mutex(); + + if (!ret) { + jpg_err("JPG Mutex Lock Fail\r\n"); + return FALSE; + } + + if ((--instanceNo) < 0) + instanceNo = 0; + + unlock_jpg_mutex(); + kfree(jpg_reg_ctx); + + return 0; +} + + +static ssize_t s3c_jpeg_write(struct file *file, const char *buf, + size_t count, loff_t *pos) +{ + return 0; +} + +static ssize_t s3c_jpeg_read(struct file *file, char *buf, + size_t count, loff_t *pos) +{ + return 0; +} + +static long s3c_jpeg_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct s5pc110_jpg_ctx *jpg_reg_ctx; + struct jpg_args param; + enum BOOL result = TRUE; + unsigned long ret; + int out; + + jpg_reg_ctx = (struct s5pc110_jpg_ctx *)file->private_data; + + if (!jpg_reg_ctx) { + jpg_err("JPG Invalid Input Handle\r\n"); + return FALSE; + } + + ret = lock_jpg_mutex(); + + if (!ret) { + jpg_err("JPG Mutex Lock Fail\r\n"); + return FALSE; + } + + switch (cmd) { + case IOCTL_JPG_DECODE: + + jpg_dbg("IOCTL_JPEG_DECODE\n"); + + out = copy_from_user(¶m, (struct jpg_args *)arg, + sizeof(struct jpg_args)); + + jpg_reg_ctx->jpg_data_addr = (unsigned int)jpg_data_base_addr; + jpg_reg_ctx->img_data_addr = + (unsigned int)jpg_data_base_addr + + jpg_reg_ctx->bufinfo->main_frame_start; + + jpeg_clock_enable(); + result = decode_jpg(jpg_reg_ctx, param.dec_param); + jpeg_clock_disable(); + + out = copy_to_user((void *)arg, + (void *)¶m, sizeof(struct jpg_args)); + break; + + case IOCTL_JPG_ENCODE: + + jpg_dbg("IOCTL_JPEG_ENCODE\n"); + + out = copy_from_user(¶m, (struct jpg_args *)arg, + sizeof(struct jpg_args)); + + jpg_dbg("encode size :: width : %d hegiht : %d\n", + param.enc_param->width, param.enc_param->height); + + jpeg_clock_enable(); + if (param.enc_param->enc_type == JPG_MAIN) { + jpg_reg_ctx->jpg_data_addr = + (unsigned int)jpg_data_base_addr; + jpg_reg_ctx->img_data_addr = + (unsigned int)jpg_data_base_addr + + jpg_reg_ctx->bufinfo->main_frame_start; + jpg_dbg("enc_img_data_addr=0x%08x," + "enc_jpg_data_addr=0x%08x\n", + jpg_reg_ctx->img_data_addr, + jpg_reg_ctx->jpg_data_addr); + + result = encode_jpg(jpg_reg_ctx, param.enc_param); + } else { + jpg_reg_ctx->jpg_thumb_data_addr = + (unsigned int)jpg_data_base_addr + + jpg_reg_ctx->bufinfo->thumb_stream_start; + jpg_reg_ctx->img_thumb_data_addr = + (unsigned int)jpg_data_base_addr + + jpg_reg_ctx->bufinfo->thumb_frame_start; + + result = encode_jpg(jpg_reg_ctx, param.thumb_enc_param); + } + jpeg_clock_disable(); + + out = copy_to_user((void *)arg, (void *)¶m, + sizeof(struct jpg_args)); + break; + + case IOCTL_JPG_GET_STRBUF: + jpg_dbg("IOCTL_JPG_GET_STRBUF\n"); + unlock_jpg_mutex(); + return arg + jpg_reg_ctx->bufinfo->main_stream_start; + + case IOCTL_JPG_GET_THUMB_STRBUF: + jpg_dbg("IOCTL_JPG_GET_THUMB_STRBUF\n"); + unlock_jpg_mutex(); + return arg + jpg_reg_ctx->bufinfo->thumb_stream_start; + + case IOCTL_JPG_GET_FRMBUF: + jpg_dbg("IOCTL_JPG_GET_FRMBUF\n"); + unlock_jpg_mutex(); + return arg + jpg_reg_ctx->bufinfo->main_frame_start; + + case IOCTL_JPG_GET_THUMB_FRMBUF: + jpg_dbg("IOCTL_JPG_GET_THUMB_FRMBUF\n"); + unlock_jpg_mutex(); + return arg + jpg_reg_ctx->bufinfo->thumb_frame_start; + + case IOCTL_JPG_GET_PHY_FRMBUF: + jpg_dbg("IOCTL_JPG_GET_PHY_FRMBUF\n"); + unlock_jpg_mutex(); + return jpg_data_base_addr + jpg_reg_ctx->bufinfo->main_frame_start; + + case IOCTL_JPG_GET_PHY_THUMB_FRMBUF: + jpg_dbg("IOCTL_JPG_GET_PHY_THUMB_FRMBUF\n"); + unlock_jpg_mutex(); + return jpg_data_base_addr + jpg_reg_ctx->bufinfo->thumb_frame_start; + + default: + jpg_dbg("JPG Invalid ioctl : 0x%X\n", cmd); + } + + unlock_jpg_mutex(); + + return result; +} + +static unsigned int s3c_jpeg_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + + jpg_dbg("enter poll\n"); + poll_wait(file, &wait_queue_jpeg, wait); + mask = POLLOUT | POLLWRNORM; + return mask; +} + +int s3c_jpeg_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long max_size; + unsigned long page_frame_no; + + page_frame_no = __phys_to_pfn(jpg_data_base_addr); + + max_size = jpg_reserved_mem_size; + + if (size > max_size) + return -EINVAL; + + vma->vm_flags |= VM_RESERVED | VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_pfn_range(vma, vma->vm_start, page_frame_no, size, + vma->vm_page_prot)) { + jpg_err("jpeg remap error"); + return -EAGAIN; + } + + return 0; +} + + +static const struct file_operations jpeg_fops = { + .owner = THIS_MODULE, + .open = s3c_jpeg_open, + .release = s3c_jpeg_release, + .unlocked_ioctl = s3c_jpeg_ioctl, + .read = s3c_jpeg_read, + .write = s3c_jpeg_write, + .mmap = s3c_jpeg_mmap, + .poll = s3c_jpeg_poll, +}; + + +static struct miscdevice s3c_jpeg_miscdev = { + .minor = 254, + .name = "s3c-jpg", + .fops = &jpeg_fops +}; + +void s3c_jpg_plat_init(struct s3c_platform_jpeg *pdata) +{ + unsigned int main_pixels; + unsigned int thumb_pixels; + + s3c_jpeg_limits.max_main_width = pdata->max_main_width; + s3c_jpeg_limits.max_main_height = pdata->max_main_height; + s3c_jpeg_limits.max_thumb_width = pdata->max_thumb_width; + s3c_jpeg_limits.max_thumb_height = pdata->max_thumb_height; + + main_pixels = s3c_jpeg_limits.max_main_width * + s3c_jpeg_limits.max_main_height; + thumb_pixels = s3c_jpeg_limits.max_thumb_width * + s3c_jpeg_limits.max_thumb_height; + + s3c_jpeg_bufinfo.main_stream_size = ALIGN(main_pixels, PAGE_SIZE); + /* Assuming JPEG V2 uses YCBCR422 output format */ + s3c_jpeg_bufinfo.main_frame_size = ALIGN(main_pixels * 2, PAGE_SIZE); + + s3c_jpeg_bufinfo.thumb_stream_size = ALIGN(thumb_pixels, PAGE_SIZE); + s3c_jpeg_bufinfo.thumb_frame_size = ALIGN(thumb_pixels * 2, PAGE_SIZE); + + s3c_jpeg_bufinfo.total_buf_size = s3c_jpeg_bufinfo.main_stream_size + + s3c_jpeg_bufinfo.thumb_stream_size + + s3c_jpeg_bufinfo.main_frame_size + + s3c_jpeg_bufinfo.thumb_frame_size; + + s3c_jpeg_bufinfo.main_stream_start = 0; + s3c_jpeg_bufinfo.thumb_stream_start = + s3c_jpeg_bufinfo.main_stream_start + + s3c_jpeg_bufinfo.main_stream_size; + s3c_jpeg_bufinfo.main_frame_start = + s3c_jpeg_bufinfo.thumb_stream_start + + s3c_jpeg_bufinfo.thumb_stream_size; + s3c_jpeg_bufinfo.thumb_frame_start = + s3c_jpeg_bufinfo.main_frame_start + + s3c_jpeg_bufinfo.main_frame_size; + + jpg_dbg("Resolution: Main (%4d x %4d), Thumb (%4d x %4d)\n", \ + s3c_jpeg_limits.max_main_width, \ + s3c_jpeg_limits.max_main_height, \ + s3c_jpeg_limits.max_thumb_width, \ + s3c_jpeg_limits.max_thumb_height); + + jpg_dbg("JPG Stream: Main(%d bytes @ 0x%x), Thumb(%d bytes @ 0x%x)\n",\ + s3c_jpeg_bufinfo.main_stream_size, \ + s3c_jpeg_bufinfo.main_stream_start, \ + s3c_jpeg_bufinfo.thumb_stream_size, \ + s3c_jpeg_bufinfo.thumb_stream_start); + + jpg_dbg("YUV frame: Main(%d bytes @ 0x%x), Thumb(%d bytes @ 0x%x)\n",\ + s3c_jpeg_bufinfo.main_frame_size, \ + s3c_jpeg_bufinfo.main_frame_start, \ + s3c_jpeg_bufinfo.thumb_frame_size, \ + s3c_jpeg_bufinfo.thumb_frame_start); + + jpg_dbg("Total buffer size : %d bytes\n", \ + s3c_jpeg_bufinfo.total_buf_size); + +} + +static int s3c_jpeg_probe(struct platform_device *pdev) +{ + struct resource *res; + static int size; + static int ret; + struct mutex *h_mutex; + struct s3c_platform_jpeg *pdata; + + pdata = to_jpeg_plat(&pdev->dev); + + if (!pdata) { + jpg_err("Err: Platform data is not setup\n"); + return -EINVAL; + } + + s3c_jpg_plat_init(pdata); + + if (s3c_jpeg_bufinfo.total_buf_size > jpg_reserved_mem_size) { + jpg_err("Err: Reserved memory (%d) is less than" + "required memory (%d)\n", \ + jpg_reserved_mem_size, \ + s3c_jpeg_bufinfo.total_buf_size); + return -ENOMEM; + } + + /* Get jpeg power domain regulator */ + jpeg_pd_regulator = regulator_get(&pdev->dev, "pd"); + if (IS_ERR(jpeg_pd_regulator)) { + jpg_err("%s: failed to get resource %s\n", + __func__, "s3c-jpg"); + return PTR_ERR(jpeg_pd_regulator); + } + + s3c_jpeg_clk = clk_get(&pdev->dev, "jpeg"); + + if (IS_ERR(s3c_jpeg_clk)) { + jpg_err("failed to find jpeg clock source\n"); + return -ENOENT; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (res == NULL) { + jpg_err("failed to get memory region resouce\n"); + return -ENOENT; + } + + size = (res->end - res->start) + 1; + s3c_jpeg_mem = request_mem_region(res->start, size, pdev->name); + + if (s3c_jpeg_mem == NULL) { + jpg_err("failed to get memory region\n"); + return -ENOENT; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (res == NULL) { + jpg_err("failed to get irq resource\n"); + return -ENOENT; + } + + irq_no = res->start; + ret = request_irq(res->start, (void *)s3c_jpeg_irq, 0, + pdev->name, pdev); + + if (ret != 0) { + jpg_err("failed to install irq (%d)\n", ret); + return ret; + } + + s3c_jpeg_base = ioremap(s3c_jpeg_mem->start, size); + + if (s3c_jpeg_base == 0) { + jpg_err("failed to ioremap() region\n"); + return -EINVAL; + } + + init_waitqueue_head(&wait_queue_jpeg); + + jpg_dbg("JPG_Init\n"); + + /* Mutex initialization */ + h_mutex = create_jpg_mutex(); + + if (h_mutex == NULL) { + jpg_err("JPG Mutex Initialize error\r\n"); + return FALSE; + } + + ret = lock_jpg_mutex(); + + if (!ret) { + jpg_err("JPG Mutex Lock Fail\n"); + return FALSE; + } + + instanceNo = 0; + + unlock_jpg_mutex(); + + ret = misc_register(&s3c_jpeg_miscdev); + + return 0; +} + +static int s3c_jpeg_remove(struct platform_device *dev) +{ + if (s3c_jpeg_mem != NULL) { + release_resource(s3c_jpeg_mem); + kfree(s3c_jpeg_mem); + s3c_jpeg_mem = NULL; + } + + free_irq(irq_no, dev); + misc_deregister(&s3c_jpeg_miscdev); + return 0; +} + +static struct platform_driver s3c_jpeg_driver = { + .probe = s3c_jpeg_probe, + .remove = s3c_jpeg_remove, + .shutdown = NULL, + .driver = { + .owner = THIS_MODULE, + .name = "s3c-jpg", + }, +}; + +static char banner[] __initdata = + KERN_INFO "S3C JPEG Driver, (c) 2007 Samsung Electronics\n"; + +static int __init s3c_jpeg_init(void) +{ + printk(banner); + printk(KERN_INFO "JPEG driver for S5PV210\n"); + return platform_driver_register(&s3c_jpeg_driver); +} + +static void __exit s3c_jpeg_exit(void) +{ + unsigned long ret; + + jpg_dbg("JPG_Deinit\n"); + + ret = lock_jpg_mutex(); + + if (!ret) + jpg_err("JPG Mutex Lock Fail\r\n"); + + unlock_jpg_mutex(); + + delete_jpg_mutex(); + + platform_driver_unregister(&s3c_jpeg_driver); + jpg_dbg("S3C JPEG driver module exit\n"); +} + +module_init(s3c_jpeg_init); +module_exit(s3c_jpeg_exit); + +MODULE_AUTHOR("Peter, Oh"); +MODULE_DESCRIPTION("S3C JPEG Encoder/Decoder Device Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.h b/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.h new file mode 100644 index 0000000..dd5bc4c --- /dev/null +++ b/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.h @@ -0,0 +1,36 @@ +/* linux/drivers/media/video/samsung/jpeg_v2/s3c-jpeg.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Header file for Samsung Jpeg Interface 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. + */ + + +#ifndef __JPEG_DRIVER_H__ +#define __JPEG_DRIVER_H__ + + +#define MAX_INSTANCE_NUM 1 +#define MAX_PROCESSING_THRESHOLD 1000 /* 1Sec */ + +#define JPEG_IOCTL_MAGIC 'J' + +#define IOCTL_JPG_DECODE _IO(JPEG_IOCTL_MAGIC, 1) +#define IOCTL_JPG_ENCODE _IO(JPEG_IOCTL_MAGIC, 2) +#define IOCTL_JPG_GET_STRBUF _IO(JPEG_IOCTL_MAGIC, 3) +#define IOCTL_JPG_GET_FRMBUF _IO(JPEG_IOCTL_MAGIC, 4) +#define IOCTL_JPG_GET_THUMB_STRBUF _IO(JPEG_IOCTL_MAGIC, 5) +#define IOCTL_JPG_GET_THUMB_FRMBUF _IO(JPEG_IOCTL_MAGIC, 6) +#define IOCTL_JPG_GET_PHY_FRMBUF _IO(JPEG_IOCTL_MAGIC, 7) +#define IOCTL_JPG_GET_PHY_THUMB_FRMBUF _IO(JPEG_IOCTL_MAGIC, 8) +#define JPG_CLOCK_DIVIDER_RATIO_QUARTER 4 + +/* Driver Helper function */ +#define to_jpeg_plat(d) (to_platform_device(d)->dev.platform_data) + +#endif /*__JPEG_DRIVER_H__*/ diff --git a/drivers/media/video/samsung/mfc50/Kconfig b/drivers/media/video/samsung/mfc50/Kconfig new file mode 100644 index 0000000..11d17c2 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/Kconfig @@ -0,0 +1,23 @@ +# +# Configuration for Multi Format Codecs (MFC) +# +# +config VIDEO_MFC50 + bool "Samsung MFC (Multi Format Codec - FIMV 5.0) Driver" + depends on VIDEO_SAMSUNG && CPU_S5PV210 + default n + select S5P_SETUP_MFC + select S5P_DEV_MFC + ---help--- + This is a Samsung Multi Format Codecs (MFC) FIMV V5.0 - driver for Samsung S5PC110 + +config VIDEO_MFC_MAX_INSTANCE + int "Maximum size of MFC instance (1-4)" + range 1 4 + depends on VIDEO_MFC50 + default 4 + +config VIDEO_MFC50_DEBUG + bool "print MFC debug message" + depends on VIDEO_MFC50 + default n diff --git a/drivers/media/video/samsung/mfc50/Makefile b/drivers/media/video/samsung/mfc50/Makefile new file mode 100644 index 0000000..31f0499 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_VIDEO_MFC50) += mfc.o mfc_buffer_manager.o mfc_intr.o mfc_memory.o mfc_opr.o mfc_shared_mem.o + +ifeq ($(CONFIG_VIDEO_MFC50_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif + +#EXTRA_CFLAGS += -DMFC_REQUEST_TIME diff --git a/drivers/media/video/samsung/mfc50/mfc.c b/drivers/media/video/samsung/mfc50/mfc.c new file mode 100755 index 0000000..0e596c7 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc.c @@ -0,0 +1,835 @@ +/* + * drivers/media/video/samsung/mfc50/mfc.c + * + * C file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * 2009.09.21 - Implement clock & power gating. + * including suspend & resume fuction. (Key Young, Park) + * 2009.10.08 - Apply 9/30 firmware (Key Young, Park) + * 2009.10.09 - Add error handling rountine (Key Young, Park) + * 2009.10.13 - move mfc interrupt routine into mfc_irq.c (Key Young, Park) + * 2009.10.27 - Update firmware (2009.10.15) (Key Young, Park) + * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park) + * 2009.11.04 - remove mfc_common.[ch] + * seperate buffer alloc & set (Key Young, Park) + * 2009.11.24 - add state check when decoding & encoding (Key Young, Park) + * + * 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/mm.h> +#include <linux/miscdevice.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/wait.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/dma-mapping.h> + +#include <linux/sched.h> +#include <linux/firmware.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#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" +#include "mfc_opr.h" +#include "mfc_memory.h" +#include "mfc_buffer_manager.h" +#include "mfc_intr.h" + +#define MFC_FW_NAME "samsung_mfc_fw.bin" + +static struct resource *mfc_mem; +static struct mutex mfc_mutex; +static struct clk *mfc_sclk; +static struct regulator *mfc_pd_regulator; +const struct firmware *mfc_fw_info; + +static int mfc_open(struct inode *inode, struct file *file) +{ + struct mfc_inst_ctx *mfc_ctx; + int ret; + + mutex_lock(&mfc_mutex); + + if (!mfc_is_running()) { + /* Turn on mfc power domain regulator */ + ret = regulator_enable(mfc_pd_regulator); + if (ret < 0) { + mfc_err("MFC_RET_POWER_ENABLE_FAIL\n"); + ret = -EINVAL; + 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); + + if (mfc_init_hw() != true) { + clk_disable(mfc_sclk); + ret = -ENODEV; + goto err_regulator; + } + clk_disable(mfc_sclk); + } + + mfc_ctx = (struct mfc_inst_ctx *)kmalloc(sizeof(struct mfc_inst_ctx), GFP_KERNEL); + if (mfc_ctx == NULL) { + mfc_err("MFCINST_MEMORY_ALLOC_FAIL\n"); + ret = -ENOMEM; + goto err_regulator; + } + + memset(mfc_ctx, 0, sizeof(struct mfc_inst_ctx)); + + /* get the inst no allocating some part of memory among reserved memory */ + mfc_ctx->mem_inst_no = mfc_get_mem_inst_no(); + mfc_ctx->InstNo = -1; + if (mfc_ctx->mem_inst_no < 0) { + mfc_err("MFCINST_INST_NUM_EXCEEDED\n"); + ret = -EPERM; + goto err_mem_inst; + } + + if (mfc_set_state(mfc_ctx, MFCINST_STATE_OPENED) < 0) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + ret = -ENODEV; + goto err_set_state; + } + + /* Decoder only */ + mfc_ctx->extraDPB = MFC_MAX_EXTRA_DPB; + mfc_ctx->FrameType = MFC_RET_FRAME_NOT_SET; + + file->private_data = mfc_ctx; + + mutex_unlock(&mfc_mutex); + + return 0; + +err_set_state: + mfc_return_mem_inst_no(mfc_ctx->mem_inst_no); +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) + mfc_err("MFC_RET_POWER_DISABLE_FAIL\n"); + } +err_open: + mutex_unlock(&mfc_mutex); + + return ret; +} + +static int mfc_release(struct inode *inode, struct file *file) +{ + struct mfc_inst_ctx *mfc_ctx; + int ret; + + mutex_lock(&mfc_mutex); + + mfc_ctx = (struct mfc_inst_ctx *)file->private_data; + if (mfc_ctx == NULL) { + mfc_err("MFCINST_ERR_INVALID_PARAM\n"); + ret = -EIO; + goto out_release; + } + + mfc_release_all_buffer(mfc_ctx->mem_inst_no); + mfc_merge_fragment(mfc_ctx->mem_inst_no); + + mfc_return_mem_inst_no(mfc_ctx->mem_inst_no); + + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) { + clk_enable(mfc_sclk); + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + clk_disable(mfc_sclk); + } + + kfree(mfc_ctx); + + 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) { + mfc_err("MFC_RET_POWER_DISABLE_FAIL\n"); + goto out_release; + } + } + +out_release: + + mutex_unlock(&mfc_mutex); + return ret; +} + +static long mfc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret, ex_ret; + struct mfc_inst_ctx *mfc_ctx = NULL; + struct mfc_common_args in_param; + + mutex_lock(&mfc_mutex); + clk_enable(mfc_sclk); + + ret = copy_from_user(&in_param, (struct mfc_common_args *)arg, sizeof(struct mfc_common_args)); + if (ret < 0) { + mfc_err("Inparm copy error\n"); + ret = -EIO; + in_param.ret_code = MFCINST_ERR_INVALID_PARAM; + goto out_ioctl; + } + + mfc_ctx = (struct mfc_inst_ctx *)file->private_data; + mutex_unlock(&mfc_mutex); + + switch (cmd) { + case IOCTL_MFC_ENC_INIT: + mutex_lock(&mfc_mutex); + + if (mfc_set_state(mfc_ctx, MFCINST_STATE_ENC_INITIALIZE) < 0) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + /* MFC encode init */ + in_param.ret_code = mfc_init_encode(mfc_ctx, &(in_param.args)); + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_ENC_EXE: + mutex_lock(&mfc_mutex); + if (mfc_ctx->MfcState < MFCINST_STATE_ENC_INITIALIZE) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + if (mfc_set_state(mfc_ctx, MFCINST_STATE_ENC_EXE) < 0) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + in_param.ret_code = mfc_exe_encode(mfc_ctx, &(in_param.args)); + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_DEC_INIT: + mutex_lock(&mfc_mutex); + if (mfc_set_state(mfc_ctx, MFCINST_STATE_DEC_INITIALIZE) < 0) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + /* MFC decode init */ + in_param.ret_code = mfc_init_decode(mfc_ctx, &(in_param.args)); + if (in_param.ret_code < 0) { + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + } + + if (in_param.args.dec_init.out_dpb_cnt <= 0) { + mfc_err("MFC out_dpb_cnt error\n"); + mutex_unlock(&mfc_mutex); + break; + } + + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_DEC_EXE: + mutex_lock(&mfc_mutex); + if (mfc_ctx->MfcState < MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + if (mfc_set_state(mfc_ctx, MFCINST_STATE_DEC_EXE) < 0) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + in_param.ret_code = mfc_exe_decode(mfc_ctx, &(in_param.args)); + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_GET_CONFIG: + mutex_lock(&mfc_mutex); + if (mfc_ctx->MfcState < MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + in_param.ret_code = mfc_get_config(mfc_ctx, &(in_param.args)); + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_SET_CONFIG: + mutex_lock(&mfc_mutex); + in_param.ret_code = mfc_set_config(mfc_ctx, &(in_param.args)); + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_GET_IN_BUF: + mutex_lock(&mfc_mutex); + if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + if (in_param.args.mem_alloc.buff_size <= 0) { + mfc_err("MFCINST_ERR_INVALID_PARAM\n"); + in_param.ret_code = MFCINST_ERR_INVALID_PARAM; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + if ((is_dec_codec(in_param.args.mem_alloc.codec_type)) && + (in_param.args.mem_alloc.buff_size < (CPB_BUF_SIZE + DESC_BUF_SIZE))) { + in_param.args.mem_alloc.buff_size = CPB_BUF_SIZE + DESC_BUF_SIZE; + } + + /* Buffer manager should have 64KB alignment for MFC base addresses */ + in_param.args.mem_alloc.buff_size = ALIGN_TO_8KB(in_param.args.mem_alloc.buff_size); + + /* allocate stream buf for decoder & current YC buf for encoder */ + if (is_dec_codec(in_param.args.mem_alloc.codec_type)) + in_param.ret_code = mfc_allocate_buffer(mfc_ctx, &in_param.args, 0); + else + in_param.ret_code = mfc_allocate_buffer(mfc_ctx, &in_param.args, 1); + + mfc_ctx->desc_buff_paddr = in_param.args.mem_alloc.out_paddr + CPB_BUF_SIZE; + + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_FREE_BUF: + mutex_lock(&mfc_mutex); + if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + in_param.ret_code = mfc_release_buffer((unsigned char *)in_param.args.mem_free.u_addr); + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_GET_PHYS_ADDR: + mutex_lock(&mfc_mutex); + mfc_debug("IOCTL_MFC_GET_PHYS_ADDR\n"); + + if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) { + mfc_err("MFCINST_ERR_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + mutex_unlock(&mfc_mutex); + break; + } + + in_param.ret_code = mfc_get_phys_addr(mfc_ctx, &(in_param.args)); + ret = in_param.ret_code; + mutex_unlock(&mfc_mutex); + break; + + case IOCTL_MFC_GET_MMAP_SIZE: + + if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) { + mfc_err("MFC_RET_STATE_INVALID\n"); + in_param.ret_code = MFCINST_ERR_STATE_INVALID; + ret = -EINVAL; + + break; + } + + in_param.ret_code = MFCINST_RET_OK; + ret = mfc_ctx->port0_mmap_size; + + break; + + case IOCTL_MFC_BUF_CACHE: + mutex_lock(&mfc_mutex); + + in_param.ret_code = MFCINST_RET_OK; + mfc_ctx->buf_type = in_param.args.buf_type; + + mutex_unlock(&mfc_mutex); + break; + + default: + mfc_err("Requested ioctl command is not defined. (ioctl cmd=0x%08x)\n", cmd); + in_param.ret_code = MFCINST_ERR_INVALID_PARAM; + ret = -EINVAL; + } + +out_ioctl: + clk_disable(mfc_sclk); + + ex_ret = copy_to_user((struct mfc_common_args *)arg, &in_param, sizeof(struct mfc_common_args)); + if (ex_ret < 0) { + mfc_err("Outparm copy to user error\n"); + ret = -EIO; + } + + mfc_debug_L0("---------------IOCTL return = %d ---------------\n", ret); + + return ret; +} + +static int mfc_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long vir_size = vma->vm_end - vma->vm_start; + unsigned long phy_size, firmware_size; + unsigned long page_frame_no = 0; + struct mfc_inst_ctx *mfc_ctx; + + mfc_debug("vma->vm_start = 0x%08x, vma->vm_end = 0x%08x\n", + (unsigned int)vma->vm_start, + (unsigned int)vma->vm_end); + mfc_debug("vma->vm_end - vma->vm_start = %ld\n", vir_size); + + mfc_ctx = (struct mfc_inst_ctx *)filp->private_data; + + firmware_size = mfc_get_port0_buff_paddr() - mfc_get_fw_buff_paddr(); + phy_size = (unsigned long)(mfc_port0_memsize - firmware_size + mfc_port1_memsize); + + /* if memory size required from appl. mmap() is bigger than max data memory + * size allocated in the driver */ + if (vir_size > phy_size) { + mfc_err("virtual requested mem(%ld) is bigger than physical mem(%ld)\n", + vir_size, phy_size); + return -EINVAL; + } + + mfc_ctx->port0_mmap_size = mfc_port0_memsize - firmware_size; + + vma->vm_flags |= VM_RESERVED | VM_IO; + if (mfc_ctx->buf_type != MFC_BUFFER_CACHE) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + /* + * port0 mapping for stream buf & frame buf (chroma + MV) + */ + page_frame_no = __phys_to_pfn(mfc_get_port0_buff_paddr()); + if (remap_pfn_range(vma, vma->vm_start, page_frame_no, + mfc_ctx->port0_mmap_size, vma->vm_page_prot)) { + mfc_err("mfc remap port0 error\n"); + return -EAGAIN; + } + + vma->vm_flags |= VM_RESERVED | VM_IO; + if (mfc_ctx->buf_type != MFC_BUFFER_CACHE) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + /* + * port1 mapping for frame buf (luma) + */ + page_frame_no = __phys_to_pfn(mfc_get_port1_buff_paddr()); + if (remap_pfn_range(vma, vma->vm_start + mfc_ctx->port0_mmap_size, + page_frame_no, vir_size - mfc_ctx->port0_mmap_size, vma->vm_page_prot)) { + mfc_err("mfc remap port1 error\n"); + return -EAGAIN; + } + + mfc_debug("virtual requested mem = %ld, physical reserved data mem = %ld\n", vir_size, phy_size); + + return 0; +} + +static const struct file_operations mfc_fops = { + .owner = THIS_MODULE, + .open = mfc_open, + .release = mfc_release, + .unlocked_ioctl = mfc_ioctl, + .mmap = mfc_mmap +}; + + +static struct miscdevice mfc_miscdev = { + .minor = 252, + .name = "s3c-mfc", + .fops = &mfc_fops, +}; + +static void mfc_firmware_request_complete_handler(const struct firmware *fw, + void *context) +{ + if (fw != NULL) { + mfc_load_firmware(fw->data, fw->size); + mfc_fw_info = fw; + } else { + mfc_err("failed to load MFC F/W, MFC will not working\n"); + } +} + +static int mfc_probe(struct platform_device *pdev) +{ + struct s3c_platform_mfc *pdata; + struct resource *res; + size_t size; + int ret; + unsigned int mfc_port1_alloc_paddr; + + if (!pdev || !pdev->dev.platform_data) { + dev_err(&pdev->dev, "Unable to probe mfc!\n"); + return -1; + } + + pdata = pdev->dev.platform_data; + + /* mfc clock enable should be here */ + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get memory region resource\n"); + ret = -ENOENT; + goto probe_out; + } + + /* 60K is required for mfc register (0x0 ~ 0xe008) */ + size = (res->end - res->start) + 1; + mfc_mem = request_mem_region(res->start, size, pdev->name); + if (mfc_mem == NULL) { + dev_err(&pdev->dev, "failed to get memory region\n"); + ret = -ENOENT; + goto err_mem_req; + } + + mfc_sfr_base_vaddr = ioremap(mfc_mem->start, mfc_mem->end - mfc_mem->start + 1); + if (mfc_sfr_base_vaddr == NULL) { + dev_err(&pdev->dev, "failed to ioremap address region\n"); + ret = -ENOENT; + goto err_mem_map; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get irq resource\n"); + ret = -ENOENT; + goto err_irq_res; + } + +#if !defined(MFC_POLLING) + ret = request_irq(res->start, mfc_irq, IRQF_DISABLED, pdev->name, pdev); + if (ret != 0) { + dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); + goto err_irq_req; + } +#endif + + mutex_init(&mfc_mutex); + + /* + * buffer memory secure + */ + mfc_port0_base_paddr =(unsigned int)pdata->buf_phy_base[0]; + mfc_port0_memsize = (unsigned int)pdata->buf_phy_size[0]; + + mfc_debug(" mfc_port0_base_paddr= 0x%x \n", mfc_port0_base_paddr); + mfc_debug(" mfc_port0_memsize = 0x%x \n", mfc_port0_memsize); + + mfc_port0_base_paddr = ALIGN_TO_128KB(mfc_port0_base_paddr); + mfc_port0_base_vaddr = phys_to_virt(mfc_port0_base_paddr); + + if (mfc_port0_base_vaddr == NULL) { + mfc_err("fail to mapping port0 buffer\n"); + ret = -EPERM; + goto err_vaddr_map; + } + + mfc_port1_alloc_paddr = (unsigned int)pdata->buf_phy_base[1]; + mfc_port1_memsize = (unsigned int)pdata->buf_phy_size[1]; + + mfc_port1_base_paddr = (unsigned int)s5p_get_media_membase_bank(1); + mfc_port1_base_paddr = ALIGN_TO_128KB(mfc_port1_base_paddr); + + mfc_debug(" mfc_port1_base_paddr= 0x%x \n", mfc_port1_base_paddr); + mfc_debug(" mfc_port1_memsize = 0x%x \n", mfc_port1_memsize); + + mfc_port1_alloc_paddr = ALIGN_TO_128KB(mfc_port1_alloc_paddr); + mfc_port1_base_vaddr = phys_to_virt(mfc_port1_alloc_paddr); + + if (mfc_port1_base_vaddr == NULL) { + mfc_err("fail to mapping port1 buffer\n"); + ret = -EPERM; + goto err_vaddr_map; + } + + mfc_set_port1_buff_paddr(mfc_port1_alloc_paddr); + + mfc_debug("mfc_port0_base_paddr = 0x%08x, mfc_port1_base_paddr = 0x%08x <<\n", + (unsigned int)mfc_port0_base_paddr, (unsigned int)mfc_port1_base_paddr); + mfc_debug("mfc_port0_base_vaddr = 0x%08x, mfc_port1_base_vaddr = 0x%08x <<\n", + (unsigned int)mfc_port0_base_vaddr, (unsigned int)mfc_port1_base_vaddr); + mfc_debug("mfc_port1_alloc_paddr = 0x%08x <<\n", (unsigned int)mfc_port1_alloc_paddr); + + /* Get mfc power domain regulator */ + mfc_pd_regulator = regulator_get(&pdev->dev, "pd"); + if (IS_ERR(mfc_pd_regulator)) { + mfc_err("failed to find mfc power domain\n"); + ret = PTR_ERR(mfc_pd_regulator); + goto err_regulator_get; + } + + mfc_sclk = clk_get(&pdev->dev, "sclk_mfc"); + if (IS_ERR(mfc_sclk)) { + mfc_err("failed to find mfc clock source\n"); + ret = PTR_ERR(mfc_sclk); + goto err_clk_get; + } + + mfc_init_mem_inst_no(); + mfc_init_buffer(); + + ret = misc_register(&mfc_miscdev); + if (ret) { + mfc_err("MFC can't misc register on minor\n"); + goto err_misc_reg; + } + + /* + * MFC FW downloading + */ + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, + MFC_FW_NAME, + &pdev->dev, + GFP_KERNEL, + pdev, + mfc_firmware_request_complete_handler); + if (ret) { + mfc_err("MFCINST_ERR_FW_INIT_FAIL\n"); + ret = -EPERM; + goto err_req_fw; + } + + return 0; + +err_req_fw: + misc_deregister(&mfc_miscdev); +err_misc_reg: + clk_put(mfc_sclk); +err_clk_get: + regulator_put(mfc_pd_regulator); +err_regulator_get: +err_vaddr_map: + free_irq(res->start, pdev); + mutex_destroy(&mfc_mutex); +err_irq_req: +err_irq_res: + iounmap(mfc_sfr_base_vaddr); +err_mem_map: + release_mem_region(mfc_mem, size); +err_mem_req: +probe_out: + dev_err(&pdev->dev, "not found (%d).\n", ret); + return ret; +} + +static int mfc_remove(struct platform_device *pdev) +{ + iounmap(mfc_sfr_base_vaddr); + iounmap(mfc_port0_base_vaddr); + + /* remove memory region */ + if (mfc_mem != NULL) { + release_resource(mfc_mem); + kfree(mfc_mem); + mfc_mem = NULL; + } + + free_irq(IRQ_MFC, pdev); + + mutex_destroy(&mfc_mutex); + + clk_put(mfc_sclk); + + misc_deregister(&mfc_miscdev); + + if (mfc_fw_info) + release_firmware(mfc_fw_info); + + return 0; +} + +static int mfc_suspend(struct platform_device *pdev, pm_message_t state) +{ + int ret = 0; + + mutex_lock(&mfc_mutex); + + if (!mfc_is_running()) { + mutex_unlock(&mfc_mutex); + return 0; + } + clk_enable(mfc_sclk); + + ret = mfc_set_sleep(); + if (ret != MFCINST_RET_OK) { + clk_disable(mfc_sclk); + mutex_unlock(&mfc_mutex); + return ret; + } + + clk_disable(mfc_sclk); + + mutex_unlock(&mfc_mutex); + + return 0; +} + +static int mfc_resume(struct platform_device *pdev) +{ + int ret = 0; + unsigned int mc_status; + + mutex_lock(&mfc_mutex); + + if (!mfc_is_running()) { + mutex_unlock(&mfc_mutex); + return 0; + } + + clk_enable(mfc_sclk); + + /* + * 1. MFC reset + */ + do { + mc_status = READL(MFC_MC_STATUS); + } while (mc_status != 0); + + if (mfc_cmd_reset() == false) { + clk_disable(mfc_sclk); + mutex_unlock(&mfc_mutex); + mfc_err("MFCINST_ERR_INIT_FAIL\n"); + return MFCINST_ERR_INIT_FAIL; + } + + WRITEL(mfc_port0_base_paddr, MFC_MC_DRAMBASE_ADDR_A); + WRITEL(mfc_port1_base_paddr, MFC_MC_DRAMBASE_ADDR_B); + WRITEL(1, MFC_NUM_MASTER); + + ret = mfc_set_wakeup(); + if (ret != MFCINST_RET_OK) { + clk_disable(mfc_sclk); + mutex_unlock(&mfc_mutex); + return ret; + } + + clk_disable(mfc_sclk); + + mutex_unlock(&mfc_mutex); + + return 0; +} + +static struct platform_driver mfc_driver = { + .probe = mfc_probe, + .remove = mfc_remove, + .shutdown = NULL, + .suspend = mfc_suspend, + .resume = mfc_resume, + + .driver = { + .owner = THIS_MODULE, + .name = "s3c-mfc", + }, +}; + +static char banner[] __initdata = KERN_INFO "S5PC110 MFC Driver, (c) 2009 Samsung Electronics\n"; + +static int __init mfc_init(void) +{ + mfc_info("%s\n", banner); + + if (platform_driver_register(&mfc_driver) != 0) { + mfc_err(KERN_ERR "platform device registration failed..\n"); + return -1; + } + + return 0; +} + +static void __exit mfc_exit(void) +{ + platform_driver_unregister(&mfc_driver); + mfc_info("S5PC110 MFC Driver exit.\n"); +} + +module_init(mfc_init); +module_exit(mfc_exit); + +MODULE_AUTHOR("Jaeryul, Oh"); +MODULE_DESCRIPTION("S3C MFC (Multi Function Codec - FIMV5.0) Device Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/samsung/mfc50/mfc_buffer_manager.c b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.c new file mode 100644 index 0000000..c480cde --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.c @@ -0,0 +1,350 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_buffer_manager.c + * + * C file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Key-Young Park, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - use struct list_head for duble linked list + * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park) + * 2009.11.13 - fix free buffer fragmentation (Key Young, Park) + * + * 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/mm.h> +#include <linux/interrupt.h> +#include <linux/miscdevice.h> +#include <linux/platform_device.h> +#include <linux/wait.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#include <plat/media.h> +#include <mach/media.h> + +#include "mfc_buffer_manager.h" +#include "mfc_errorno.h" +#include "mfc_logmsg.h" +#include "mfc_memory.h" + +static struct list_head mfc_alloc_mem_head[MFC_MAX_PORT_NUM]; +static struct list_head mfc_free_mem_head[MFC_MAX_PORT_NUM]; + +void mfc_print_mem_list(void) +{ + struct list_head *pos; + struct mfc_alloc_mem *alloc_node; + struct mfc_free_mem *free_node; + int port_no; + + for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) { + mfc_info("===== %s port%d list =====\n", __func__, port_no); + list_for_each(pos, &mfc_alloc_mem_head[port_no]) + { + alloc_node = list_entry(pos, struct mfc_alloc_mem, list); + mfc_info("[alloc_list] inst_no: %d, p_addr: 0x%08x, " + "u_addr: 0x%p, size: %d\n", + alloc_node->inst_no, + alloc_node->p_addr, + alloc_node->u_addr, + alloc_node->size); + } + + list_for_each(pos, &mfc_free_mem_head[port_no]) + { + free_node = list_entry(pos, struct mfc_free_mem, list); + mfc_info("[free_list] start_addr: 0x%08x size:%d\n", + free_node->start_addr , free_node->size); + } + } +} + +void mfc_merge_fragment(int inst_no) +{ + struct list_head *pos, *n; + struct mfc_free_mem *node1, *node2; + int port_no; + + for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) { + list_for_each_safe(pos, n, &mfc_free_mem_head[port_no]) + { + node1 = list_entry(pos, struct mfc_free_mem, list); + node2 = list_entry(n, struct mfc_free_mem, list); + if ((node1->start_addr + node1->size) == node2->start_addr) { + node2->start_addr = node1->start_addr; + node2->size += node1->size; + list_del(&(node1->list)); + kfree(node1); + } + } + } + +#if defined(DEBUG) + mfc_print_mem_list(); +#endif +} + + + +static unsigned int mfc_get_free_mem(int alloc_size, int inst_no, int port_no) +{ + struct list_head *pos; + struct mfc_free_mem *free_node, *match_node = NULL; + unsigned int alloc_addr = 0; + + mfc_debug("request Size : %d\n", alloc_size); + + if (list_empty(&mfc_free_mem_head[port_no])) { + mfc_err("all memory is gone\n"); + return alloc_addr; + } + /* find best chunk of memory */ + list_for_each(pos, &mfc_free_mem_head[port_no]) + { + free_node = list_entry(pos, struct mfc_free_mem, list); + + if (match_node != NULL) { + if ((free_node->size >= alloc_size) && + (free_node->size < match_node->size)) + match_node = free_node; + } else { + if (free_node->size >= alloc_size) + match_node = free_node; + } + } + + + if (match_node != NULL) { + mfc_debug("match : startAddr(0x%08x) size(%d)\n", match_node->start_addr, match_node->size); + + alloc_addr = match_node->start_addr; + match_node->start_addr += alloc_size; + match_node->size -= alloc_size; + + if (match_node->size < 0x1) /* delete match_node. */ + mfc_err("there is no suitable chunk...[case 0]\n"); + } else { + mfc_err("there is no suitable chunk....[case 1]\n"); + return 0; + } + + return alloc_addr; +} + + +int mfc_init_buffer(void) +{ + struct mfc_free_mem *free_node; + int port_no; + + for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) { + INIT_LIST_HEAD(&mfc_alloc_mem_head[port_no]); + INIT_LIST_HEAD(&mfc_free_mem_head[port_no]); + /* init free head node */ + free_node = + (struct mfc_free_mem *)kmalloc(sizeof(struct mfc_free_mem), GFP_KERNEL); + memset(free_node, 0x00, sizeof(struct mfc_free_mem)); + + if (port_no) { + free_node->start_addr = mfc_get_port1_buff_paddr(); + free_node->size = mfc_port1_memsize; + } else { + free_node->start_addr = mfc_get_port0_buff_paddr(); + free_node->size = mfc_port0_memsize - + (mfc_get_port0_buff_paddr() - mfc_get_fw_buff_paddr()); + } + + list_add_tail(&(free_node->list), &mfc_free_mem_head[port_no]); + } + +#if defined(DEBUG) + mfc_print_mem_list(); +#endif + return 0; +} + +enum mfc_error_code mfc_release_buffer(unsigned char *u_addr) +{ + struct list_head *pos; + int port_no; + struct mfc_alloc_mem *alloc_node; + bool found = false; + + for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) { + list_for_each(pos, &mfc_alloc_mem_head[port_no]) + { + alloc_node = list_entry(pos, struct mfc_alloc_mem, list); + if (alloc_node->u_addr == u_addr) { + mfc_free_alloc_mem(alloc_node, port_no); + found = true; + break; + } + } + } + +#if defined(DEBUG) + mfc_print_mem_list(); +#endif + + if (found) + return MFCINST_RET_OK; + else + return MFCINST_MEMORY_INVALID_ADDR; +} + +void mfc_release_all_buffer(int inst_no) +{ + struct list_head *pos, *n; + int port_no; + struct mfc_alloc_mem *alloc_node; + + for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) { + list_for_each_safe(pos, n, &mfc_alloc_mem_head[port_no]) { + alloc_node = list_entry(pos, struct mfc_alloc_mem, list); + if (alloc_node->inst_no == inst_no) { + mfc_free_alloc_mem(alloc_node, port_no); + } + } + } + +#if defined(DEBUG) + mfc_print_mem_list(); +#endif +} + +void mfc_free_alloc_mem(struct mfc_alloc_mem *alloc_node, int port_no) +{ + struct list_head *pos; + struct mfc_free_mem *free_node; + struct mfc_free_mem *target_node; + + free_node = (struct mfc_free_mem *)kmalloc(sizeof(struct mfc_free_mem), GFP_KERNEL); + free_node->start_addr = alloc_node->p_addr; + free_node->size = alloc_node->size; + + list_for_each(pos, &mfc_free_mem_head[port_no]) + { + target_node = list_entry(pos, struct mfc_free_mem, list); + if (alloc_node->p_addr < target_node->start_addr) + break; + } + + if (pos == &mfc_free_mem_head[port_no]) + list_add_tail(&(free_node->list), &(mfc_free_mem_head[port_no])); + else + list_add_tail(&(free_node->list), pos); + + list_del(&(alloc_node->list)); + kfree(alloc_node); +} + +enum mfc_error_code mfc_get_phys_addr(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + int ret, port_no; + struct list_head *pos; + struct mfc_alloc_mem *alloc_node; + struct mfc_get_phys_addr_arg *phys_addr_arg; + + phys_addr_arg = (struct mfc_get_phys_addr_arg *)args; + for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) { + list_for_each(pos, &mfc_alloc_mem_head[port_no]) + { + alloc_node = list_entry(pos, struct mfc_alloc_mem, list); + if (alloc_node->u_addr == (unsigned char *)phys_addr_arg->u_addr) { + mfc_debug("u_addr(0x%08x), p_addr(0x%08x) is found\n", + alloc_node->u_addr, alloc_node->p_addr); + goto found; + } + } + } + + mfc_err("invalid virtual address(0x%08x)\r\n", phys_addr_arg->u_addr); + ret = MFCINST_MEMORY_INVALID_ADDR; + goto out_getphysaddr; + +found: + phys_addr_arg->p_addr = alloc_node->p_addr; + ret = MFCINST_RET_OK; + +out_getphysaddr: + return ret; +} + +enum mfc_error_code mfc_allocate_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args, int port_no) +{ + int ret; + int inst_no = mfc_ctx->mem_inst_no; + unsigned int start_paddr; + struct mfc_mem_alloc_arg *in_param; + struct mfc_alloc_mem *alloc_node; + + in_param = (struct mfc_mem_alloc_arg *)args; + + alloc_node = (struct mfc_alloc_mem *)kmalloc(sizeof(struct mfc_alloc_mem), GFP_KERNEL); + if (!alloc_node) { + mfc_err("There is no more kernel memory"); + ret = MFCINST_MEMORY_ALLOC_FAIL; + goto out_getcodecviraddr; + } + memset(alloc_node, 0x00, sizeof(struct mfc_alloc_mem)); + + /* if user request area, allocate from reserved area */ + start_paddr = mfc_get_free_mem((int)in_param->buff_size, inst_no, port_no); + mfc_debug("start_paddr = 0x%X\n\r", start_paddr); + + if (!start_paddr) { + mfc_err("There is no more memory\n\r"); + in_param->out_uaddr = -1; + ret = MFCINST_MEMORY_ALLOC_FAIL; + kfree(alloc_node); + goto out_getcodecviraddr; + } + + alloc_node->p_addr = start_paddr; + if (port_no) { + alloc_node->v_addr = (unsigned char *)(mfc_get_port1_buff_vaddr() + + (alloc_node->p_addr - mfc_get_port1_buff_paddr())); + alloc_node->u_addr = (unsigned char *)(in_param->mapped_addr + + mfc_ctx->port0_mmap_size + + (alloc_node->p_addr - mfc_get_port1_buff_paddr())); + } else { + alloc_node->v_addr = (unsigned char *)(mfc_get_port0_buff_vaddr() + + (alloc_node->p_addr - mfc_get_port0_buff_paddr())); + alloc_node->u_addr = (unsigned char *)(in_param->mapped_addr + + (alloc_node->p_addr - mfc_get_port0_buff_paddr())); + } + + in_param->out_uaddr = (unsigned int)alloc_node->u_addr; + in_param->out_paddr = (unsigned int)alloc_node->p_addr; + mfc_debug("u_addr : 0x%08x v_addr : 0x%08x p_addr : 0x%08x\n", + (unsigned int)alloc_node->u_addr, + (unsigned int)alloc_node->v_addr, + alloc_node->p_addr); + + alloc_node->size = (int)in_param->buff_size; + alloc_node->inst_no = inst_no; + + list_add(&(alloc_node->list), &mfc_alloc_mem_head[port_no]); + ret = MFCINST_RET_OK; + +#if defined(DEBUG) + mfc_print_mem_list(); +#endif + +out_getcodecviraddr: + return ret; +} diff --git a/drivers/media/video/samsung/mfc50/mfc_buffer_manager.h b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.h new file mode 100644 index 0000000..d40bc04 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.h @@ -0,0 +1,56 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_buffer_manager.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Key-Young Park, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.11.04 - remove mfc_common.[ch] + * seperate buffer alloc & set (Key Young, Park) + * + * 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 _MFC_BUFFER_MANAGER_H_ +#define _MFC_BUFFER_MANAGER_H_ + +#include <linux/list.h> +#include "mfc_interface.h" +#include "mfc_opr.h" + +#define MFC_MAX_PORT_NUM 2 + +/* Struct Definition */ +struct mfc_alloc_mem { + struct list_head list; /* strcut list_head for alloc mem */ + unsigned int p_addr; /* physical address */ + unsigned char *v_addr; /* virtual address */ + unsigned char *u_addr; /* virtual address for user mode process */ + int size; /* memory size */ + int inst_no; /* instance no */ +}; + + +struct mfc_free_mem { + struct list_head list; /* struct list_head for free mem */ + unsigned int start_addr; /* start address of free mem */ + unsigned int size; /* size of free mem */ +}; + + +/* Function Prototype */ +void mfc_print_mem_list(void); +int mfc_init_buffer(void); +void mfc_merge_fragment(int inst_no); +void mfc_release_all_buffer(int inst_no); +void mfc_free_alloc_mem(struct mfc_alloc_mem *alloc_node, int port_no); +enum mfc_error_code mfc_release_buffer(unsigned char *u_addr); +enum mfc_error_code mfc_get_phys_addr(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +enum mfc_error_code mfc_allocate_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args, int port_no); + +#endif /* _MFC_BUFFER_MANAGER_H_ */ diff --git a/drivers/media/video/samsung/mfc50/mfc_errorno.h b/drivers/media/video/samsung/mfc50/mfc_errorno.h new file mode 100644 index 0000000..7f27115 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_errorno.h @@ -0,0 +1,83 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_errorno.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * 2009.09.21 - Implement clock & power gating. + * including suspend & resume fuction. (Key Young, Park) + * + * 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 _MFC_ERRORNO_H_ +#define _MFC_ERRORNO_H_ + +enum mfc_error_code { + MFCINST_RET_OK = 1, + MFCINST_ERR_INVALID_PARAM = -1001, + MFCINST_ERR_STATE_INVALID = -1002, + MFCINST_ERR_POWER_OFF = -1003, + MFCINST_ERR_WRONG_CODEC_MODE = -1004, + MFCINST_ERR_INIT_FAIL = -1005, + MFCINST_ERR_FILE_OPEN_FAIL = -1006, + MFCINST_ERR_INTR_TIME_OUT = -1007, + MFCINST_ERR_INTR_INIT_FAIL = -1008, + MFCINST_ERR_OPEN_FAIL = -1009, + MFCINST_ERR_CLOSE_FAIL = -1010, + + + MFCINST_ERR_DEC_INIT_CMD_FAIL = -2001, + MFCINST_ERR_DEC_HEADER_DECODE_FAIL = -2002, + MFCINST_ERR_DEC_INIT_BUFFER_FAIL = -2003, + MFCINST_ERR_DEC_DECODE_CMD_FAIL = -2004, + MFCINST_ERR_DEC_DECODE_DONE_FAIL = -2005, + MFCINST_ERR_DEC_INVALID_STRM = -2006, + MFCINST_ERR_DEC_STRM_SIZE_INVALID = -2007, + MFCINST_ERR_DEC_SEQ_DONE_FAIL = -2008, + MFCINST_ERR_DEC_NON_I_FRAME_START = -2009, + + MFCINST_ERR_ENC_INIT_CMD_FAIL = -3001, + MFCINST_ERR_ENC_HEADER_DECODE_FAIL = -3002, + MFCINST_ERR_ENC_ENCODE_CMD_FAIL = -3003, + MFCINST_ERR_ENC_ENCODE_DONE_FAIL = -3004, + MFCINST_ERR_ENC_PARAM_INVALID_VALUE = -3005, + + MFCINST_ERR_STRM_BUF_INVALID = -4001, + MFCINST_ERR_FRM_BUF_INVALID = -4002, + MFCINST_ERR_FRM_BUF_SIZE = -4003, + + MFCINST_ERR_FW_LOAD_FAIL = -5001, + MFCINST_ERR_FW_MEMORY_INVALID = -5002, + MFCINST_ERR_FW_DMA_SET_FAIL = -5003, + MFCINST_ERR_FW_INIT_FAIL = -5004, + MFCINST_ERR_SEQ_START_FAIL = -5005, + + MFCINST_INST_NUM_INVALID = -6001, + MFCINST_INST_NUM_EXCEEDED = -6002, + MFCINST_ERR_SET_CONF = -6003, + MFCINST_ERR_GET_CONF = -6004, + + MFCINST_MEMORY_ALLOC_FAIL = -8001, + MFCINST_MUTEX_CREATE_FAIL = -8002, + MFCINST_POWER_INIT_FAIL = -8003, + MFCINST_POWER_ON_OFF_FAIL = -8004, + MFCINST_POWER_STATE_INVALID = -8005, + MFCINST_POWER_MANAGER_ERR = -8006, + MFCINST_SLEEP_FAIL = -8007, + MFCINST_WAKEUP_FAIL = -8008, + + MFCINST_MEMORY_INVALID_ADDR = -8101, + MFCINST_MEMORY_MAPPING_FAIL = -8102, + + MFCAPI_RET_FAIL = -9001, +}; + +#endif /* _MFC_ERRORNO_H_ */ + diff --git a/drivers/media/video/samsung/mfc50/mfc_interface.h b/drivers/media/video/samsung/mfc50/mfc_interface.h new file mode 100644 index 0000000..4da825a --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_interface.h @@ -0,0 +1,340 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_interface.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * 2009.10.22 - Change codec name VC1AP_DEC -> VC1_DEC (Key Young, Park) + * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park) + * 2009.11.06 - Apply common MFC API (Key Young, Park) + * + * 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 _MFC_INTERFACE_H_ +#define _MFC_INTERFACE_H_ + +#include "mfc_errorno.h" + +#define IOCTL_MFC_DEC_INIT 0x00800001 +#define IOCTL_MFC_ENC_INIT 0x00800002 +#define IOCTL_MFC_DEC_EXE 0x00800003 +#define IOCTL_MFC_ENC_EXE 0x00800004 + +#define IOCTL_MFC_GET_IN_BUF 0x00800010 +#define IOCTL_MFC_FREE_BUF 0x00800011 +#define IOCTL_MFC_GET_PHYS_ADDR 0x00800012 +#define IOCTL_MFC_GET_MMAP_SIZE 0x00800014 + +#define IOCTL_MFC_SET_CONFIG 0x00800101 +#define IOCTL_MFC_GET_CONFIG 0x00800102 + +#define IOCTL_MFC_BUF_CACHE 0x00801000 + +/* MFC H/W support maximum 32 extra DPB */ +#define MFC_MAX_EXTRA_DPB 4 + +#define ENC_PROFILE_LEVEL(profile, level) ((profile) | ((level) << 8)) + +#define ENC_PROFILE_MPEG4_SP 0 +#define ENC_PROFILE_MPEG4_ASP 1 +#define ENC_PROFILE_H264_BP 0 +#define ENC_PROFILE_H264_MAIN 1 +#define ENC_PROFILE_H264_HIGH 2 + +#define ENC_RC_DISABLE 0 +#define ENC_RC_ENABLE_MACROBLOCK 1 +#define ENC_RC_ENABLE_FRAME 2 + +#define ENC_RC_QBOUND(min_qp, max_qp) ((min_qp) | ((max_qp) << 8)) +#define ENC_RC_MB_CTRL_DARK_DISABLE (1 << 3) +#define ENC_RC_MB_CTRL_SMOOTH_DISABLE (1 << 2) +#define ENC_RC_MB_CTRL_STATIC_DISABLE (1 << 1) +#define ENC_RC_MB_CTRL_ACTIVITY_DISABLE (1 << 0) + + +enum ssbsip_mfc_codec_type { + H264_DEC, + VC1_DEC, /* VC1 advaced Profile decoding */ + MPEG4_DEC, + XVID_DEC, + MPEG1_DEC, + MPEG2_DEC, + H263_DEC, + VC1RCV_DEC, /* VC1 simple/main profile decoding */ + FIMV1_DEC, + FIMV2_DEC, + FIMV3_DEC, + FIMV4_DEC, + H264_ENC, + MPEG4_ENC, + H263_ENC, + UNKNOWN_TYPE +}; + +enum ssbsip_mfc_force_set_frame_type { + DONT_CARE = 0, + I_FRAME = 1, + NOT_CODED = 2 +}; + +enum ssbsip_mfc_dec_conf { + MFC_DEC_SETCONF_POST_ENABLE = 1, + MFC_DEC_SETCONF_EXTRA_BUFFER_NUM, + MFC_DEC_SETCONF_DISPLAY_DELAY, + MFC_DEC_SETCONF_IS_LAST_FRAME, + MFC_DEC_SETCONF_SLICE_ENABLE, + MFC_DEC_SETCONF_CRC_ENABLE, + MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT, + MFC_DEC_SETCONF_FRAME_TAG, + MFC_DEC_GETCONF_CRC_DATA, + MFC_DEC_GETCONF_BUF_WIDTH_HEIGHT, + FC_DEC_GETCONF_CROP_INFO, + MFC_DEC_GETCONF_FRAME_TAG +}; + +enum ssbsip_mfc_enc_conf { + MFC_ENC_SETCONF_FRAME_TYPE = 100, + MFC_ENC_SETCONF_CHANGE_FRAME_RATE, + MFC_ENC_SETCONF_CHANGE_BIT_RATE, + MFC_ENC_SETCONF_FRAME_TAG, + MFC_ENC_SETCONF_ALLOW_FRAME_SKIP, + MFC_ENC_GETCONF_FRAME_TAG +}; + +struct mfc_strm_ref_buf_arg { + unsigned int strm_ref_y; + unsigned int mv_ref_yc; +}; + +struct mfc_frame_buf_arg { + unsigned int luma; + unsigned int chroma; +}; + +struct mfc_enc_init_mpeg4_arg { + enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */ + int in_width; /* [IN] width of YUV420 frame to be encoded */ + int in_height; /* [IN] height of YUV420 frame to be encoded */ + int in_profile_level; /* [IN] profile & level */ + int in_gop_num; /* [IN] GOP Number (interval of I-frame) */ + int in_frame_qp; /* [IN] the quantization parameter of the frame */ + int in_frame_P_qp; /* [IN] the quantization parameter of the P frame */ + int in_frame_B_qp; /* [IN] the quantization parameter of the B frame */ + + int in_RC_frm_enable; /* [IN] RC enable (0:disable, 1:frame level RC) */ + int in_RC_framerate; /* [IN] RC parameter (framerate) */ + int in_RC_bitrate; /* [IN] RC parameter (bitrate in kbps) */ + int in_RC_qbound; /* [IN] RC parameter (Q bound) */ + int in_RC_rpara; /* [IN] RC parameter (Reaction Coefficient) */ + + int in_MS_mode; /* [IN] Multi-slice mode (0:single, 1:multiple) */ + int in_MS_size; /* [IN] Multi-slice size (in num. of mb or byte) */ + int in_mb_refresh; /* [IN] Macroblock refresh */ + int in_interlace_mode; /* [IN] interlace mode(0:progressive, 1:interlace) */ + int in_BframeNum; /* [IN] B frame number */ + + int in_pad_ctrl_on; /* [IN] Enable (1) / Disable (0) padding */ + int in_luma_pad_val; /* [IN] pad value if pad_ctrl_on is Enable */ + int in_cb_pad_val; + int in_cr_pad_val; + + int in_frame_map; /* [IN] Encoding input NV12 type linear(0) TILE(1) */ + + unsigned int in_mapped_addr; + struct mfc_strm_ref_buf_arg out_u_addr; + struct mfc_strm_ref_buf_arg out_p_addr; + struct mfc_strm_ref_buf_arg out_buf_size; + unsigned int out_header_size; + + /* MPEG4 Only */ + int in_qpelME_enable; /* [IN] Quarter-pel MC enable(1:enable, 0:disable) */ + int in_time_increament_res; /* [IN] time increment resolution */ + int in_time_vop_time_increament; /* [IN] time increment */ +}; + +//struct mfc_enc_init_mpeg4_arg mfc_enc_init_h263_arg; + +struct mfc_enc_init_h264_arg { + enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */ + int in_width; /* [IN] width of YUV420 frame to be encoded */ + int in_height; /* [IN] height of YUV420 frame to be encoded */ + int in_profile_level; /* [IN] profile & level */ + int in_gop_num; /* [IN] GOP Number (interval of I-frame) */ + int in_frame_qp; /* [IN] the quantization parameter of the frame */ + int in_frame_P_qp; /* [IN] the quantization parameter of the P frame */ + int in_frame_B_qp; /* [IN] the quantization parameter of the B frame */ + + int in_RC_frm_enable; /* [IN] RC enable (0:disable, 1:frame level RC) */ + int in_RC_framerate; /* [IN] RC parameter (framerate) */ + int in_RC_bitrate; /* [IN] RC parameter (bitrate in kbps) */ + int in_RC_qbound; /* [IN] RC parameter (Q bound) */ + int in_RC_rpara; /* [IN] RC parameter (Reaction Coefficient) */ + + int in_MS_mode; /* [IN] Multi-slice mode (0:single, 1:multiple) */ + int in_MS_size; /* [IN] Multi-slice size (in num. of mb or byte) */ + int in_mb_refresh; /* [IN] Macroblock refresh */ + int in_interlace_mode; /* [IN] interlace mode(0:progressive, 1:interlace) */ + int in_BframeNum; + + int in_pad_ctrl_on; /* [IN] Enable padding control */ + int in_luma_pad_val; /* [IN] Luma pel value used to fill padding area */ + int in_cb_pad_val; /* [IN] CB pel value used to fill padding area */ + int in_cr_pad_val; /* [IN] CR pel value used to fill padding area */ + + int in_frame_map; /* [IN] Encoding input NV12 type linear(0) TILE(1) */ + + unsigned int in_mapped_addr; + struct mfc_strm_ref_buf_arg out_u_addr; + struct mfc_strm_ref_buf_arg out_p_addr; + struct mfc_strm_ref_buf_arg out_buf_size; + unsigned int out_header_size; + + /* H264 Only */ + int in_RC_mb_enable; /* [IN] RC enable (0:disable, 1:MB level RC) */ + int in_reference_num; /* [IN] The number of reference pictures used */ + int in_ref_num_p; /* [IN] The number of reference pictures used for P pictures */ + int in_RC_mb_dark_disable; /* [IN] Disable adaptive rate control on dark region */ + int in_RC_mb_smooth_disable; /* [IN] Disable adaptive rate control on smooth region */ + int in_RC_mb_static_disable; /* [IN] Disable adaptive rate control on static region */ + int in_RC_mb_activity_disable; /* [IN] Disable adaptive rate control on static region */ + int in_deblock_filt; /* [IN] disable the loop filter */ + int in_deblock_alpha_C0; /* [IN] Alpha & C0 offset for H.264 loop filter */ + int in_deblock_beta; /* [IN] Beta offset for H.264 loop filter */ + int in_symbolmode; /* [IN] The mode of entropy coding(CABAC, CAVLC) */ + int in_transform8x8_mode; /* [IN] Allow 8x8 transform(only for high profile) */ + int in_md_interweight_pps; /* [IN] Inter weighted parameter for mode decision */ + int in_md_intraweight_pps; /* [IN] Intra weighted parameter for mode decision */ +}; + +struct mfc_enc_exe_arg { + enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */ + unsigned int in_Y_addr; /* [IN] In-buffer addr of Y component */ + unsigned int in_CbCr_addr; /* [IN] In-buffer addr of CbCr component */ + unsigned int in_Y_addr_vir; /* [IN] In-buffer addr of Y component */ + unsigned int in_CbCr_addr_vir; /* [IN] In-buffer addr of CbCr component */ + unsigned int in_strm_st; /* [IN] Out-buffer start addr of encoded strm */ + unsigned int in_strm_end; /* [IN] Out-buffer end addr of encoded strm */ + int in_frametag; /* [IN] unique frame ID */ + + unsigned int out_frame_type; /* [OUT] frame type */ + int out_encoded_size; /* [OUT] Length of Encoded video stream */ + unsigned int out_encoded_Y_paddr; /* [OUT] physical Y address which is flushed */ + unsigned int out_encoded_C_paddr; /* [OUT] physical C address which is flushed */ + int out_frametag_top; /* [OUT] unique frame ID of an output frame or top field */ + int out_frametag_bottom; /* [OUT] unique frame ID of bottom field */ +}; + +struct mfc_dec_init_arg { + enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */ + unsigned int in_strm_buf; /* [IN] the physical address of STRM_BUF */ + int in_strm_size; /* [IN] size of video stream filled in STRM_BUF */ + int in_packed_PB; /* [IN] Is packed PB frame or not, 1: packedPB 0: unpacked */ + + int out_img_width; /* [OUT] width of YUV420 frame */ + int out_img_height; /* [OUT] height of YUV420 frame */ + int out_buf_width; /* [OUT] width of YUV420 frame */ + int out_buf_height; /* [OUT] height of YUV420 frame */ + int out_dpb_cnt; /* [OUT] the number of buffers which is nessary during decoding */ + + int out_crop_top_offset; /* [OUT] crop information, top offset */ + int out_crop_bottom_offset; /* [OUT] crop information, bottom offset */ + int out_crop_left_offset; /* [OUT] crop information, left offset */ + int out_crop_right_offset; /* [OUT] crop information, right offset */ + + struct mfc_frame_buf_arg in_frm_buf; /* [IN] the address of dpb FRAME_BUF */ + struct mfc_frame_buf_arg in_frm_size; /* [IN] size of dpb FRAME_BUF */ + unsigned int in_mapped_addr; + + struct mfc_frame_buf_arg out_u_addr; + struct mfc_frame_buf_arg out_p_addr; + struct mfc_frame_buf_arg out_frame_buf_size; +}; + +struct mfc_dec_exe_arg { + enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */ + unsigned int in_strm_buf; /* [IN] the physical address of STRM_BUF */ + int in_strm_size; /* [IN] Size of video stream filled in STRM_BUF */ + struct mfc_frame_buf_arg in_frm_buf; /* [IN] the address of dpb FRAME_BUF */ + struct mfc_frame_buf_arg in_frm_size; /* [IN] size of dpb FRAME_BUF */ + int in_frametag; /* [IN] unique frame ID */ + + unsigned int out_display_Y_addr; /* [OUT] the physical address of display buf */ + unsigned int out_display_C_addr; /* [OUT] the physical address of display buf */ + int out_display_status; /* [OUT] whether display frame exist or not. */ + int out_timestamp_top; /* [OUT] presentation time of an output frame or top field */ + int out_timestamp_bottom; /* [OUT] presentation time of bottom field */ + int out_consume_bytes; /* [OUT] consumed bytes when decoding finished */ + int out_frametag_top; /* [OUT] unique frame ID of an output frame or top field */ + int out_frametag_bottom; /* [OUT] unique frame ID of bottom field */ + int out_res_change; /* [OUT] whether resolution is changed or not (0, 1, 2) */ + int out_crop_top_offset; /* [OUT] crop information, top offset */ + int out_crop_bottom_offset; /* [OUT] crop information, bottom offset */ + int out_crop_left_offset; /* [OUT] crop information, left offset */ + int out_crop_right_offset; /* [OUT] crop information, right offset */ +}; + +struct mfc_get_config_arg { + int in_config_param; /* [IN] Configurable parameter type */ + int out_config_value[4]; /* [IN] Values to get for the configurable parameter. */ +}; + +struct mfc_set_config_arg { + int in_config_param; /* [IN] Configurable parameter type */ + int in_config_value[2]; /* [IN] Values to be set for the configurable parameter. */ + int out_config_value_old[2]; /* [OUT] Old values of the configurable parameters */ +}; + +struct mfc_get_phys_addr_arg { + unsigned int u_addr; + unsigned int p_addr; +}; + +struct mfc_mem_alloc_arg { + enum ssbsip_mfc_codec_type codec_type; + int buff_size; + unsigned int mapped_addr; + unsigned int out_uaddr; + unsigned int out_paddr; +}; + +struct mfc_mem_free_arg { + unsigned int u_addr; +}; + +enum mfc_buffer_type { + MFC_BUFFER_NO_CACHE = 0, + MFC_BUFFER_CACHE = 1 +}; + +union mfc_args { + struct mfc_enc_init_mpeg4_arg enc_init_mpeg4; + struct mfc_enc_init_mpeg4_arg enc_init_h263; + struct mfc_enc_init_h264_arg enc_init_h264; + struct mfc_enc_exe_arg enc_exe; + + struct mfc_dec_init_arg dec_init; + struct mfc_dec_exe_arg dec_exe; + + struct mfc_get_config_arg get_config; + struct mfc_set_config_arg set_config; + + struct mfc_mem_alloc_arg mem_alloc; + struct mfc_mem_free_arg mem_free; + struct mfc_get_phys_addr_arg get_phys_addr; + + enum mfc_buffer_type buf_type; +}; + +struct mfc_common_args { + enum mfc_error_code ret_code; /* [OUT] error code */ + union mfc_args args; +}; + +#endif /* _MFC_INTERFACE_H_ */ diff --git a/drivers/media/video/samsung/mfc50/mfc_intr.c b/drivers/media/video/samsung/mfc50/mfc_intr.c new file mode 100644 index 0000000..035d460 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_intr.c @@ -0,0 +1,202 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_intr.c + * + * C file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * 2009.09.21 - Implement clock & power gating. + * including suspend & resume fuction. (Key Young, Park) + * 2009.10.09 - Add error handling rountine (Key Young, Park) + * 2009.10.13 - Change wait_for_done (Key Young, Park) + * 2009.11.04 - remove mfc_common.[ch] + * seperate buffer alloc & set (Key Young, Park) + * + * 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/delay.h> +#include <linux/errno.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/io.h> + +#include <plat/regs-mfc.h> + +#include "mfc_logmsg.h" +#include "mfc_opr.h" +#include "mfc_memory.h" +#include "mfc_intr.h" + + +#define MFC_WAIT_1_TIME 100 +#define MFC_WAIT_2_TIME 200 +#define MFC_WAIT_3_TIME 400 +#define MFC_WAIT_4_TIME 600 +#define MFC_WAIT_5_TIME 800 +#define MFC_WAIT_6_TIME 1000 + +#define ENABLE_MFC_INTERRUPT_DEBUG 0 /* 0: Disable 1: Enable */ + +#if defined(MFC_REQUEST_TIME) +struct timeval mfc_wakeup_before; +struct timeval mfc_wakeup_after; +#endif + +static unsigned int mfc_int_type; +static unsigned int mfc_disp_err_status; +static unsigned int mfc_dec_err_status; +static bool irq_sync; +static DECLARE_WAIT_QUEUE_HEAD(mfc_wait_queue); +static DEFINE_SPINLOCK(mfc_irq_lock); + +#if !defined(MFC_POLLING) +irqreturn_t mfc_irq(int irq, void *dev_id) +{ + unsigned int int_reason; + unsigned int err_status; + + int_reason = READL(MFC_RISC2HOST_COMMAND) & 0x1FFFF; + err_status = READL(MFC_RISC2HOST_ARG2); + + mfc_disp_err_status = err_status >> 16; + mfc_dec_err_status = err_status & 0xFFFF; + + mfc_debug_L0("mfc_irq() : Interrupt !! : %d\n", int_reason); + + if (((int_reason & R2H_CMD_FRAME_DONE_RET) == R2H_CMD_FRAME_DONE_RET) || + ((int_reason & R2H_CMD_SEQ_DONE_RET) == R2H_CMD_SEQ_DONE_RET) || + ((int_reason & R2H_CMD_SYS_INIT_RET) == R2H_CMD_SYS_INIT_RET) || + ((int_reason & R2H_CMD_OPEN_INSTANCE_RET) == R2H_CMD_OPEN_INSTANCE_RET) || + ((int_reason & R2H_CMD_CLOSE_INSTANCE_RET) == R2H_CMD_CLOSE_INSTANCE_RET) || + ((int_reason & R2H_CMD_INIT_BUFFERS_RET) == R2H_CMD_INIT_BUFFERS_RET) || + ((int_reason & R2H_CMD_DECODE_ERR_RET) == R2H_CMD_DECODE_ERR_RET) || + ((int_reason & R2H_CMD_SLICE_DONE_RET) == R2H_CMD_SLICE_DONE_RET) || + ((int_reason & R2H_CMD_ERROR_RET) == R2H_CMD_ERROR_RET)) { + mfc_int_type = int_reason; + irq_sync = true; + wake_up(&mfc_wait_queue); + } else { + irq_sync = false; + mfc_info("Strange Interrupt !! : %d\n", int_reason); + } + + + WRITEL(0, MFC_RISC_HOST_INT); + WRITEL(0, MFC_RISC2HOST_COMMAND); + WRITEL(0xffff, MFC_SI_RTN_CHID); + + return IRQ_HANDLED; +} +#endif + +void mfc_interrupt_debug(int nCnt) +{ + int nn = 0; + for (nn = 0; nn < nCnt; nn++) { + mdelay(100); + mfc_err("[%d] Timeout (0x64: 0x%08x) (0xF4: 0x%08x)\n", nn, READL(0x64), READL(0xF4)); + } +} + +int mfc_wait_for_done(enum mfc_wait_done_type command) +{ + unsigned int nwait_time = 100; + unsigned int ret_val = 1; + unsigned long flags; + + if ((command == R2H_CMD_CLOSE_INSTANCE_RET) || + (command == R2H_CMD_OPEN_INSTANCE_RET) || + (command == R2H_CMD_SYS_INIT_RET) || + (command == R2H_CMD_FW_STATUS_RET)) + nwait_time = MFC_WAIT_6_TIME; + else + nwait_time = MFC_WAIT_2_TIME; + + +#if defined(MFC_REQUEST_TIME) + long sec, msec; +#endif + +#if defined(MFC_POLLING) + unsigned long timeo = jiffies; + timeo += 20; /* waiting for 100ms */ +#endif + +#if defined(MFC_REQUEST_TIME) + do_gettimeofday(&mfc_wakeup_before); + if (mfc_wakeup_before.tv_usec - mfc_wakeup_after.tv_usec < 0) { + msec = 1000000 + mfc_wakeup_before.tv_usec - mfc_wakeup_after.tv_usec; + sec = mfc_wakeup_before.tv_sec - mfc_wakeup_after.tv_sec - 1; + } else { + msec = mfc_wakeup_before.tv_usec - mfc_wakeup_after.tv_usec; + sec = mfc_wakeup_before.tv_sec - mfc_wakeup_after.tv_sec; + } +#endif + +#if defined(MFC_POLLING) + while (time_before(jiffies, timeo)) + ret_val = READL(MFC_RISC2HOST_COMMAND) & 0x1ffff; + if (ret_val != 0) { + WRITEL(0, MFC_RISC_HOST_INT); + WRITEL(0, MFC_RISC2HOST_COMMAND); + WRITEL(0xffff, MFC_SI_RTN_CHID); + mfc_int_type = ret_val; + break; + } + msleep_interruptible(2); + } + + if (ret_val == 0) + printk(KERN_INFO "MFC timeouted!\n"); +#else + if (wait_event_timeout(mfc_wait_queue, irq_sync, nwait_time) == 0) { + ret_val = 0; + mfc_err("Interrupt Time Out(Cmd: %d) (Ver: 0x%08x) (0x64: 0x%08x) (0xF4: 0x%08x) (0x80: 0x%08x)\n", command, READL(0x58), READL(0x64), READL(0xF4), READL(0x80)); + +#if ENABLE_MFC_INTERRUPT_DEBUG /* For MFC Interrupt Debugging. */ + mfc_interrupt_debug(10); +#endif + + mfc_int_type = 0; + return ret_val; + } else if (mfc_int_type == R2H_CMD_DECODE_ERR_RET) { + mfc_err("Decode Error Returned Disp Error Status(%d), Dec Error Status(%d)\n", mfc_disp_err_status, mfc_dec_err_status); + } else if (command != mfc_int_type) { + mfc_err("Interrupt Error Returned (%d) waiting for (%d)\n", mfc_int_type, command); + } +#endif + spin_lock_irqsave(&mfc_irq_lock, flags); + irq_sync = false; + spin_unlock_irqrestore(&mfc_irq_lock, flags); + +#if defined(MFC_REQUEST_TIME) + do_gettimeofday(&mfc_wakeup_after); + if (mfc_wakeup_after.tv_usec - mfc_wakeup_before.tv_usec < 0) { + msec = 1000000 + mfc_wakeup_after.tv_usec - mfc_wakeup_before.tv_usec; + sec = mfc_wakeup_after.tv_sec - mfc_wakeup_before.tv_sec - 1; + } else { + msec = mfc_wakeup_after.tv_usec - mfc_wakeup_before.tv_usec; + sec = mfc_wakeup_after.tv_sec - mfc_wakeup_before.tv_sec; + } + + mfc_info("mfc_wait_for_done: mfc request interval time is %ld(sec), %ld(msec)\n", sec, msec); +#endif + + ret_val = mfc_int_type; + mfc_int_type = 0; + + return ret_val; +} + + +int mfc_return_code(void) +{ + return mfc_dec_err_status; +} diff --git a/drivers/media/video/samsung/mfc50/mfc_intr.h b/drivers/media/video/samsung/mfc50/mfc_intr.h new file mode 100644 index 0000000..ed156b9 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_intr.h @@ -0,0 +1,25 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_intr.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Key-Young Park, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.10.13 - Separate from mfc_common.h(Key Young, Park) + * + * 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 _MFC_INTR_H_ +#define _MFC_INTR_H_ + +#include <linux/interrupt.h> + +irqreturn_t mfc_irq(int irq, void *dev_id); +int mfc_wait_for_done(enum mfc_wait_done_type command); +int mfc_return_code(void); +#endif diff --git a/drivers/media/video/samsung/mfc50/mfc_logmsg.h b/drivers/media/video/samsung/mfc50/mfc_logmsg.h new file mode 100644 index 0000000..881d733 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_logmsg.h @@ -0,0 +1,72 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_logmsg.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * + * 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 _MFC_LOGMSG_H_ +#define _MFC_LOGMSG_H_ + +/* debug macros */ +#define MFC_DEBUG(fmt, ...) \ + do { \ + printk(KERN_DEBUG \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + +#define MFC_ERROR(fmt, ...) \ + do { \ + printk(KERN_ERR \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + +#define MFC_NOTICE(fmt, ...) \ + do { \ + printk(KERN_NOTICE \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + +#define MFC_INFO(fmt, ...) \ + do { \ + printk(KERN_INFO \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + +#define MFC_WARN(fmt, ...) \ + do { \ + printk(KERN_WARNING \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + + +#ifdef CONFIG_VIDEO_MFC50_DEBUG +#define mfc_debug(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__) +#define mfc_debug_L0(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__) +#else +#define mfc_debug(fmt, ...) +#define mfc_debug_L0(fmt, ...) +#endif + +#if defined(DEBUG_LEVEL_0) +#define mfc_debug_L0(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__) +#define mfc_debug(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__) +#elseif define(DEBUG_LEVEL_1) +#define mfc_debug(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__) +#endif + +#define mfc_err(fmt, ...) MFC_ERROR(fmt, ##__VA_ARGS__) +#define mfc_notice(fmt, ...) MFC_NOTICE(fmt, ##__VA_ARGS__) +#define mfc_info(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__) +#define mfc_warn(fmt, ...) MFC_WARN(fmt, ##__VA_ARGS__) + +#endif /* _MFC_LOGMSG_H_ */ diff --git a/drivers/media/video/samsung/mfc50/mfc_memory.c b/drivers/media/video/samsung/mfc50/mfc_memory.c new file mode 100644 index 0000000..a33dd9f --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_memory.c @@ -0,0 +1,70 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_memory.c + * + * C file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * + * 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/mm.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <mach/map.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <asm/sizes.h> +#include <linux/memory.h> +#include <plat/media.h> + +#include "mfc_memory.h" +#include "mfc_logmsg.h" +#include "mfc_interface.h" + +void __iomem *mfc_sfr_base_vaddr; +unsigned int mfc_port0_base_paddr, mfc_port1_base_paddr; +unsigned char *mfc_port0_base_vaddr, *mfc_port1_base_vaddr; +unsigned int mfc_port0_memsize, mfc_port1_memsize; +unsigned int mfc_port1_alloc_base; + +unsigned int mfc_get_fw_buff_paddr(void) +{ + return mfc_port0_base_paddr; +} + +unsigned char *mfc_get_fw_buff_vaddr(void) +{ + return mfc_port0_base_vaddr; +} + +unsigned int mfc_get_port0_buff_paddr(void) +{ + return mfc_port0_base_paddr + MFC_FW_MAX_SIZE; +} + +unsigned char *mfc_get_port0_buff_vaddr(void) +{ + return mfc_port0_base_vaddr + MFC_FW_MAX_SIZE; +} + +unsigned char *mfc_get_port1_buff_vaddr(void) +{ + return mfc_port1_base_vaddr; +} + +unsigned int mfc_get_port1_buff_paddr(void) +{ + return mfc_port1_alloc_base; +} + +void mfc_set_port1_buff_paddr(unsigned int addr) +{ + mfc_port1_alloc_base = addr; +} diff --git a/drivers/media/video/samsung/mfc50/mfc_memory.h b/drivers/media/video/samsung/mfc50/mfc_memory.h new file mode 100644 index 0000000..0d17a09 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_memory.h @@ -0,0 +1,111 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_memory.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * 2009.10.08 - Apply 9/30 firmware(Key Young, Park) + * 2009.11.04 - remove mfc_common.[ch] + * seperate buffer alloc & set (Key Young, Park) + * + * 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 _MFC_MEMORY_H_ +#define _MFC_MEMORY_H_ + +#include "mfc_opr.h" + +#ifdef CONFIG_VIDEO_MFC_MAX_INSTANCE +#define MFC_MAX_INSTANCE_NUM (CONFIG_VIDEO_MFC_MAX_INSTANCE) +#endif + +#define SET_MEM_1080P 1 +#define SET_MEM_720P 0 + +#if SET_MEM_1080P +/* + * Memory Configuration for 1080P + * MFC_FW_TOTAL_BUF_SIZE should be aligned to 4KB (page size) + */ +#define MFC_FW_TOTAL_BUF_SIZE (ALIGN_TO_4KB(MFC_FW_MAX_SIZE + MFC_MAX_INSTANCE_NUM * MFC_FW_BUF_SIZE)) +#define MFC_FW_MAX_SIZE (512 * 1024) /* 512KB : 512x1024 */ +#define MFC_FW_BUF_SIZE (512 * 1024) /* 512KB : 512x1024 size per instance */ + +#define RISC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */ +#define CPB_BUF_SIZE (0x300000) /* 3MB : 3x1024x1024 for decoder */ +#define DESC_BUF_SIZE (0x20000) /* 128KB : 128x1024 */ +#define SHARED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */ +#define PRED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */ +#define DEC_CODEC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */ +#define ENC_CODEC_BUF_SIZE (0x50000) /* 320KB : 512x1024 size per instance */ + +#define STREAM_BUF_SIZE (0x300000) /* 3MB : 3x1024x1024 for encoder */ +#define MV_BUF_SIZE (0x10000) /* 64KB : 64x1024 for encoder */ + +#define H264DEC_CONTEXT_SIZE (640 * 1024) /* 600KB -> 640KB for alignment */ +#define VC1DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define MPEG2DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define H263DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define MPEG4DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define H264ENC_CONTEXT_SIZE (640 * 1024) /* 64KB -> 640KB for alignment */ +#define MPEG4ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define H263ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ + +#else +/* Memory Configuration for 720P */ +#define MFC_FW_TOTAL_BUF_SIZE (ALIGN_TO_4KB(MFC_FW_MAX_SIZE + MFC_MAX_INSTANCE_NUM * MFC_FW_BUF_SIZE)) +#define MFC_FW_MAX_SIZE (2 * 1024 * 1024) /* 2MB : 2x1024x1024 */ +#define MFC_FW_BUF_SIZE (512 * 1024) /* 512KB : 512x1024 size per instance */ + +#define RISC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */ +#define CPB_BUF_SIZE (0x300000) /* 3MB : 3x1024x1024 for decoder */ +#define DESC_BUF_SIZE (0x20000) /* 128KB : 128x1024 */ +#define SHARED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */ +#define PRED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */ +#define DEC_CODEC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */ +#define ENC_CODEC_BUF_SIZE (0x50000) /* 320KB : 512x1024 size per instance */ + +#define STREAM_BUF_SIZE (0x200000) /* 2MB : 2x1024x1024 for encoder */ +#define MV_BUF_SIZE (0x10000) /* 64KB : 64x1024 for encoder */ + +#define H264DEC_CONTEXT_SIZE (640 * 1024) /* 600KB -> 640KB for alignment */ +#define VC1DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define MPEG2DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define H263DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define MPEG4DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define H264ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define MPEG4ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ +#define H263ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */ + +#endif + +unsigned int mfc_get_fw_buf_phys_addr(void); +unsigned int mfc_get_risc_buf_phys_addr(int instNo); + +extern unsigned char *mfc_port0_base_vaddr; /* port1 */ +extern unsigned char *mfc_port1_base_vaddr; /* port0 */ +extern unsigned int mfc_port0_base_paddr, mfc_port1_base_paddr; +extern unsigned int mfc_port0_memsize, mfc_port1_memsize; + +unsigned int mfc_get_fw_buff_paddr(void); +unsigned char *mfc_get_fw_buff_vaddr(void); +unsigned int mfc_get_port0_buff_paddr(void); +unsigned char *mfc_get_port0_buff_vaddr(void); +unsigned int mfc_get_port1_buff_paddr(void); +unsigned char *mfc_get_port1_buff_vaddr(void); +void mfc_set_port1_buff_paddr(unsigned int addr); + +extern void __iomem *mfc_sfr_base_vaddr; + +#define READL(offset) readl(mfc_sfr_base_vaddr + (offset)) +#define WRITEL(data, offset) writel((data), mfc_sfr_base_vaddr + (offset)) + +#endif /* _MFC_MEMORY_H_ */ diff --git a/drivers/media/video/samsung/mfc50/mfc_opr.c b/drivers/media/video/samsung/mfc50/mfc_opr.c new file mode 100644 index 0000000..39ca126 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_opr.c @@ -0,0 +1,2576 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_opr.c + * + * C file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code. (Key Young, Park) + * 2009.09.21 - Implement clock & power gating. + * including suspend & resume fuction. (Key Young, Park) + * 2009.09.23 - Use TILE mode encoding / Move MFC reserved memory + * before FIMC reserved memory. (Key Young, Park) + * 2009.09.24 - Minor patch. (Key Young, Park) + * 2009.10.08 - Apply 9/30 firmware(Key Young, Park) + * 2009.10.13 - Change wait_for_done (Key Young, Park) + * 2009.10.17 - Add error handling routine for buffer allocation (Key Young, Park) + * 2009.10.22 - Change codec name VC1AP_DEC -> VC1_DEC (Key Young, Park) + * 2009.10.27 - Update firmware (2009.10.15) (Key Young, Park) + * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park) + * 2009.11.04 - remove mfc_common.[ch] + * seperate buffer alloc & set (Key Young, Park) + * 2009.11.06 - Apply common MFC API (Key Young, Park) + * 2009.11.06 - memset shared_memory (Key Young, Park) + * 2009.11.09 - implement packed PB (Key Young, Park) + * + * 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/delay.h> +#include <linux/mm.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/dma-mapping.h> +#include <plat/regs-mfc.h> +#include <asm/cacheflush.h> +#include <mach/map.h> +#include <plat/map-s5p.h> + +#include "mfc_opr.h" +#include "mfc_logmsg.h" +#include "mfc_memory.h" +#include "mfc_buffer_manager.h" +#include "mfc_interface.h" +#include "mfc_shared_mem.h" +#include "mfc_intr.h" + + +/* DEBUG_MAKE_RAW is option to dump input stream data of MFC.*/ +#define DEBUG_MAKE_RAW 0 /* Making Dec/Enc Debugging Files */ +#define ENABLE_DEBUG_MFC_INIT 0 +#define ENABLE_MFC_REGISTER_DEBUG 0 /* 0: Disable 1: Enable */ +#define ENABLE_ENC_MB 1 + +#define ENABLE_CHECK_START_CODE 1 +#define ENABLE_CHECK_NULL_STREAM 1 +#define ENABLE_CHECK_STREAM_SIZE 1 +#define ENABLE_CHECK_SEQ_HEADER 0 + +#if DEBUG_MAKE_RAW +#define ENABLE_DEBUG_DEC_EXE_INTR_ERR 1 /* You must make the "dec_in" folder in data folder.*/ +#define ENABLE_DEBUG_DEC_EXE_INTR_OK 1 /* Make log about Normal Interrupts.*/ +#define ENABLE_DEBUG_ENC_EXE_INTR_ERR 1 /* You must make the "enc_in" folder in data folder.*/ +#endif + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_DEC_EXE_INTR_ERR +#define ENABLE_DEBUG_DEC_EXE_PARSER_ERR 1 /* Firstly, Set ENABLE_DEBUG_DEC_EXE_INTR_ERR is "1". */ +#endif +#endif + +#define WRITEL_SHARED_MEM(data, address) \ + do { \ + writel(data, address); \ + dmac_flush_range((void *)address, (void *)(address + 4)); \ + } while (0) + +#if DEBUG_MAKE_RAW +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/syscalls.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/fcntl.h> +#include <linux/uaccess.h> +#endif + + +static void mfc_backup_context(struct mfc_inst_ctx *mfc_ctx); +static void mfc_restore_context(struct mfc_inst_ctx *mfc_ctx); +static void mfc_set_encode_init_param(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +static int mfc_get_inst_no(struct mfc_inst_ctx *mfc_ctx, unsigned int context_addr, int context_size); +static enum mfc_error_code mfc_encode_header(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +static enum mfc_error_code mfc_decode_one_frame(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg, unsigned int *consumed_strm_size); + +static void mfc_set_codec_buffer(struct mfc_inst_ctx *mfc_ctx); +static void mfc_set_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx); +static void mfc_set_dec_stream_buffer(struct mfc_inst_ctx *mfc_ctx, int buf_addr, unsigned int buf_size); +static void mfc_set_enc_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); + +static enum mfc_error_code mfc_alloc_codec_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +static enum mfc_error_code mfc_alloc_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +static enum mfc_error_code mfc_alloc_context_buffer(struct mfc_inst_ctx *mfc_ctx, unsigned int mapped_addr, unsigned int *context_addr, int *size); +static enum mfc_error_code mfc_alloc_stream_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); + +static int CheckMPEG4StartCode(unsigned char *src_mem, unsigned int remainSize); +static int CheckDecStartCode(unsigned char *src_mem, unsigned int nstreamSize, enum ssbsip_mfc_codec_type nCodecType); +static int CheckNullStream(unsigned char *src_mem, unsigned int streamSize); + +static int mfc_mem_inst_no[MFC_MAX_INSTANCE_NUM]; +static bool mCheckType; + + +/* + * Debugging Functions Definition + * tile_to_linear_4x2(..) + * calculate_seq_size(..) + * printk_mfc_init_info(..) + */ +#if DEBUG_MAKE_RAW +static int mframe_cnt; +static int mImgWidth; +static int mImgHight; + +static void copy16(unsigned char *p_linear_addr, unsigned char *p_tiled_addr, int mm, int nn); +static void write_file(char *filename, unsigned char *data, unsigned int nSize); +static int tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos); +static void tile_to_linear_4x2(unsigned char *p_linear_addr, unsigned char *p_tiled_addr, unsigned int x_size, unsigned int y_size); +#endif + +#if ENABLE_CHECK_SEQ_HEADER +static int calculate_seq_size(mfc_args *args); +#endif + +#if ENABLE_DEBUG_MFC_INIT +void printk_mfc_init_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_args *args); +#endif + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_DEC_EXE_INTR_ERR +void printk_mfc_dec_exe_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg); +void makefile_mfc_dec_err_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg, int nReturnErrCode); +void makefile_mfc_decinit_err_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_init_arg *decinit_arg, int nReturnErrCode); + +static unsigned int mcontext_addr; +static int mcontext_size; +static int mIsDangerError; +#endif +#endif + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_ENC_EXE_INTR_ERR +void makefile_mfc_enc_err_info(struct mfc_enc_exe_arg *enc_arg); +#endif +#endif + +#if ENABLE_MFC_REGISTER_DEBUG +void mfc_fw_debug(mfc_wait_done_type command); +#endif + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_ENC_EXE_INTR_ERR +static unsigned char pResLinearbuf[1280*720*3/2]; +#endif +#endif + +#define MC_STATUS_TIMEOUT 1000 /* ms */ + +bool mfc_cmd_reset(void) +{ + unsigned int mc_status; + unsigned long timeo = jiffies; + + timeo += msecs_to_jiffies(MC_STATUS_TIMEOUT); + + /* Stop procedure */ + WRITEL(0x3f6, MFC_SW_RESET); /* reset RISC */ + WRITEL(0x3e2, MFC_SW_RESET); /* All reset except for MC */ + mdelay(10); + + /* Check MC status */ + do { + mc_status = (READL(MFC_MC_STATUS) & 0x3); + + if (mc_status == 0) + break; + + schedule_timeout_uninterruptible(1); + } while (time_before(jiffies, timeo)); + + if (mc_status != 0) + return false; + + WRITEL(0x0, MFC_SW_RESET); + WRITEL(0x3fe, MFC_SW_RESET); + + return true; +} + +static bool mfc_cmd_host2risc(enum mfc_facade_cmd cmd, int arg1, int arg2, int arg3, int arg4) +{ + enum mfc_facade_cmd cur_cmd = 0; + unsigned long timeo = jiffies; + timeo += 20; /* waiting for 100ms */ + + /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ + while (time_before(jiffies, timeo)) { + cur_cmd = READL(MFC_HOST2RISC_COMMAND); + if (cur_cmd == H2R_CMD_EMPTY) + break; + msleep_interruptible(2); + } + + if (cur_cmd != H2R_CMD_EMPTY) + return false; + + WRITEL(arg1, MFC_HOST2RISC_ARG1); + WRITEL(arg2, MFC_HOST2RISC_ARG2); + WRITEL(arg3, MFC_HOST2RISC_ARG3); + WRITEL(arg4, MFC_HOST2RISC_ARG4); + WRITEL(cmd, MFC_HOST2RISC_COMMAND); + + return true; +} + +static void mfc_backup_context(struct mfc_inst_ctx *mfc_ctx) +{ +} + +static void mfc_restore_context(struct mfc_inst_ctx *mfc_ctx) +{ +} + +static void mfc_set_dec_stream_buffer(struct mfc_inst_ctx *mfc_ctx, int buf_addr, unsigned int buf_size) +{ + unsigned int port0_base_paddr; + + mfc_debug_L0("inst_no : %d, buf_addr : 0x%08x, buf_size : 0x%08x\n", mfc_ctx->InstNo, buf_addr, buf_size); + if (mfc_ctx->buf_type == MFC_BUFFER_CACHE) { + unsigned char *in_vir; + in_vir = phys_to_virt(buf_addr); + dma_map_single(NULL, in_vir, buf_size, DMA_TO_DEVICE); + } + port0_base_paddr = mfc_port0_base_paddr; + + /* release buffer */ + WRITEL(0xffffffff, MFC_SI_CH0_RELEASE_BUFFER); + + /* Set stream & desc buffer */ + WRITEL((buf_addr - port0_base_paddr) >> 11, MFC_SI_CH0_ES_ADDR); + WRITEL(buf_size, MFC_SI_CH0_ES_DEC_UNIT_SIZE); + WRITEL(CPB_BUF_SIZE, MFC_SI_CH0_CPB_SIZE); + WRITEL((mfc_ctx->desc_buff_paddr - port0_base_paddr) >> 11, MFC_SI_CH0_DESC_ADDR); + WRITEL(DESC_BUF_SIZE, MFC_SI_CH0_DESC_SIZE); + + mfc_debug_L0("stream_paddr: 0x%08x, desc_paddr: 0x%08x\n", buf_addr, buf_addr + CPB_BUF_SIZE); +} + +static enum mfc_error_code mfc_alloc_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_dec_init_arg *init_arg; + enum mfc_error_code ret_code; + union mfc_args local_param; + struct mfc_frame_buf_arg buf_size; + unsigned int luma_size, chroma_size; + unsigned int luma_plane_sz, chroma_plane_sz, mv_plane_sz; + + init_arg = (struct mfc_dec_init_arg *)args; + + /* width : 128B align, height : 32B align, size: 8KB align */ + luma_plane_sz = ALIGN_TO_128B(init_arg->out_img_width) * ALIGN_TO_32B(init_arg->out_img_height); + luma_plane_sz = ALIGN_TO_8KB(luma_plane_sz); + chroma_plane_sz = ALIGN_TO_128B(init_arg->out_img_width) * ALIGN_TO_32B(init_arg->out_img_height / 2); + chroma_plane_sz = ALIGN_TO_8KB(chroma_plane_sz); + mv_plane_sz = 0; + + buf_size.luma = luma_plane_sz; + buf_size.chroma = chroma_plane_sz; + + if (mfc_ctx->MfcCodecType == H264_DEC) { + /* width : 128B align, height : 32B align, size: 8KB align */ + mv_plane_sz = ALIGN_TO_128B(init_arg->out_img_width) * ALIGN_TO_32B(init_arg->out_img_height / 4); + mv_plane_sz = ALIGN_TO_8KB(mv_plane_sz); + buf_size.luma += mv_plane_sz; + } + + mfc_ctx->shared_mem.allocated_luma_dpb_size = luma_plane_sz; + mfc_ctx->shared_mem.allocated_chroma_dpb_size = chroma_plane_sz; + mfc_ctx->shared_mem.allocated_mv_size = mv_plane_sz; + + luma_size = buf_size.luma * mfc_ctx->totalDPBCnt; + chroma_size = buf_size.chroma * mfc_ctx->totalDPBCnt; + + /* + * Allocate chroma & (Mv in case of H264) buf + */ + init_arg->out_frame_buf_size.chroma = chroma_size; + + memset(&local_param, 0, sizeof(local_param)); + local_param.mem_alloc.buff_size = chroma_size; + local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr; + + ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0); + if (ret_code < 0) + return ret_code; + + init_arg->out_u_addr.chroma = local_param.mem_alloc.out_uaddr; + init_arg->out_p_addr.chroma = local_param.mem_alloc.out_paddr; + + /* + * Allocate luma buf + */ + init_arg->out_frame_buf_size.luma = luma_size; + + memset(&local_param, 0, sizeof(local_param)); + local_param.mem_alloc.buff_size = luma_size; + local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr; + + ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 1); + if (ret_code < 0) + return ret_code; + + init_arg->out_u_addr.luma = local_param.mem_alloc.out_uaddr; + init_arg->out_p_addr.luma = local_param.mem_alloc.out_paddr; + + mfc_ctx->dec_dpb_buff_paddr = init_arg->out_p_addr; + + return MFCINST_RET_OK; +} + + + +static void mfc_set_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx) +{ + unsigned int port0_base_paddr, port1_base_paddr, i; + struct mfc_frame_buf_arg dpb_buff_addr; + unsigned int luma_plane_sz, chroma_plane_sz, mv_plane_sz; + + dpb_buff_addr = mfc_ctx->dec_dpb_buff_paddr; + port0_base_paddr = mfc_port0_base_paddr; + port1_base_paddr = mfc_port1_base_paddr; + + luma_plane_sz = mfc_ctx->shared_mem.allocated_luma_dpb_size; + chroma_plane_sz = mfc_ctx->shared_mem.allocated_chroma_dpb_size; + mv_plane_sz = mfc_ctx->shared_mem.allocated_mv_size; + + mfc_debug("luma_buf_addr start : 0x%08x luma_buf_size : %d\n", dpb_buff_addr.luma, (luma_plane_sz + mv_plane_sz)); + mfc_debug("chroma_buf_addr start : 0x%08x chroma_buf_size : %d\n", dpb_buff_addr.chroma, chroma_plane_sz); + + if (mfc_ctx->MfcCodecType == H264_DEC) { + for (i = 0; i < mfc_ctx->totalDPBCnt; i++) { + mfc_debug("DPB[%d] luma_buf_addr : 0x%08x luma_buf_size : %d\n", i, dpb_buff_addr.luma, luma_plane_sz); + mfc_debug("DPB[%d] chroma_buf_addr : 0x%08x chroma_buf_size : %d\n", i, dpb_buff_addr.chroma, chroma_plane_sz); + mfc_debug("DPB[%d] mv_buf_addr : 0x%08x mv_plane_sz : %d\n", i, dpb_buff_addr.luma + luma_plane_sz, mv_plane_sz); + + /* set Luma address */ + WRITEL((dpb_buff_addr.luma - port1_base_paddr) >> 11, MFC_H264DEC_LUMA + (4 * i)); + WRITEL((dpb_buff_addr.luma + luma_plane_sz - port1_base_paddr) >> 11, MFC_H264DEC_MV + (4 * i)); + dpb_buff_addr.luma += (luma_plane_sz + mv_plane_sz); + + /* set Chroma address & set MV address */ + WRITEL((dpb_buff_addr.chroma - port0_base_paddr) >> 11, MFC_H264DEC_CHROMA + (4 * i)); + dpb_buff_addr.chroma += chroma_plane_sz; + } + } else { + for (i = 0; i < mfc_ctx->totalDPBCnt; i++) { + mfc_debug("DPB[%d] luma_buf_addr : 0x%08x luma_buf_size : %d\n", i, dpb_buff_addr.luma, luma_plane_sz); + mfc_debug("DPB[%d] chroma_buf_addr : 0x%08x chroma_buf_size : %d\n", i, dpb_buff_addr.chroma, chroma_plane_sz); + + /* set Luma address */ + WRITEL((dpb_buff_addr.luma - port1_base_paddr) >> 11, MFC_DEC_LUMA + (4 * i)); + dpb_buff_addr.luma += luma_plane_sz; + + /* set Chroma address */ + WRITEL((dpb_buff_addr.chroma - port0_base_paddr) >> 11, MFC_DEC_CHROMA + (4 * i)); + dpb_buff_addr.chroma += chroma_plane_sz; + } + } + + mfc_debug("luma_buf_addr end : 0x%08x\n", dpb_buff_addr.luma); + mfc_debug("chroma_buf_addr end : 0x%08x\n", dpb_buff_addr.chroma); +} + +/* Allocate buffers for encoder */ +static enum mfc_error_code mfc_alloc_stream_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_enc_init_mpeg4_arg *init_arg; + union mfc_args local_param; + unsigned int luma_plane_sz, chroma_plane_sz; + enum mfc_error_code ret_code = MFCINST_RET_OK; + struct mfc_frame_buf_arg buf_size; + + init_arg = (struct mfc_enc_init_mpeg4_arg *)args; + + /* width : 128B align, height : 32B align, size: 8KB align */ + luma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height); + luma_plane_sz = ALIGN_TO_8KB(luma_plane_sz); + chroma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height / 2); + chroma_plane_sz = ALIGN_TO_8KB(chroma_plane_sz); + + buf_size.luma = luma_plane_sz; + buf_size.chroma = chroma_plane_sz; + + /* + * Allocate stream ref Y0, Y1 buf + */ + init_arg->out_buf_size.strm_ref_y = STREAM_BUF_SIZE + (buf_size.luma * 2); + + memset(&local_param, 0, sizeof(local_param)); + local_param.mem_alloc.buff_size = init_arg->out_buf_size.strm_ref_y; + local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr; + + ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0); + if (ret_code < 0) + return ret_code; + + init_arg->out_u_addr.strm_ref_y = local_param.mem_alloc.out_uaddr; + init_arg->out_p_addr.strm_ref_y = local_param.mem_alloc.out_paddr; + + /* + * Allocate ref C0, C1, Y2, C2, Y3, C3 buf XXX : remove MV buffer + */ + init_arg->out_buf_size.mv_ref_yc = (buf_size.luma * 2) + (buf_size.chroma * 4); + + memset(&local_param, 0, sizeof(local_param)); + local_param.mem_alloc.buff_size = init_arg->out_buf_size.mv_ref_yc; + local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr; + + ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 1); + if (ret_code < 0) + return ret_code; + + init_arg->out_u_addr.mv_ref_yc = local_param.mem_alloc.out_uaddr; + init_arg->out_p_addr.mv_ref_yc = local_param.mem_alloc.out_paddr; + + return ret_code; +} + +static void mfc_set_enc_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + unsigned int port0_base_paddr, port1_base_paddr, i; + struct mfc_strm_ref_buf_arg ref_buf_addr; + unsigned int luma_plane_sz, chroma_plane_sz; + struct mfc_enc_init_mpeg4_arg *init_arg; + + init_arg = (struct mfc_enc_init_mpeg4_arg *)args; + + /* width : 128B align, height : 32B align, size: 8KB align */ + luma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height); + luma_plane_sz = ALIGN_TO_8KB(luma_plane_sz); + chroma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height / 2); + chroma_plane_sz = ALIGN_TO_8KB(chroma_plane_sz); + + ref_buf_addr = init_arg->out_p_addr; + mfc_debug("strm_ref_y_buf_addr : 0x%08x, strm_ref_y_buf_size : %d\n", + ref_buf_addr.strm_ref_y, init_arg->out_buf_size.strm_ref_y); + mfc_debug("mv_ref_yc_buf_addr : 0x%08x, mv_ref_yc_buf_size : %d\n", + ref_buf_addr.mv_ref_yc, init_arg->out_buf_size.mv_ref_yc); + + port0_base_paddr = mfc_port0_base_paddr; + port1_base_paddr = mfc_port1_base_paddr; + + mfc_debug("stream_buf_addr : 0x%08x\n", ref_buf_addr.strm_ref_y); + ref_buf_addr.strm_ref_y += STREAM_BUF_SIZE; + + /* Set Y0, Y1 ref buffer address */ + mfc_debug("REF[0] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.strm_ref_y, luma_plane_sz); + WRITEL((ref_buf_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_ENC_DPB_Y0_ADDR); + ref_buf_addr.strm_ref_y += luma_plane_sz; + mfc_debug("REF[1] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.strm_ref_y, luma_plane_sz); + WRITEL((ref_buf_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_ENC_DPB_Y1_ADDR); + + /* Set Y2, Y3 ref buffer address */ + mfc_debug("REF[2] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.mv_ref_yc, luma_plane_sz); + WRITEL((ref_buf_addr.mv_ref_yc - port1_base_paddr) >> 11, MFC_ENC_DPB_Y2_ADDR); + ref_buf_addr.mv_ref_yc += luma_plane_sz; + mfc_debug("REF[3] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.mv_ref_yc, luma_plane_sz); + WRITEL((ref_buf_addr.mv_ref_yc - port1_base_paddr) >> 11, MFC_ENC_DPB_Y3_ADDR); + ref_buf_addr.mv_ref_yc += luma_plane_sz; + + /* Set C0, C1, C2, C3 ref buffer address */ + for (i = 0; i < 4; i++) { + mfc_debug("REF[%d] chroma_buf_addr : 0x%08x chroma_buf_size : %d\n", i, ref_buf_addr.mv_ref_yc, chroma_plane_sz); + WRITEL((ref_buf_addr.mv_ref_yc - port1_base_paddr) >> 11, MFC_ENC_DPB_C0_ADDR + (4 * i)); + ref_buf_addr.mv_ref_yc += chroma_plane_sz; + } +} + +static enum mfc_error_code mfc_alloc_codec_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_dec_init_arg *init_arg; + enum mfc_error_code ret_code; + union mfc_args local_param; + + init_arg = (struct mfc_dec_init_arg *)args; + + memset(&local_param, 0, sizeof(local_param)); + if (is_dec_codec(mfc_ctx->MfcCodecType)) + local_param.mem_alloc.buff_size = DEC_CODEC_BUF_SIZE + SHARED_BUF_SIZE; + else + local_param.mem_alloc.buff_size = ENC_CODEC_BUF_SIZE + SHARED_BUF_SIZE; + + local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr; + ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0); + if (ret_code < 0) + return ret_code; + + mfc_ctx->codec_buff_paddr = local_param.mem_alloc.out_paddr; + if (is_dec_codec(mfc_ctx->MfcCodecType)) + mfc_ctx->shared_mem_paddr = mfc_ctx->codec_buff_paddr + DEC_CODEC_BUF_SIZE; + else + mfc_ctx->shared_mem_paddr = mfc_ctx->codec_buff_paddr + ENC_CODEC_BUF_SIZE; + + mfc_ctx->shared_mem_vaddr = (unsigned int)mfc_get_fw_buff_vaddr() + (mfc_ctx->shared_mem_paddr - mfc_port0_base_paddr); + memset((void *)mfc_ctx->shared_mem_vaddr, 0x0, SHARED_MEM_MAX); + + if (mfc_ctx->MfcCodecType == H264_ENC) { + memset(&local_param, 0, sizeof(local_param)); + local_param.mem_alloc.buff_size = PRED_BUF_SIZE; + local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr; + ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 1); + if (ret_code < 0) + return ret_code; + + mfc_ctx->pred_buff_paddr = local_param.mem_alloc.out_paddr; + } + + return MFCINST_RET_OK; +} + + + +static void mfc_set_codec_buffer(struct mfc_inst_ctx *mfc_ctx) +{ + unsigned int codec_buff_paddr; + unsigned int pred_buff_paddr; + unsigned int port0_base_paddr; + unsigned int port1_base_paddr; + + port0_base_paddr = mfc_port0_base_paddr; + port1_base_paddr = mfc_port1_base_paddr; + codec_buff_paddr = mfc_ctx->codec_buff_paddr; + pred_buff_paddr = mfc_ctx->pred_buff_paddr; + + mfc_debug("inst_no : %d, codec_buf_start: 0x%08x\n", mfc_ctx->InstNo, codec_buff_paddr); + + switch (mfc_ctx->MfcCodecType) { + case H264_DEC: + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_H264DEC_VERT_NB_MV); + codec_buff_paddr += (16 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_H264DEC_NB_IP); + codec_buff_paddr += (32 << 10); + break; + + case MPEG4_DEC: + case H263_DEC: + case XVID_DEC: + case FIMV1_DEC: + case FIMV2_DEC: + case FIMV3_DEC: + case FIMV4_DEC: + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_NB_DCAC); + codec_buff_paddr += (16 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPNB_MV); + codec_buff_paddr += (68 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_SUB_ANCHOR_MV); + codec_buff_paddr += (136 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_OVERLAP_TRANSFORM); + codec_buff_paddr += (32 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_STX_PARSER); + codec_buff_paddr += (68 << 10); + break; + + case VC1_DEC: + case VC1RCV_DEC: + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_NB_DCAC); + codec_buff_paddr += (16 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPNB_MV); + codec_buff_paddr += (68 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_SUB_ANCHOR_MV); + codec_buff_paddr += (136 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_OVERLAP_TRANSFORM); + codec_buff_paddr += (32 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_BITPLANE3); + codec_buff_paddr += (8 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_BITPLANE2); + codec_buff_paddr += (8 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_BITPLANE1); + codec_buff_paddr += (8 << 10); + break; + + case MPEG1_DEC: + case MPEG2_DEC: + break; + + case H264_ENC: + case MPEG4_ENC: + case H263_ENC: + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPPER_MV_ADDR); + codec_buff_paddr += (64 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_DIRECT_COLZERO_FLAG_ADDR); + codec_buff_paddr += (64 << 10); + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPPER_INTRA_MD_ADDR); + codec_buff_paddr += (64 << 10); + if (mfc_ctx->MfcCodecType == H264_ENC) { + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_NBOR_INFO_MPENC_ADDR); + WRITEL((pred_buff_paddr - port1_base_paddr) >> 11, MFC_UPPER_INTRA_PRED_ADDR); + } else { + WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_ACDC_COEF_BASE_ADDR); + } + codec_buff_paddr += (64 << 10); + break; + + default: + break; + } + + mfc_debug("inst_no : %d, codec_buf_end : 0x%08x\n", mfc_ctx->InstNo, codec_buff_paddr); +} + +/* This function sets the MFC SFR values according to the input arguments. */ +static void mfc_set_encode_init_param(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + unsigned int ms_size; + struct mfc_enc_init_mpeg4_arg *enc_init_mpeg4_arg; + struct mfc_enc_init_h264_arg *enc_init_h264_arg; + + enc_init_mpeg4_arg = (struct mfc_enc_init_mpeg4_arg *)args; + enc_init_h264_arg = (struct mfc_enc_init_h264_arg *)args; + +#if DEBUG_MAKE_RAW + mImgHight = enc_init_mpeg4_arg->in_height; + mImgWidth = enc_init_mpeg4_arg->in_width; +#endif + + mfc_debug("mfc_codec_type : %d\n", mfc_ctx->MfcCodecType); + + WRITEL(enc_init_mpeg4_arg->in_width, MFC_HSIZE_PX); + if (enc_init_mpeg4_arg->in_interlace_mode) + WRITEL(enc_init_mpeg4_arg->in_height >> 1, MFC_VSIZE_PX); + else + WRITEL(enc_init_mpeg4_arg->in_height, MFC_VSIZE_PX); + + /* H.263 does not support field picture */ + WRITEL(enc_init_mpeg4_arg->in_interlace_mode, MFC_PICTURE_STRUCT); + WRITEL(0, MFC_ENC_INT_MASK); /* mask interrupt */ + WRITEL(1, MFC_STR_BF_MODE_CTRL); /* stream buf frame mode */ + WRITEL((1 << 18) | (enc_init_mpeg4_arg->in_BframeNum << 16) | + enc_init_mpeg4_arg->in_gop_num, MFC_ENC_PIC_TYPE_CTRL); + + /* Multi-slice options */ + if (enc_init_mpeg4_arg->in_MS_mode) { + ms_size = (mfc_ctx->MfcCodecType == H263_ENC) ? 0 : enc_init_mpeg4_arg->in_MS_size; + switch (enc_init_mpeg4_arg->in_MS_mode) { + case 1: + WRITEL(0x1, MFC_ENC_MSLICE_CTRL); + WRITEL(ms_size, MFC_ENC_MSLICE_MB); + break; + + case 2: + WRITEL(0x3, MFC_ENC_MSLICE_CTRL); + WRITEL(ms_size, MFC_ENC_MSLICE_BYTE); + break; + + default: + mfc_err("Invalid Multi-slice mode type\n"); + break; + } + } else { + WRITEL(0, MFC_ENC_MSLICE_CTRL); + } + + /* Set circular intra refresh MB count */ + WRITEL(enc_init_mpeg4_arg->in_mb_refresh, MFC_ENC_CIR_CTRL); + + if (enc_init_mpeg4_arg->in_frame_map == 1) + WRITEL(MEM_STRUCT_TILE_ENC, MFC_ENC_MAP_FOR_CUR); + else + WRITEL(MEM_STRUCT_LINEAR, MFC_ENC_MAP_FOR_CUR); + + /* Set padding control */ + WRITEL((enc_init_mpeg4_arg->in_pad_ctrl_on << 31) | + (enc_init_mpeg4_arg->in_cr_pad_val << 16) | + (enc_init_mpeg4_arg->in_cb_pad_val << 8) | + (enc_init_mpeg4_arg->in_luma_pad_val << 0), MFC_ENC_PADDING_CTRL); + + /* Set Rate Control */ + if (enc_init_mpeg4_arg->in_RC_frm_enable) { + WRITEL(enc_init_mpeg4_arg->in_RC_framerate, MFC_RC_FRAME_RATE); + WRITEL(enc_init_mpeg4_arg->in_RC_bitrate, MFC_RC_BIT_RATE); + WRITEL(enc_init_mpeg4_arg->in_RC_rpara, MFC_RC_RPARA); + } + + WRITEL(enc_init_mpeg4_arg->in_RC_qbound, MFC_RC_QBOUND); + + switch (mfc_ctx->MfcCodecType) { + case H264_ENC: + WRITEL(enc_init_h264_arg->in_profile_level, MFC_PROFILE); + WRITEL(enc_init_h264_arg->in_transform8x8_mode, MFC_H264_ENC_TRANS_8X8_FLAG); + WRITEL(enc_init_h264_arg->in_deblock_filt, MFC_LF_CONTROL); + WRITEL(((enc_init_h264_arg->in_deblock_alpha_C0 * 2) & 0x1f), MFC_LF_ALPHA_OFF); + WRITEL(((enc_init_h264_arg->in_deblock_beta * 2) & 0x1f), MFC_LF_BETA_OFF); + WRITEL(1, MFC_EDFU_SF_EPB_ON_CTRL); /* Auto EPB insertion on, only for h264 */ + + /* if in_RC_mb_enable is '1' */ +#if ENABLE_ENC_MB + if (enc_init_h264_arg->in_RC_frm_enable != 1) + enc_init_h264_arg->in_RC_frm_enable = 1; + if (enc_init_h264_arg->in_RC_mb_enable != 1) + enc_init_h264_arg->in_RC_mb_enable = 1; +#endif + + WRITEL((enc_init_h264_arg->in_RC_frm_enable << 9) | + (enc_init_h264_arg->in_RC_mb_enable << 8) | + (enc_init_h264_arg->in_frame_qp & 0x3f), + MFC_RC_CONFIG); + + if (enc_init_h264_arg->in_RC_mb_enable) { + WRITEL((enc_init_h264_arg->in_RC_mb_dark_disable << 3)| + (enc_init_h264_arg->in_RC_mb_smooth_disable << 2)| + (enc_init_h264_arg->in_RC_mb_static_disable << 1)| + (enc_init_h264_arg->in_RC_mb_activity_disable << 0), + MFC_RC_MB_CTRL); + } + + WRITEL((enc_init_h264_arg->in_symbolmode & 0x1), MFC_H264_ENC_ENTRP_MODE); + + if (enc_init_h264_arg->in_reference_num > 2) + enc_init_h264_arg->in_reference_num = 2; + if (enc_init_h264_arg->in_ref_num_p > enc_init_h264_arg->in_reference_num) + enc_init_h264_arg->in_ref_num_p = enc_init_h264_arg->in_reference_num; + WRITEL((enc_init_h264_arg->in_ref_num_p << 5) | + (enc_init_h264_arg->in_reference_num), + MFC_H264_ENC_NUM_OF_REF); + + WRITEL(enc_init_h264_arg->in_md_interweight_pps, MFC_H264_ENC_MDINTER_WEIGHT); + WRITEL(enc_init_h264_arg->in_md_intraweight_pps, MFC_H264_ENC_MDINTRA_WEIGHT); + break; + + case MPEG4_ENC: + WRITEL(enc_init_mpeg4_arg->in_profile_level, MFC_PROFILE); + WRITEL((enc_init_mpeg4_arg->in_RC_frm_enable << 9) | + (enc_init_mpeg4_arg->in_frame_qp & 0x3f), + MFC_RC_CONFIG); + WRITEL(enc_init_mpeg4_arg->in_qpelME_enable, MFC_MPEG4_ENC_QUART_PXL); + if (enc_init_mpeg4_arg->in_time_increament_res) { + mfc_ctx->shared_mem.vop_timing = (1 << 31) | + (enc_init_mpeg4_arg->in_time_increament_res << 16) | + (enc_init_mpeg4_arg->in_time_vop_time_increament); + } + break; + + case H263_ENC: + WRITEL(0x20, MFC_PROFILE); + WRITEL((enc_init_mpeg4_arg->in_RC_frm_enable << 9) | + (enc_init_mpeg4_arg->in_frame_qp & 0x3f), + MFC_RC_CONFIG); + break; + + default: + mfc_err("Invalid MFC codec type\n"); + } +} + +int mfc_load_firmware(const unsigned char *data, size_t size) +{ + volatile unsigned char *fw_virbuf; + + mfc_debug("mfc_load_firmware : MFC F/W Loading Start.................\n"); + + fw_virbuf = mfc_get_fw_buff_vaddr(); + memset((void *)fw_virbuf, 0, MFC_FW_MAX_SIZE); + + invalidate_kernel_vmap_range((void *)data, size); + memcpy((void *)fw_virbuf, data, size); + flush_kernel_vmap_range((void *)fw_virbuf, size); + + mfc_debug("mfc_load_firmware : MFC F/W Loading Stop.................(fw_virbuf: 0x%08x)\n", fw_virbuf); + + return 0; +} + +enum mfc_error_code mfc_init_hw() +{ + int fw_buf_size; + unsigned int fw_version; + unsigned int mc_status; + unsigned long idcode; + int nIntrRet = 0; + + mfc_debug("mfc_init_hw++\n"); + + /* + * 0-1. Check Type + */ + idcode = readl(S5P_VA_CHIPID); + if ((idcode & 0x0F) == 0x02) + mCheckType = false; + else + mCheckType = true; + + /* + * 1. MFC reset + */ + do { + mc_status = READL(MFC_MC_STATUS); + } while (mc_status != 0); + + if (mfc_cmd_reset() == false) { + mfc_err("MFCINST_ERR_INIT_FAIL\n"); + return MFCINST_ERR_INIT_FAIL; + } + + /* + * 2. Set DRAM base Addr + */ + WRITEL(mfc_port0_base_paddr, MFC_MC_DRAMBASE_ADDR_A); + WRITEL(mfc_port1_base_paddr, MFC_MC_DRAMBASE_ADDR_B); + WRITEL(1, MFC_NUM_MASTER); + + /* + * 3. Initialize registers of stream I/F for decoder + */ + WRITEL(0xffff, MFC_SI_CH0_INST_ID); + WRITEL(0xffff, MFC_SI_CH1_INST_ID); + + WRITEL(0, MFC_RISC2HOST_COMMAND); + WRITEL(0, MFC_HOST2RISC_COMMAND); + + /* + * 4. Release reset signal to the RISC. + */ + WRITEL(0x3ff, MFC_SW_RESET); + nIntrRet = mfc_wait_for_done(R2H_CMD_FW_STATUS_RET); + if (nIntrRet != R2H_CMD_FW_STATUS_RET) { + /* + * 4-1. MFC FW downloading + */ + + mfc_err("MFCINST_ERR_FW_LOAD_MFC_SW_RESET_FAIL............(Ret = %d)", nIntrRet); + + + mfc_err("MFCINST_ERR_FW_LOAD_FAIL\n"); + return MFCINST_ERR_FW_LOAD_FAIL; + } + + /* + * 5. Initialize firmware + */ + fw_buf_size = MFC_FW_MAX_SIZE; + if (mfc_cmd_host2risc(H2R_CMD_SYS_INIT, fw_buf_size, 0, 0, 0) == false) { + mfc_err("R2H_CMD_SYS_INIT FAIL\n"); + return MFCINST_ERR_FW_INIT_FAIL; + } + + if (mfc_wait_for_done(R2H_CMD_SYS_INIT_RET) != R2H_CMD_SYS_INIT_RET) { + mfc_err("R2H_CMD_SYS_INIT_RET FAIL\n"); + return MFCINST_ERR_FW_INIT_FAIL; + } + + fw_version = READL(MFC_FW_VERSION); + + + mfc_debug("MFC FW version : %02xyy, %02xmm, %02xdd\n", + (fw_version >> 16) & 0xff, (fw_version >> 8) & 0xff, fw_version & 0xff); + + mfc_debug("DRAM PORT0 BASE ADDRESS: 0x%08x\n", READL(MFC_MC_DRAMBASE_ADDR_A)); + mfc_debug("DRAM PORT1 BASE ADDRESS: 0x%08x\n", READL(MFC_MC_DRAMBASE_ADDR_B)); + mfc_debug("mfc_init_hw-\n"); + + return MFCINST_RET_OK; +} + +static unsigned int mfc_get_codec_arg(enum ssbsip_mfc_codec_type codec_type) +{ + unsigned int codec_no = 99; + + switch (codec_type) { + case H264_DEC: + codec_no = 0; + break; + + case VC1_DEC: + codec_no = 1; + break; + + case MPEG4_DEC: + case XVID_DEC: + codec_no = 2; + break; + + case MPEG1_DEC: + case MPEG2_DEC: + codec_no = 3; + break; + + case H263_DEC: + codec_no = 4; + break; + + case VC1RCV_DEC: + codec_no = 5; + break; + + case FIMV1_DEC: + codec_no = 6; + break; + + case FIMV2_DEC: + codec_no = 7; + break; + + case FIMV3_DEC: + codec_no = 8; + break; + + case FIMV4_DEC: + codec_no = 9; + break; + + case H264_ENC: + codec_no = 16; + break; + + case MPEG4_ENC: + codec_no = 17; + break; + + case H263_ENC: + codec_no = 18; + break; + + default: + break; + } + + return codec_no; +} + +static int mfc_get_inst_no(struct mfc_inst_ctx *mfc_ctx, unsigned int context_addr, int context_size) +{ + unsigned int codec_no; + int inst_no; + unsigned int port0_base_paddr; + int mfc_wait_ret = 0; + port0_base_paddr = mfc_port0_base_paddr; + + codec_no = (unsigned int)mfc_get_codec_arg(mfc_ctx->MfcCodecType); + + if (mfc_cmd_host2risc(H2R_CMD_OPEN_INSTANCE, + codec_no, + (mfc_ctx->crcEnable << 31) | PIXEL_CACHE_ON_ONLY_P_PICTURE, + (context_addr - port0_base_paddr) >> 11, + context_size) == false) { + mfc_err("R2H_CMD_OPEN_INSTANCE FAIL\n"); + return MFCINST_ERR_OPEN_FAIL; + } + + mfc_wait_ret = mfc_wait_for_done(R2H_CMD_OPEN_INSTANCE_RET); + if (mfc_wait_ret != R2H_CMD_OPEN_INSTANCE_RET) { + mfc_err("R2H_CMD_OPEN_INSTANCE_RET FAIL..........(ret:%d)\n", mfc_wait_ret); + return MFCINST_ERR_OPEN_FAIL; + } + + inst_no = READL(MFC_RISC2HOST_ARG1); + if (inst_no >= MFC_MAX_INSTANCE_NUM) { + mfc_err("mfc_get_inst_no() - INSTANCE NO : %d, CODEC_TYPE : %d --\n", inst_no, codec_no); + return -1; + } else { + mfc_debug("mfc_get_inst_no() - INSTANCE NO : %d, CODEC_TYPE : %d --\n", inst_no, codec_no); + return inst_no; + } +} + +int mfc_return_inst_no(int inst_no, enum ssbsip_mfc_codec_type codec_type) +{ + unsigned int codec_no; + int mfc_wait_ret = 0; + + codec_no = (unsigned int)mfc_get_codec_arg(codec_type); + + if (mfc_cmd_host2risc(H2R_CMD_CLOSE_INSTANCE, inst_no, 0, 0, 0) == false) { + mfc_err("R2H_CMD_CLOSE_INSTANCE FAIL\n"); + return MFCINST_ERR_CLOSE_FAIL; + } + + mfc_wait_ret = mfc_wait_for_done(R2H_CMD_CLOSE_INSTANCE_RET); + if (mfc_wait_ret != R2H_CMD_CLOSE_INSTANCE_RET) { + mfc_err("R2H_CMD_CLOSE_INSTANCE_RET FAIL\n"); + return MFCINST_ERR_CLOSE_FAIL; + } + + mfc_debug("mfc_return_inst_no() - INSTANCE NO : %d, CODEC_TYPE : %d --\n", READL(MFC_RISC2HOST_ARG1), codec_no); + return MFCINST_RET_OK; +} + +enum mfc_error_code mfc_init_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_enc_init_mpeg4_arg *enc_init_mpeg4_arg; + enum mfc_error_code ret_code; + unsigned int context_addr; + int context_size; + int frame_P_qp, frame_B_qp; + int nSize = 0; + + enc_init_mpeg4_arg = (struct mfc_enc_init_mpeg4_arg *)args; + + mfc_debug("++\n"); + mfc_ctx->MfcCodecType = enc_init_mpeg4_arg->in_codec_type; + mfc_ctx->img_width = (unsigned int)enc_init_mpeg4_arg->in_width; + mfc_ctx->img_height = (unsigned int)enc_init_mpeg4_arg->in_height; + mfc_ctx->interlace_mode = enc_init_mpeg4_arg->in_interlace_mode; + + + /* + * Set Available Type + */ + if (mCheckType == false) { + nSize = mfc_ctx->img_width * mfc_ctx->img_height; + mfc_ctx->shared_mem.p720_limit_enable = 49425; + if (nSize > BOUND_MEMORY_SIZE) + return MFCINST_ERR_FRM_BUF_SIZE; + } else { + mfc_ctx->shared_mem.p720_limit_enable = 49424; + } + + + + + /* OPEN CHANNEL + * - set open instance using codec_type + * - get the instance no + */ + ret_code = mfc_alloc_context_buffer(mfc_ctx, enc_init_mpeg4_arg->in_mapped_addr, &context_addr, &context_size); + if (ret_code != MFCINST_RET_OK) + return ret_code; + + mfc_ctx->InstNo = mfc_get_inst_no(mfc_ctx, context_addr, context_size); + if (mfc_ctx->InstNo < 0) { + mfc_err("MFCINST_INST_NUM_EXCEEDED\n"); + return MFCINST_INST_NUM_EXCEEDED; + } + + /* INIT CODEC + * - set init parameter + * - set init sequence done command + * - set codec buffer + * - set input risc buffer + */ + + mfc_set_encode_init_param(mfc_ctx, args); + + ret_code = mfc_alloc_codec_buffer(mfc_ctx, args); + if (ret_code != MFCINST_RET_OK) { + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return ret_code; + } + + mfc_set_codec_buffer(mfc_ctx); + + /* Set Ref YC0~3 & MV */ + ret_code = mfc_alloc_stream_ref_buffer(mfc_ctx, args); + if (ret_code != MFCINST_RET_OK) { + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return ret_code; + } + + mfc_set_enc_ref_buffer(mfc_ctx, args); + + if (enc_init_mpeg4_arg->in_frame_P_qp) + frame_P_qp = enc_init_mpeg4_arg->in_frame_P_qp; + else + frame_P_qp = enc_init_mpeg4_arg->in_frame_qp; + + if (enc_init_mpeg4_arg->in_frame_B_qp) + frame_B_qp = enc_init_mpeg4_arg->in_frame_B_qp; + else + frame_B_qp = enc_init_mpeg4_arg->in_frame_qp; + mfc_ctx->shared_mem.P_B_frame_qp = (frame_B_qp << 6 | frame_P_qp); + + if (enc_init_mpeg4_arg->in_RC_frm_enable) + mfc_ctx->shared_mem.vop_timing = ((1 << 31) | (enc_init_mpeg4_arg->in_RC_framerate << 16) | 1); + + + mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + + ret_code = mfc_encode_header(mfc_ctx, args); + + mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + + mfc_backup_context(mfc_ctx); + + mfc_debug_L0("--\n"); + + return ret_code; +} + +static enum mfc_error_code mfc_encode_header(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_enc_init_mpeg4_arg *init_arg; + unsigned int port0_base_paddr; + int nIntrRet = 0; + int nReturnErrCode = 0; + + init_arg = (struct mfc_enc_init_mpeg4_arg *)args; + + mfc_debug("++ enc_arg->in_strm_st : 0x%08x\n", init_arg->out_p_addr.strm_ref_y); + + port0_base_paddr = mfc_port0_base_paddr; + + /* Set share memory */ + WRITEL((mfc_ctx->shared_mem_paddr - port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR); + + /* Set stream buffer addr */ + WRITEL((init_arg->out_p_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_SI_CH0_SB_U_ADDR); + WRITEL((init_arg->out_p_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_SI_CH0_SB_L_ADDR); + WRITEL(STREAM_BUF_SIZE, MFC_SI_CH0_BUFFER_SIZE); + + WRITEL(1, MFC_STR_BF_U_EMPTY); + WRITEL(1, MFC_STR_BF_L_EMPTY); + + /* buf reset command if stream buffer is frame mode */ + WRITEL(0x1 << 1, MFC_EDFU_SF_BUF_CTRL); + + WRITEL((SEQ_HEADER << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID); + nIntrRet = mfc_wait_for_done(R2H_CMD_SEQ_DONE_RET); + nReturnErrCode = mfc_return_code(); + if (nIntrRet == 0) { + mfc_err("MFCINST_ERR_ENC_EXE_TIME_OUT\n"); + return MFCINST_ERR_INTR_TIME_OUT; + } else if ((nIntrRet != R2H_CMD_SEQ_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) { + mfc_err("MFCINST_ERR_ENC_SEQ_HEADER_FAIL ....Intr Code (%d)\n", nIntrRet); + return MFCINST_ERR_ENC_HEADER_DECODE_FAIL; + } else if (nIntrRet != R2H_CMD_SEQ_DONE_RET) { + mfc_warn("MFCINST_WARN_ENC_SEQ_HEADER.........(code: %d)\n", nIntrRet); + } + + + init_arg->out_header_size = READL(MFC_SI_ENC_STREAM_SIZE); + + if (mfc_ctx->buf_type == MFC_BUFFER_CACHE) { + dma_unmap_single(NULL, init_arg->out_p_addr.strm_ref_y, + init_arg->out_header_size, DMA_FROM_DEVICE); + } + mfc_debug("encoded header size (%d)\n", init_arg->out_header_size); + + return MFCINST_RET_OK; +} + +static enum mfc_error_code mfc_encode_one_frame(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_enc_exe_arg *enc_arg; + unsigned int port0_base_paddr, port1_base_paddr; + int interrupt_flag; + int nReturnErrCode; + + + enc_arg = (struct mfc_enc_exe_arg *)args; + + mfc_debug("++ enc_arg->in_strm_st : 0x%08x enc_arg->in_strm_end :0x%08x \r\n", + enc_arg->in_strm_st, enc_arg->in_strm_end); + mfc_debug("enc_arg->in_Y_addr : 0x%08x enc_arg->in_CbCr_addr :0x%08x \r\n", + enc_arg->in_Y_addr, enc_arg->in_CbCr_addr); + + mfc_restore_context(mfc_ctx); + + port0_base_paddr = mfc_port0_base_paddr; + port1_base_paddr = mfc_port1_base_paddr; + +#ifdef ENABLE_DEBUG_ENC_EXE_INTR_ERR +#if ENABLE_DEBUG_ENC_EXE_INTR_ERR + makefile_mfc_enc_err_info(enc_arg); +#endif +#endif + + /* Set share memory */ + WRITEL((mfc_ctx->shared_mem_paddr - port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR); + + /* Set stream buffer addr */ + WRITEL((enc_arg->in_strm_st - port0_base_paddr) >> 11, MFC_SI_CH0_SB_U_ADDR); + WRITEL((enc_arg->in_strm_st - port0_base_paddr) >> 11, MFC_SI_CH0_SB_L_ADDR); + WRITEL(STREAM_BUF_SIZE, MFC_SI_CH0_BUFFER_SIZE); + + /* Set current frame buffer addr */ + WRITEL((enc_arg->in_Y_addr - port1_base_paddr) >> 11, MFC_SI_CH0_CURRENT_Y_ADDR); + WRITEL((enc_arg->in_CbCr_addr - port1_base_paddr) >> 11, MFC_SI_CH0_CURRENT_C_ADDR); + + WRITEL(1, MFC_STR_BF_U_EMPTY); + WRITEL(1, MFC_STR_BF_L_EMPTY); + + /* buf reset command if stream buffer is frame mode */ + WRITEL(0x1 << 1, MFC_EDFU_SF_BUF_CTRL); + + if (mfc_ctx->forceSetFrameType == NOT_CODED) + WRITEL((0x1 << 1), MFC_SI_CH0_ENC_PARA); + else if (mfc_ctx->forceSetFrameType == I_FRAME) + WRITEL(0x1, MFC_SI_CH0_ENC_PARA); + + mfc_ctx->forceSetFrameType = DONT_CARE; + + if (mfc_ctx->buf_type == MFC_BUFFER_CACHE) { + unsigned char *in_vir; + unsigned int aligned_width; + unsigned int aligned_height; + + in_vir = phys_to_virt(enc_arg->in_Y_addr); + aligned_width = ALIGN_TO_128B(mfc_ctx->img_width); + aligned_height = ALIGN_TO_32B(mfc_ctx->img_height); + dma_map_single(NULL, in_vir, aligned_width*aligned_height, + DMA_TO_DEVICE); + + in_vir = phys_to_virt(enc_arg->in_CbCr_addr); + aligned_height = ALIGN_TO_32B(mfc_ctx->img_height/2); + dma_map_single(NULL, in_vir, aligned_width*aligned_height, + DMA_TO_DEVICE); + } + + /* Try frame encoding */ + WRITEL((FRAME << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID); + interrupt_flag = mfc_wait_for_done(R2H_CMD_FRAME_DONE_RET); + nReturnErrCode = mfc_return_code(); + if (interrupt_flag == 0) { + mfc_err("MFCINST_ERR_ENC_EXE_TIME_OUT\n"); + return MFCINST_ERR_INTR_TIME_OUT; + } else if ((interrupt_flag != R2H_CMD_FRAME_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) { + mfc_err("MFCINST_ERR_ENC_DONE_FAIL\n"); + return MFCINST_ERR_ENC_ENCODE_DONE_FAIL; + } else if (interrupt_flag != R2H_CMD_FRAME_DONE_RET) { + mfc_warn("MFCINST_WARN_ENC_EXE.........(code: %d)\n", interrupt_flag); + } + + /* Get encoded infromation */ + enc_arg->out_frame_type = READL(MFC_SI_ENC_SLICE_TYPE); + enc_arg->out_encoded_size = READL(MFC_SI_ENC_STREAM_SIZE); + enc_arg->out_encoded_Y_paddr = READL(MFC_SI_ENCODED_Y_ADDR); + enc_arg->out_encoded_C_paddr = READL(MFC_SI_ENCODED_C_ADDR); + + if (mfc_ctx->buf_type == MFC_BUFFER_CACHE) { + dma_unmap_single(NULL, enc_arg->in_strm_st, + enc_arg->out_encoded_size, DMA_FROM_DEVICE); + } + + mfc_debug("-- frame type(%d) encodedSize(%d)\r\n", + enc_arg->out_frame_type, enc_arg->out_encoded_size); + + return MFCINST_RET_OK; +} + +enum mfc_error_code mfc_exe_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + enum mfc_error_code ret_code; + struct mfc_enc_exe_arg *enc_arg; + + enc_arg = (struct mfc_enc_exe_arg *)args; + + mfc_ctx->shared_mem.set_frame_tag = enc_arg->in_frametag; + mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + + /* 5. Encode Frame */ + ret_code = mfc_encode_one_frame(mfc_ctx, args); + + if (ret_code != MFCINST_RET_OK) { + mfc_debug("mfc_exe_encode() : Encode Fail..(%d)\n", ret_code); + return ret_code; + } + + mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + enc_arg->out_frametag_top = mfc_ctx->shared_mem.get_frame_tag_top; + enc_arg->out_frametag_bottom = mfc_ctx->shared_mem.get_frame_tag_bot; + + mfc_debug_L0("--\n"); + + return ret_code; +} + +enum mfc_error_code mfc_init_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + enum mfc_error_code ret_code; + struct mfc_dec_init_arg *init_arg; + unsigned int context_addr; + int context_size; + int nSize; + int nIntrRet = 0; + int nReturnErrCode = 0; + + + mfc_debug("[%d] mfc_init_decode() start\n", current->pid); + init_arg = (struct mfc_dec_init_arg *)args; + + /* Calculate stream header size */ +#if ENABLE_CHECK_SEQ_HEADER + init_arg->in_strm_size = calculate_seq_size(init_arg); +#endif + + /* Context setting from input param */ + mfc_ctx->MfcCodecType = init_arg->in_codec_type; + mfc_ctx->IsPackedPB = init_arg->in_packed_PB; + + /* OPEN CHANNEL + * - set open instance using codec_type + * - get the instance no + */ + ret_code = mfc_alloc_context_buffer(mfc_ctx, init_arg->in_mapped_addr, &context_addr, &context_size); + if (ret_code != MFCINST_RET_OK) + return ret_code; + + mfc_ctx->InstNo = mfc_get_inst_no(mfc_ctx, context_addr, context_size); + if (mfc_ctx->InstNo < 0) { + mfc_err("MFCINST_INST_NUM_EXCEEDED\n"); + return MFCINST_INST_NUM_EXCEEDED; + } + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_DEC_EXE_INTR_ERR + mcontext_addr = context_addr; + mcontext_size = context_size; +#endif +#endif + + /* + * MFC_LF_CONTROL used both encoding and decoding + * H.264 encoding, MPEG4 decoding(post filter) + * should disable : need more DPB for loop filter + */ + + /* INIT CODEC + * set input stream buffer + * set sequence done command + * set NUM_EXTRA_DPB + */ + if (mfc_ctx->MfcCodecType == FIMV1_DEC) { + WRITEL(mfc_ctx->widthFIMV1, MFC_SI_CH0_FIMV1_HRESOL); + WRITEL(mfc_ctx->heightFIMV1, MFC_SI_CH0_FIMV1_VRESOL); + } + + ret_code = mfc_alloc_codec_buffer(mfc_ctx, args); + if (ret_code != MFCINST_RET_OK) { + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return ret_code; + } + + if (nReturnErrCode < 0) + return MFCINST_ERR_DEC_INVALID_STRM; + + mfc_set_dec_stream_buffer(mfc_ctx, init_arg->in_strm_buf, init_arg->in_strm_size); + + /* Set Display Delay and SliceEnable */ + mfc_ctx->sliceEnable = 0; + WRITEL(((mfc_ctx->sliceEnable << 31) | + (mfc_ctx->displayDelay ? ((1 << 30) | + (mfc_ctx->displayDelay << 16)) : 0)), + MFC_SI_CH0_DPB_CONFIG_CTRL); + + /* Set Available Type */ + if (mCheckType == false) { + nSize = mfc_ctx->img_width * mfc_ctx->img_height; + mfc_ctx->shared_mem.p720_limit_enable = 49425; + if (nSize > BOUND_MEMORY_SIZE) { + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return MFCINST_ERR_FRM_BUF_SIZE; + } + } else { + mfc_ctx->shared_mem.p720_limit_enable = 49424; + } + + WRITEL_SHARED_MEM(mfc_ctx->shared_mem.p720_limit_enable, + mfc_ctx->shared_mem_vaddr + P720_LIMIT_ENABLE); + WRITEL((mfc_ctx->shared_mem_paddr - mfc_port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR); + + /* Codec Command : Decode a sequence header */ + WRITEL((SEQ_HEADER << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID); + + nIntrRet = mfc_wait_for_done(R2H_CMD_SEQ_DONE_RET); + nReturnErrCode = mfc_return_code(); + if (nIntrRet == 0) { + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_DEC_EXE_INTR_ERR + makefile_mfc_decinit_err_info(mfc_ctx, init_arg, 300); +#endif +#endif + + mfc_err("MFCINST_ERR_DEC_INIT_TIME_OUT..........[#1]\n"); + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return MFCINST_ERR_INTR_TIME_OUT; + } else if ((nIntrRet != R2H_CMD_SEQ_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) { + mfc_err("MFCINST_ERR_DEC_SEQ_HEADER_FAIL ....Intr Code (%d)\n", nIntrRet); + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return MFCINST_ERR_DEC_SEQ_DONE_FAIL; + } else if (nIntrRet != R2H_CMD_SEQ_DONE_RET) { + mfc_warn("MFCINST_WARN_DEC_INIT.........(code: %d)\n", nIntrRet); + } + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_OK + #if ENABLE_DEBUG_DEC_EXE_INTR_OK + makefile_mfc_decinit_err_info(mfc_ctx, init_arg, 1000); +#endif +#endif + + /* out param & context setting from header decoding result */ + mfc_ctx->img_width = READL(MFC_SI_HOR_RESOL); + mfc_ctx->img_height = READL(MFC_SI_VER_RESOL); + + init_arg->out_img_width = READL(MFC_SI_HOR_RESOL); + init_arg->out_img_height = READL(MFC_SI_VER_RESOL); + + /* in the case of VC1 interlace, height will be the multiple of 32 + * otherwise, height and width is the mupltiple of 16 + */ + init_arg->out_buf_width = ALIGN_TO_128B(READL(MFC_SI_HOR_RESOL)); + init_arg->out_buf_height = ALIGN_TO_32B(READL(MFC_SI_VER_RESOL)); + + if (mfc_ctx->MfcCodecType == FIMV1_DEC) { + mfc_ctx->img_width = mfc_ctx->widthFIMV1; + mfc_ctx->img_height = mfc_ctx->heightFIMV1; + + init_arg->out_img_width = mfc_ctx->widthFIMV1; + init_arg->out_img_height = mfc_ctx->heightFIMV1; + init_arg->out_buf_width = ALIGN_TO_128B(mfc_ctx->widthFIMV1); + init_arg->out_buf_height = ALIGN_TO_32B(mfc_ctx->heightFIMV1); + } + + + /* Set totalDPB */ + init_arg->out_dpb_cnt = READL(MFC_SI_MIN_NUM_DPB); + mfc_ctx->DPBCnt = READL(MFC_SI_MIN_NUM_DPB); + + mfc_ctx->totalDPBCnt = init_arg->out_dpb_cnt; + mfc_ctx->totalDPBCnt = init_arg->out_dpb_cnt + mfc_ctx->extraDPB; + if (mfc_ctx->totalDPBCnt < mfc_ctx->displayDelay) + mfc_ctx->totalDPBCnt = mfc_ctx->displayDelay; + + WRITEL(((mfc_ctx->sliceEnable << 31) | + (mfc_ctx->displayDelay ? ((1 << 30) | + (mfc_ctx->displayDelay << 16)) : 0) | + mfc_ctx->totalDPBCnt), MFC_SI_CH0_DPB_CONFIG_CTRL); + + mfc_debug("buf_width : %d buf_height : %d out_dpb_cnt : %d mfc_ctx->DPBCnt : %d\n", + init_arg->out_img_width, init_arg->out_img_height, init_arg->out_dpb_cnt, mfc_ctx->DPBCnt); + mfc_debug("img_width : %d img_height : %d\n", + init_arg->out_img_width, init_arg->out_img_height); + + mfc_set_codec_buffer(mfc_ctx); + + ret_code = mfc_alloc_dec_frame_buffer(mfc_ctx, args); + if (ret_code != MFCINST_RET_OK) { + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return ret_code; + } + + mfc_set_dec_frame_buffer(mfc_ctx); + +#ifdef ENABLE_DEBUG_MFC_INIT +#if ENABLE_DEBUG_MFC_INIT + printk_mfc_init_info(mfc_ctx, init_arg); +#endif +#endif + + mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + WRITEL((mfc_ctx->shared_mem_paddr - mfc_port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR); + WRITEL((INIT_BUFFER << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID); + + nIntrRet = mfc_wait_for_done(R2H_CMD_INIT_BUFFERS_RET); + nReturnErrCode = mfc_return_code(); + if (nIntrRet == 0) { +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_DEC_EXE_INTR_ERR + makefile_mfc_decinit_err_info(mfc_ctx, init_arg, 300); +#endif +#endif + + mfc_err("MFCINST_ERR_DEC_INIT_TIME_OUT..............[#2]\n"); + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return MFCINST_ERR_INTR_TIME_OUT; + } else if ((nIntrRet != R2H_CMD_INIT_BUFFERS_RET) && (nReturnErrCode < MFC_WARN_START_NO)) { + mfc_err("MFCINST_ERR_DEC_INIT_BUFFER_FAIL ........(Intr Code : %d)\n", nIntrRet); + /* In case of no instance, we should not release codec instance */ + if (mfc_ctx->InstNo >= 0) + mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); + + return MFCINST_ERR_DEC_INIT_BUFFER_FAIL; + } else if (nIntrRet != R2H_CMD_INIT_BUFFERS_RET) { + mfc_warn("MFCINST_WARN_DEC_INIT_BUFFER.........(Intr code: %d)\n", nIntrRet); + } + + mfc_ctx->IsStartedIFrame = 0; + + mfc_backup_context(mfc_ctx); + + mfc_debug("[%d] mfc_init_decode() end\n", current->pid); + + mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + init_arg->out_crop_top_offset = (mfc_ctx->shared_mem.crop_info2 & 0xffff); + init_arg->out_crop_bottom_offset = (mfc_ctx->shared_mem.crop_info2 >> 16); + init_arg->out_crop_left_offset = (mfc_ctx->shared_mem.crop_info1 & 0xffff); + init_arg->out_crop_right_offset = (mfc_ctx->shared_mem.crop_info1 >> 16); + mfc_debug("out_crop_top_offset : %d out_crop_bottom_offset : %d\n", init_arg->out_crop_top_offset, init_arg->out_crop_bottom_offset); + + return MFCINST_RET_OK; +} + +static enum mfc_error_code mfc_decode_one_frame(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg, unsigned int *consumed_strm_size) +{ + unsigned int frame_type; + static int count; + int interrupt_flag; + int nReturnErrCode = 0; + int nMaxFrameSize = 0; + int nOffSet = 0; + int nSum = 0; + unsigned char *stream_vir; + + /* Check Invalid Stream Size */ +#if ENABLE_CHECK_STREAM_SIZE + nMaxFrameSize = mfc_ctx->img_height * mfc_ctx->img_width; + if ((dec_arg->in_strm_size < 1) || (dec_arg->in_strm_size > nMaxFrameSize) || (dec_arg->in_strm_size > STREAM_BUF_SIZE)) { + mfc_err("MFCINST_ERR_DEC_STRM_SIZE_INVALID : (stream size : %d), (resolution : %d)\n", dec_arg->in_strm_size, nMaxFrameSize); + return MFCINST_ERR_DEC_STRM_SIZE_INVALID; + } +#endif + + /* Check Invalid Null Stream */ +#if ENABLE_CHECK_NULL_STREAM + if ((dec_arg->in_strm_size > 10) && (!(mfc_ctx->IsPackedPB))) { + stream_vir = phys_to_virt(dec_arg->in_strm_buf); + nSum = CheckNullStream(stream_vir, dec_arg->in_strm_size); + + if (nSum != 0) { +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR + #if ENABLE_DEBUG_DEC_EXE_INTR_ERR + makefile_mfc_dec_err_info(mfc_ctx, dec_arg, 500); +#endif +#endif + return MFCINST_ERR_STRM_BUF_INVALID; + } + } +#endif + + /* Check H.263 Strat Code */ +#if ENABLE_CHECK_START_CODE + stream_vir = phys_to_virt(dec_arg->in_strm_buf); + nOffSet = CheckDecStartCode(stream_vir, dec_arg->in_strm_size, dec_arg->in_codec_type); + + if (nOffSet < 0) { +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR + #if ENABLE_DEBUG_DEC_EXE_INTR_ERR + makefile_mfc_dec_err_info(mfc_ctx, dec_arg, 400); +#endif +#endif + return MFCINST_ERR_STRM_BUF_INVALID; + } +#endif + + count++; + mfc_debug_L0("++ IntNo%d(%d)\r\n", mfc_ctx->InstNo, count); + + WRITEL((mfc_ctx->shared_mem_paddr - mfc_port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR); + mfc_set_dec_stream_buffer(mfc_ctx, dec_arg->in_strm_buf, dec_arg->in_strm_size); + + if (mfc_ctx->endOfFrame) { + WRITEL((LAST_FRAME<<16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID); + mfc_ctx->endOfFrame = 0; + } else { + WRITEL((FRAME<<16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID); + } + + interrupt_flag = mfc_wait_for_done(R2H_CMD_FRAME_DONE_RET); + nReturnErrCode = mfc_return_code(); + if (interrupt_flag == 0) { +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR + #if ENABLE_DEBUG_DEC_EXE_INTR_ERR + makefile_mfc_dec_err_info(mfc_ctx, dec_arg, 300); +#endif +#endif + + +#if ENABLE_MFC_REGISTER_DEBUG + mfc_fw_debug(R2H_CMD_FRAME_DONE_RET); +#endif + + mfc_err("MFCINST_ERR_DEC_EXE_TIME_OUT\n"); + return MFCINST_ERR_INTR_TIME_OUT; + } else if ((interrupt_flag != R2H_CMD_FRAME_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) { + +#ifdef ENABLE_DEBUG_DEC_EXE_PARSER_ERR + #if ENABLE_DEBUG_DEC_EXE_PARSER_ERR + makefile_mfc_dec_err_info(mfc_ctx, dec_arg, nReturnErrCode); +#endif +#endif + /* Clear start_byte_num in case of error */ + mfc_ctx->shared_mem.start_byte_num = 0x0; + mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + +#if ENABLE_MFC_REGISTER_DEBUG + mfc_fw_debug(R2H_CMD_FRAME_DONE_RET); +#endif + + mfc_err("MFCINST_ERR_DEC_DONE_FAIL.......(interrupt_flag: %d), (ERR Code: %d)\n", interrupt_flag, nReturnErrCode); + return MFCINST_ERR_DEC_DECODE_DONE_FAIL; + + } else if (interrupt_flag != R2H_CMD_FRAME_DONE_RET) { + mfc_warn("MFCINST_WARN_DEC_EXE.........(interrupt_flag: %d), (WARN Code: %d)\n", interrupt_flag, nReturnErrCode); + } + + mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + + dec_arg->out_res_change = (READL(MFC_SI_DISPLAY_STATUS) >> 4) & 0x3; + + if (((READL(MFC_SI_DISPLAY_STATUS) & 0x3) != DECODING_DISPLAY) && + ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) != DISPLAY_ONLY)) { + dec_arg->out_display_Y_addr = 0; + dec_arg->out_display_C_addr = 0; + mfc_debug("DECODING_ONLY frame decoded\n"); + } else { + /* address shift */ + dec_arg->out_display_Y_addr = READL(MFC_SI_DISPLAY_Y_ADR) << 11; + dec_arg->out_display_C_addr = READL(MFC_SI_DISPLAY_C_ADR) << 11; + mfc_debug("DISPLAY Able frame decoded\n"); + } + + if ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DECODING_EMPTY) + dec_arg->out_display_status = 0; + else if ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DECODING_DISPLAY) + dec_arg->out_display_status = 1; + else if ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DISPLAY_ONLY) + dec_arg->out_display_status = 2; + else + dec_arg->out_display_status = 3; + + frame_type = READL(MFC_SI_FRAME_TYPE); + mfc_ctx->FrameType = (enum mfc_frame_type)(frame_type & 0x3); + + mfc_debug_L0("(Y_ADDR : 0x%08x C_ADDR : 0x%08x)\r\n", + dec_arg->out_display_Y_addr, dec_arg->out_display_C_addr); + + *consumed_strm_size = READL(MFC_SI_DEC_FRM_SIZE); + + return MFCINST_RET_OK; +} + +enum mfc_error_code mfc_exe_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + enum mfc_error_code ret_code; + struct mfc_dec_exe_arg *dec_arg; + int consumed_strm_size; + + /* 6. Decode Frame */ + mfc_debug_L0("[%d] mfc_exe_decode() start\n", current->pid); + + dec_arg = (struct mfc_dec_exe_arg *)args; + + mfc_ctx->shared_mem.set_frame_tag = dec_arg->in_frametag; + + mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + + ret_code = mfc_decode_one_frame(mfc_ctx, dec_arg, &consumed_strm_size); + + if (ret_code != MFCINST_RET_OK) { + mfc_debug("mfc_exe_decode() : Decode Fail..(%d)\n", ret_code); + return ret_code; + } + + mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + dec_arg->out_frametag_top = mfc_ctx->shared_mem.get_frame_tag_top; + dec_arg->out_frametag_bottom = mfc_ctx->shared_mem.get_frame_tag_bot; + dec_arg->out_timestamp_top = mfc_ctx->shared_mem.pic_time_top; + dec_arg->out_timestamp_bottom = mfc_ctx->shared_mem.pic_time_bot; + dec_arg->out_consume_bytes = consumed_strm_size; + dec_arg->out_crop_top_offset = (mfc_ctx->shared_mem.crop_info2 & 0xffff); + dec_arg->out_crop_bottom_offset = (mfc_ctx->shared_mem.crop_info2 >> 16); + dec_arg->out_crop_left_offset = (mfc_ctx->shared_mem.crop_info1 & 0xffff); + dec_arg->out_crop_right_offset = (mfc_ctx->shared_mem.crop_info1 >> 16); + + + /* PackedPB Stream Processing */ + if ((mfc_ctx->IsPackedPB) && + (mfc_ctx->FrameType == MFC_RET_FRAME_P_FRAME) && + (dec_arg->in_strm_size - consumed_strm_size > 4)) { + + unsigned char *stream_vir; + int offset = 0; + + stream_vir = phys_to_virt(dec_arg->in_strm_buf); + + invalidate_kernel_vmap_range((void *)stream_vir, dec_arg->in_strm_size); + + offset = CheckMPEG4StartCode(stream_vir+consumed_strm_size , dec_arg->in_strm_size - consumed_strm_size); + if (offset > 4) + consumed_strm_size += offset; + dec_arg->in_strm_size -= consumed_strm_size; + + mfc_ctx->shared_mem.set_frame_tag = dec_arg->in_frametag; + mfc_ctx->shared_mem.start_byte_num = consumed_strm_size; + mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + ret_code = mfc_decode_one_frame(mfc_ctx, dec_arg, &consumed_strm_size); + if (ret_code != MFCINST_RET_OK) + return ret_code; + + mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem)); + dec_arg->out_frametag_top = mfc_ctx->shared_mem.get_frame_tag_top; + dec_arg->out_frametag_bottom = mfc_ctx->shared_mem.get_frame_tag_bot; + dec_arg->out_timestamp_top = mfc_ctx->shared_mem.pic_time_top; + dec_arg->out_timestamp_bottom = mfc_ctx->shared_mem.pic_time_bot; + dec_arg->out_consume_bytes += consumed_strm_size; + dec_arg->out_crop_top_offset = (mfc_ctx->shared_mem.crop_info2 & 0xffff); + dec_arg->out_crop_bottom_offset = (mfc_ctx->shared_mem.crop_info2 >> 16); + dec_arg->out_crop_left_offset = (mfc_ctx->shared_mem.crop_info1 & 0xffff); + dec_arg->out_crop_right_offset = (mfc_ctx->shared_mem.crop_info1 >> 16); + + mfc_ctx->shared_mem.start_byte_num = 0; + + } + + if (mfc_ctx->buf_type == MFC_BUFFER_CACHE) { + if (((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DECODING_DISPLAY) || + ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DISPLAY_ONLY)) { + unsigned int aligned_width; + unsigned int aligned_height; + + aligned_width = ALIGN_TO_128B(mfc_ctx->img_width); + aligned_height = ALIGN_TO_32B(mfc_ctx->img_height); + dma_unmap_single(NULL, dec_arg->out_display_Y_addr, + aligned_width*aligned_height, DMA_FROM_DEVICE); + + aligned_height = ALIGN_TO_32B(mfc_ctx->img_height/2); + dma_unmap_single(NULL, dec_arg->out_display_C_addr, + aligned_width*aligned_height, DMA_FROM_DEVICE); + } + } + + mfc_debug_L0("--\n"); + + return ret_code; +} + +enum mfc_error_code mfc_deinit_hw(struct mfc_inst_ctx *mfc_ctx) +{ + mfc_restore_context(mfc_ctx); + + return MFCINST_RET_OK; +} + +enum mfc_error_code mfc_get_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_get_config_arg *get_cnf_arg; + get_cnf_arg = (struct mfc_get_config_arg *)args; + + switch (get_cnf_arg->in_config_param) { + case MFC_DEC_GETCONF_CRC_DATA: + if (mfc_ctx->MfcState != MFCINST_STATE_DEC_EXE) { + mfc_err("MFC_DEC_GETCONF_CRC_DATA : state is invalid\n"); + return MFC_DEC_GETCONF_CRC_DATA; + } + get_cnf_arg->out_config_value[0] = READL(MFC_CRC_LUMA0); + get_cnf_arg->out_config_value[1] = READL(MFC_CRC_CHROMA0); + break; + + default: + mfc_err("invalid config param\n"); + return MFCINST_ERR_GET_CONF; /* peter, it should be mod. */ + } + + return MFCINST_RET_OK; +} + +enum mfc_error_code mfc_set_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args) +{ + struct mfc_set_config_arg *set_cnf_arg; + set_cnf_arg = (struct mfc_set_config_arg *)args; + + switch (set_cnf_arg->in_config_param) { + case MFC_DEC_SETCONF_POST_ENABLE: + if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFC_DEC_SETCONF_POST_ENABLE : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) { + mfc_ctx->postEnable = set_cnf_arg->in_config_value[0]; + } else { + mfc_warn("POST_ENABLE should be 0 or 1\n"); + mfc_ctx->postEnable = 0; + } + break; + + case MFC_DEC_SETCONF_EXTRA_BUFFER_NUM: + if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFC_DEC_SETCONF_EXTRA_BUFFER_NUM : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + if ((set_cnf_arg->in_config_value[0] >= 0) || (set_cnf_arg->in_config_value[0] <= MFC_MAX_EXTRA_DPB)) { + mfc_ctx->extraDPB = set_cnf_arg->in_config_value[0]; + } else { + mfc_warn("EXTRA_BUFFER_NUM should be between 0 and 5...It will be set 5 by default\n"); + mfc_ctx->extraDPB = MFC_MAX_EXTRA_DPB; + } + break; + + case MFC_DEC_SETCONF_DISPLAY_DELAY: + if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFC_DEC_SETCONF_DISPLAY_DELAY : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + if ((set_cnf_arg->in_config_value[0] >= 0) || (set_cnf_arg->in_config_value[0] < 16)) { + mfc_ctx->displayDelay = set_cnf_arg->in_config_value[0]; + mfc_debug("DISPLAY_DELAY Number = %d\n", mfc_ctx->displayDelay); + } else { + mfc_warn("DISPLAY_DELAY should be between 0 and 16\n"); + mfc_ctx->displayDelay = 0; + } + break; + + case MFC_DEC_SETCONF_IS_LAST_FRAME: + if (mfc_ctx->MfcState != MFCINST_STATE_DEC_EXE) { + mfc_err("MFC_DEC_SETCONF_IS_LAST_FRAME : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) { + mfc_ctx->endOfFrame = set_cnf_arg->in_config_value[0]; + } else { + mfc_warn("IS_LAST_FRAME should be 0 or 1\n"); + mfc_ctx->endOfFrame = 0; + } + break; + + case MFC_DEC_SETCONF_SLICE_ENABLE: + if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFC_DEC_SETCONF_SLICE_ENABLE : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) { + mfc_ctx->sliceEnable = set_cnf_arg->in_config_value[0]; + } else { + mfc_warn("SLICE_ENABLE should be 0 or 1\n"); + mfc_ctx->sliceEnable = 0; + } + break; + + case MFC_DEC_SETCONF_CRC_ENABLE: + if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFC_DEC_SETCONF_CRC_ENABLE : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) { + mfc_ctx->crcEnable = set_cnf_arg->in_config_value[0]; + } else { + mfc_warn("CRC_ENABLE should be 0 or 1\n"); + mfc_ctx->crcEnable = 0; + } + break; + + case MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT: + if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) { + mfc_err("MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + mfc_ctx->widthFIMV1 = set_cnf_arg->in_config_value[0]; + mfc_ctx->heightFIMV1 = set_cnf_arg->in_config_value[1]; + break; + + case MFC_ENC_SETCONF_FRAME_TYPE: + if (mfc_ctx->MfcState != MFCINST_STATE_ENC_EXE) { + mfc_err("MFC_ENC_SETCONF_FRAME_TYPE : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + if ((set_cnf_arg->in_config_value[0] >= DONT_CARE) && (set_cnf_arg->in_config_value[0] <= NOT_CODED)) { + mfc_ctx->forceSetFrameType = set_cnf_arg->in_config_value[0]; + } else { + mfc_warn("FRAME_TYPE should be between 0 and 2\n"); + mfc_ctx->forceSetFrameType = DONT_CARE; + } + break; + + case MFC_ENC_SETCONF_ALLOW_FRAME_SKIP: + if (mfc_ctx->MfcState >= MFCINST_STATE_ENC_INITIALIZE) { + mfc_err("MFC_ENC_SETCONF_ALLOW_FRAME_SKIP : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + + if (set_cnf_arg->in_config_value[0]) + mfc_ctx->shared_mem.ext_enc_control = (mfc_ctx->shared_mem.ext_enc_control | (0x1 << 1)); + break; + + /* XXX: need to implement */ + case MFC_ENC_SETCONF_CHANGE_FRAME_RATE: + if (mfc_ctx->MfcState != MFCINST_STATE_ENC_EXE) { + mfc_err("MFC_ENC_SETCONF_FRAME_TYPE : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + break; + + /* XXX: need to implement */ + case MFC_ENC_SETCONF_CHANGE_BIT_RATE: + if (mfc_ctx->MfcState != MFCINST_STATE_ENC_EXE) { + mfc_err("MFC_ENC_SETCONF_FRAME_TYPE : state is invalid\n"); + return MFCINST_ERR_STATE_INVALID; + } + break; + + default: + mfc_err("invalid config param\n"); + return MFCINST_ERR_SET_CONF; + } + + return MFCINST_RET_OK; +} + +enum mfc_error_code mfc_set_sleep() +{ + if (mfc_cmd_host2risc(H2R_CMD_SLEEP, 0, 0, 0, 0) == false) { + mfc_err("R2H_CMD_SLEEP FAIL\n"); + return MFCINST_SLEEP_FAIL; + } + + if (mfc_wait_for_done(R2H_CMD_SLEEP_RET) != R2H_CMD_SLEEP_RET) { + mfc_err("R2H_CMD_SLEEP_RET FAIL\n"); + return MFCINST_SLEEP_FAIL; + } + + return MFCINST_RET_OK; +} + +enum mfc_error_code mfc_set_wakeup() +{ + int ret; + + if (mfc_cmd_host2risc(H2R_CMD_WAKEUP, 0, 0, 0, 0) == false) { + mfc_err("R2H_CMD_WAKEUP FAIL\n"); + return MFCINST_WAKEUP_FAIL; + } + + WRITEL(0x3ff, MFC_SW_RESET); + + ret = mfc_wait_for_done(R2H_CMD_WAKEUP_RET); + if ((ret != R2H_CMD_WAKEUP_RET) && (ret != R2H_CMD_FW_STATUS_RET)) { + mfc_err("R2H_CMD_WAKEUP_RET FAIL\n"); + return MFCINST_WAKEUP_FAIL; + } + + return MFCINST_RET_OK; +} + +static enum +mfc_error_code mfc_alloc_context_buffer(struct mfc_inst_ctx *mfc_ctx, unsigned int mapped_addr, + unsigned int *context_addr, int *size) +{ + union mfc_args local_param; + enum mfc_error_code ret_code; + unsigned char *context_vir; + + switch (mfc_ctx->MfcCodecType) { + case H264_ENC: + *size = H264ENC_CONTEXT_SIZE; + break; + + case MPEG4_ENC: + *size = MPEG4ENC_CONTEXT_SIZE; + break; + + case H263_ENC: + *size = H263ENC_CONTEXT_SIZE; + break; + + case H264_DEC: + *size = H264DEC_CONTEXT_SIZE; + break; + + case H263_DEC: + *size = H263DEC_CONTEXT_SIZE; + break; + + case MPEG2_DEC: + *size = MPEG2DEC_CONTEXT_SIZE; + break; + + case MPEG4_DEC: + case FIMV1_DEC: + case FIMV2_DEC: + case FIMV3_DEC: + case FIMV4_DEC: + *size = MPEG4DEC_CONTEXT_SIZE; + break; + + case VC1_DEC: + case VC1RCV_DEC: + *size = VC1DEC_CONTEXT_SIZE; + break; + + default: + return MFCINST_ERR_WRONG_CODEC_MODE; + } + + memset(&local_param, 0, sizeof(local_param)); + local_param.mem_alloc.buff_size = *size; + local_param.mem_alloc.mapped_addr = mapped_addr; + + ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0); + if (ret_code < 0) + return ret_code; + + /* Set mfc context to "0". */ + context_vir = phys_to_virt(local_param.mem_alloc.out_paddr); + memset(context_vir, 0x0, local_param.mem_alloc.buff_size); + + dmac_flush_range(context_vir, context_vir + local_param.mem_alloc.buff_size); + + *context_addr = local_param.mem_alloc.out_paddr; + + return ret_code; +} + +void mfc_init_mem_inst_no(void) +{ + memset(&mfc_mem_inst_no, 0x00, sizeof(mfc_mem_inst_no)); +} + +int mfc_get_mem_inst_no(void) +{ + unsigned int i; + + for (i = 0; i < MFC_MAX_INSTANCE_NUM; i++) { + if (mfc_mem_inst_no[i] == 0) { + mfc_mem_inst_no[i] = 1; + return i; + } + } + + return -1; +} + +void mfc_return_mem_inst_no(int inst_no) +{ + if ((inst_no >= 0) && (inst_no < MFC_MAX_INSTANCE_NUM)) + mfc_mem_inst_no[inst_no] = 0; +} + +bool mfc_is_running(void) +{ + unsigned int i; + bool ret = false; + + for (i = 0; i < MFC_MAX_INSTANCE_NUM; i++) { + mfc_debug("mfc_mem_inst_no[%d] = %d\n", i, mfc_mem_inst_no[i]); + if (mfc_mem_inst_no[i] == 1) + ret = true; + } + + return ret; +} + +int mfc_set_state(struct mfc_inst_ctx *ctx, enum mfc_inst_state state) +{ + if (ctx->MfcState > state) + return -1; + + ctx->MfcState = state; + return 0; +} + +bool is_dec_codec(enum ssbsip_mfc_codec_type codec_type) +{ + switch (codec_type) { + case H264_DEC: + case VC1_DEC: + case MPEG4_DEC: + case XVID_DEC: + case MPEG1_DEC: + case MPEG2_DEC: + case H263_DEC: + case VC1RCV_DEC: + case FIMV1_DEC: + case FIMV2_DEC: + case FIMV3_DEC: + case FIMV4_DEC: + return true; + + case H264_ENC: + case MPEG4_ENC: + case H263_ENC: + return false; + + default: + return false; + } +} + + + + + +/* + * Debugging Functions Definition + * tile_to_linear_4x2(..) + * calculate_seq_size(..) + * printk_mfc_init_info(..) + */ + + +#if DEBUG_MAKE_RAW +static void write_file(char *filename, unsigned char *data, unsigned int nSize) +{ + struct file *file; + loff_t pos = 0; + int fd; + mm_segment_t old_fs; + + invalidate_kernel_vmap_range(data, nSize); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + fd = sys_open(filename, O_WRONLY|O_CREAT, 0644); + if (fd >= 0) { + sys_write(fd, data, nSize); + file = fget(fd); + if (file) { + vfs_write(file, data, nSize, &pos); + fput(file); + } + sys_close(fd); + } else { + mfc_err("........Open fail : %d\n", fd); + } + set_fs(old_fs); + + dmac_flush_range(data, data + nSize); + +} + +static int tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos) +{ + int pixel_x_m1, pixel_y_m1; + int roundup_x, roundup_y; + int linear_addr0, linear_addr1, bank_addr ; + int x_addr; + int trans_addr; + + pixel_x_m1 = x_size - 1; + pixel_y_m1 = y_size - 1; + + roundup_x = ((pixel_x_m1 >> 7) + 1); + roundup_y = ((pixel_x_m1 >> 6) + 1); + + x_addr = (x_pos >> 2); + + if ((y_size <= y_pos+32) && (y_pos < y_size) && + (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) { + linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } else { + linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } + + linear_addr0 = linear_addr0 << 2; + trans_addr = (linear_addr1 << 13) | (bank_addr << 11) | linear_addr0; + + return trans_addr; +} + + +static void copy16(unsigned char *p_linear_addr, unsigned char *p_tiled_addr, int mm, int nn) +{ + p_linear_addr[mm] = p_tiled_addr[nn]; + p_linear_addr[mm + 1] = p_tiled_addr[nn + 1]; + p_linear_addr[mm + 2] = p_tiled_addr[nn + 2]; + p_linear_addr[mm + 3] = p_tiled_addr[nn + 3]; + + p_linear_addr[mm + 4] = p_tiled_addr[nn + 4]; + p_linear_addr[mm + 5] = p_tiled_addr[nn + 5]; + p_linear_addr[mm + 6] = p_tiled_addr[nn + 6]; + p_linear_addr[mm + 7] = p_tiled_addr[nn + 7]; + + p_linear_addr[mm + 8] = p_tiled_addr[nn + 8]; + p_linear_addr[mm + 9] = p_tiled_addr[nn + 9]; + p_linear_addr[mm + 10] = p_tiled_addr[nn + 10]; + p_linear_addr[mm + 11] = p_tiled_addr[nn + 11]; + + p_linear_addr[mm + 12] = p_tiled_addr[nn + 12]; + p_linear_addr[mm + 13] = p_tiled_addr[nn + 13]; + p_linear_addr[mm + 14] = p_tiled_addr[nn + 14]; + p_linear_addr[mm + 15] = p_tiled_addr[nn + 15]; +} + + +static void +tile_to_linear_4x2(unsigned char *p_linear_addr, unsigned char *p_tiled_addr, + unsigned int x_size, unsigned int y_size) +{ + int trans_addr; + unsigned int i, j, k, nn, mm, index; + + /*. TILE 4x2 test */ + for (i = 0; i < y_size; i = i + 16) { + for (j = 0; j < x_size; j = j + 16) { + trans_addr = tile_4x2_read(x_size, y_size, j, i); + index = i*x_size + j; + + k = 0; nn = trans_addr + (k << 6); mm = index; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 1; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 2; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 3; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 4; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 5; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 6; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 7; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 8; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 9; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 10; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 11; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 12; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 13; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 14; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + k = 15; nn = trans_addr + (k << 6); mm += x_size; + copy16(p_linear_addr, p_tiled_addr, mm, nn); + + } + } +} +#endif + + + +#if ENABLE_CHECK_SEQ_HEADER +static int calculate_seq_size(mfc_args *args) +{ + int nn = 0; + int nCnt = 0; + unsigned char nSum = 0; + unsigned char *stream_vir; + + stream_vir = phys_to_virt(args->dec_init.in_strm_buf); + if (args->dec_init.in_strm_size > 31) { + for (nn = 0; nn < args->dec_init.in_strm_size - 4; nn++) { + nSum = (unsigned char)(((*(stream_vir + nn)) << 1) + ((*(stream_vir + nn + 1)) << 1) + + ((*(stream_vir + nn + 2)) << 1) + (*(stream_vir+nn+3))); + if (nSum == 0x1) { + nCnt++; + } + + if (nCnt == 3) { + mfc_info("After Stream Size : %d , nCnt = %d\n", args->dec_init.in_strm_size, nCnt); + return nn; + } + } + } + + return args->dec_init.in_strm_size; +} +#endif + + +#if ENABLE_DEBUG_MFC_INIT +void printk_mfc_init_info(mfc_inst_ctx *mfc_ctx, mfc_args *args) +{ + int nn = 0; + unsigned char *stream_vir; + + mfc_info("MFC Decoder/Encoder Init Information\n"); + mfc_info("[InstNo : %d], [DPBCnt : %d], [totalDPBCnt : %d], [extraDPB : %d], [displayDelay : %d],\n", + mfc_ctx->InstNo, mfc_ctx->DPBCnt, mfc_ctx->totalDPBCnt, mfc_ctx->extraDPB, mfc_ctx->displayDelay); + mfc_info("[img_width : %d], [img_height : %d], [MfcCodecType : %d], [MfcState : %d]\n", + mfc_ctx->img_width, mfc_ctx->img_height, mfc_ctx->MfcCodecType, mfc_ctx->MfcState); + + mfc_info("Input Stream Buffer Information\n"); + mfc_info("[in_strm_size : %d], [in_strm_buf : %d]\n", + args->dec_init.in_strm_size, args->dec_init.in_strm_buf); + + stream_vir = phys_to_virt(args->dec_init.in_strm_buf); + if (args->dec_init.in_strm_size > 0) { + mfc_info("Input Stream Buffer\n"); + for (nn = 0; nn < 40; nn++) + printk("%02x ", *(stream_vir+nn)); + printk("\n"); + } + +} +#endif + + +#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR +#if ENABLE_DEBUG_DEC_EXE_INTR_ERR +void printk_mfc_dec_exe_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg) +{ + int nn = 0; + unsigned char *stream_vir; + + mfc_info("MFC Decoder/Encoder Exe Information\n"); + mfc_info("[InstNo : %d], [DPBCnt : %d], [totalDPBCnt : %d], [extraDPB : %d], [displayDelay : %d],\n", + mfc_ctx->InstNo, mfc_ctx->DPBCnt, mfc_ctx->totalDPBCnt, mfc_ctx->extraDPB, mfc_ctx->displayDelay); + mfc_info("[img_width : %d], [img_height : %d], [MfcCodecType : %d], [MfcState : %d], [FrameType: %d]\n", + mfc_ctx->img_width, mfc_ctx->img_height, mfc_ctx->MfcCodecType, mfc_ctx->MfcState, mfc_ctx->FrameType); + + mfc_info("Input Stream Buffer Information\n"); + mfc_info("[in_strm_size : %d], [in_strm_buf : %d]\n", + dec_arg->in_strm_size, dec_arg->in_strm_buf); + + stream_vir = phys_to_virt(dec_arg->in_strm_buf); + if (dec_arg->in_strm_size > 0) { + mfc_info("Input Stream Buffer\n"); + for (nn = 0; nn < 50; nn++) + printk("%02x ", *(stream_vir+nn)); + printk("\n"); + } +} + +void +makefile_mfc_dec_err_info(struct mfc_inst_ctx *mfc_ctx, + struct mfc_dec_exe_arg *dec_arg, int nReturnErrCode) +{ + char fileName0[50]; + char fileName1[50]; + unsigned char *ctx_virbuf; + unsigned char *mfc_dec_in_base_vaddr; + + mframe_cnt++; + + if ((nReturnErrCode < 145) || (nReturnErrCode == 300)) { + mIsDangerError = 1; + printk_mfc_dec_exe_info(mfc_ctx, dec_arg); + } + + memset(fileName0, 0, 50); + memset(fileName1, 0, 50); + + sprintf(fileName0, "/data/dec_in/mfc_decexe_instream_%d_%d.raw", nReturnErrCode, mframe_cnt); + sprintf(fileName1, "/data/dec_in/mfc_decexe_mfcctx_%d_%d.bin", nReturnErrCode, mframe_cnt); + + mfc_dec_in_base_vaddr = phys_to_virt(dec_arg->in_strm_buf); + ctx_virbuf = phys_to_virt(mcontext_addr); + + write_file(fileName0, mfc_dec_in_base_vaddr, dec_arg->in_strm_size); + write_file(fileName1, ctx_virbuf, mcontext_size); + +} + + +void makefile_mfc_decinit_err_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_init_arg *decinit_arg, int nReturnErrCode) +{ + char fileName0[50]; + char fileName1[50]; + unsigned char *ctx_virbuf; + unsigned char *mfc_dec_in_base_vaddr; + + mframe_cnt++; + + pr_info("makefile_mfc_decinit_err_info : in_strm_size(%d)\n", decinit_arg->in_strm_size); + + memset(fileName0, 0, 50); + memset(fileName1, 0, 50); + + sprintf(fileName0, "/data/dec_in/mfc_decinit_instream_%d_%d.raw", nReturnErrCode, mframe_cnt); + sprintf(fileName1, "/data/dec_in/mfc_decinit_mfcctx_%d_%d.bin", nReturnErrCode, mframe_cnt); + + mfc_dec_in_base_vaddr = phys_to_virt(decinit_arg->in_strm_buf); + ctx_virbuf = phys_to_virt(mcontext_addr); + + write_file(fileName0, mfc_dec_in_base_vaddr, decinit_arg->in_strm_size); + write_file(fileName1, ctx_virbuf, mcontext_size); +} +#endif +#endif + +#ifdef ENABLE_DEBUG_ENC_EXE_INTR_ERR +#if ENABLE_DEBUG_ENC_EXE_INTR_ERR +void makefile_mfc_enc_err_info(struct mfc_enc_exe_arg *enc_arg) +{ + int nFrameSize = 0; + char fileName[50]; + unsigned char *mfc_enc_in_base_Y_vaddr; + unsigned char *mfc_enc_in_base_CbCr_vaddr; + + mframe_cnt++; + + memset(fileName, 0, 50); + sprintf(fileName, "/data/enc_in/mfc_in_%04d.yuv", mframe_cnt); + nFrameSize = mImgHight * mImgWidth * 3/2; + + mfc_enc_in_base_Y_vaddr = phys_to_virt(enc_arg->in_Y_addr); + mfc_enc_in_base_CbCr_vaddr = phys_to_virt(enc_arg->in_CbCr_addr); + + mfc_debug("enc_arg->in_Y_addr : 0x%08x enc_arg->in_Y_addr_vir :0x%08x\r\n", + enc_arg->in_Y_addr, mfc_enc_in_base_Y_vaddr); + + tile_to_linear_4x2(pResLinearbuf, mfc_enc_in_base_Y_vaddr, + mImgWidth, mImgHight); + tile_to_linear_4x2(pResLinearbuf + (mImgHight * mImgWidth), + mfc_enc_in_base_CbCr_vaddr, mImgWidth, mImgHight/2); + write_file(fileName, pResLinearbuf, nFrameSize); + +} +#endif +#endif + + +static int CheckMPEG4StartCode(unsigned char *src_mem, unsigned int remainSize) +{ + unsigned int index = 0; + + for (index = 0; index < remainSize-3; index++) { + if ((src_mem[index] == 0x00) + && (src_mem[index+1] == 0x00) + && (src_mem[index+2] == 0x01)) + return index; + } + + return -1; +} + +#if ENABLE_CHECK_START_CODE +static int CheckDecStartCode(unsigned char *src_mem, unsigned int nstreamSize, enum ssbsip_mfc_codec_type nCodecType) +{ + unsigned int index = 0; + /* Check Start Code within "isearchSize" bytes. */ + unsigned int isearchSize = 20; + unsigned int nShift = 0; + unsigned char nFlag = 0xFF; + + if (nCodecType == H263_DEC) { + nFlag = 0x08; + nShift = 4; + } else if (nCodecType == MPEG4_DEC) { + nFlag = 0x01; + nShift = 0; + } else if (nCodecType == H264_DEC) { + nFlag = 0x01; + nShift = 0; + } else { + nFlag = 0xFF; + } + + if (nFlag != 0xFF) { + if (nstreamSize > 3) { + if (nstreamSize > isearchSize) { + for (index = 0; index < isearchSize-3; index++) { + if ((src_mem[index] == 0x00) + && (src_mem[index+1] == 0x00) + && ((src_mem[index+2] >> nShift) == nFlag)) + return index; + } + } else { + for (index = 0; index < nstreamSize - 3; index++) { + if ((src_mem[index] == 0x00) + && (src_mem[index+1] == 0x00) + && ((src_mem[index+2] >> nShift) == nFlag)) + return index; + } + } + } else { + return -1; + } + } else { + return 0; + } + + return -1; +} +#endif + +#if ENABLE_CHECK_NULL_STREAM +static int CheckNullStream(unsigned char *src_mem, unsigned int streamSize) +{ + unsigned int temp = 0; + unsigned int nn; + + if (streamSize < 30) { + for (nn = 0; nn < streamSize; nn++) + temp += src_mem[nn]; + } else { + for (nn = 0; nn < 10; nn++) + temp += src_mem[nn]; + + if (temp == 0) { + for (nn = streamSize-10; nn < streamSize; nn++) + temp += src_mem[nn]; + } + } + + if (temp == 0) { + mfc_debug("Null Stream......Error\n"); + return -1; + } + + return 0; + +} +#endif + +#if ENABLE_MFC_REGISTER_DEBUG +void mfc_fw_debug(mfc_wait_done_type command) +{ + mfc_err("=== MFC FW Debug (Cmd: %d)" + "(Ver: 0x%08x) ===\n", command, READL(0x58)); + mfc_err("=== (0x64: 0x%08x) (0x68: 0x%08x)" + "(0xE4: 0x%08x) (0xE8: 0x%08x)\n", + READL(0x64), READL(0x68), READL(0xe4), READL(0xe8)); + mfc_err("=== (0xF0: 0x%08x) (0xF4: 0x%08x)" + "(0xF8: 0x%08x) (0xFC: 0x%08x)\n", + READL(0xf0), READL(0xf4), READL(0xf8), READL(0xfc)); +} +#endif diff --git a/drivers/media/video/samsung/mfc50/mfc_opr.h b/drivers/media/video/samsung/mfc50/mfc_opr.h new file mode 100644 index 0000000..18cfe53 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_opr.h @@ -0,0 +1,204 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_opr.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.09.14 - Beautify source code (Key Young, Park) + * 2009.09.21 - Implement clock & power gating. + * including suspend & resume fuction. (Key Young, Park) + * 2009.11.04 - remove mfc_common.[ch] + * seperate buffer alloc & set (Key Young, Park) + * + * 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 _MFC_OPR_H_ +#define _MFC_OPR_H_ + +#include <plat/regs-mfc.h> +#include "mfc_errorno.h" +#include "mfc_interface.h" +#include "mfc_shared_mem.h" + +#define MFC_WARN_START_NO 145 +#define MFC_ERR_START_NO 1 + + +#define INT_MFC_FW_DONE (0x1 << 5) +#define INT_MFC_DMA_DONE (0x1 << 7) +#define INT_MFC_FRAME_DONE (0x1 << 8) +/* Interrupt on/off (0x500) */ +#define INT_ENABLE_BIT (0 << 0) +#define INT_DISABLE_BIT (1 << 0) +/* Interrupt mode (0x504) */ +#define INT_LEVEL_BIT (0 << 0) +#define INT_PULSE_BIT (1 << 0) + +/* Command Types */ +#define MFC_CHANNEL_SET 0 +#define MFC_CHANNEL_READ 1 +#define MFC_CHANNEL_END 2 +#define MFC_INIT_CODEC 3 +#define MFC_FRAME_RUN 4 +#define MFC_SLEEP 6 +#define MFC_WAKEUP 7 + +/* DPB Count */ +#define NUM_MPEG4_DPB 2 +#define NUM_POST_DPB 3 +#define NUM_VC1_DPB 4 + +#define ALIGN_TO_16B(x) ((((x) + (1 << 4) - 1) >> 4) << 4) +#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) +#define ALIGN_TO_64B(x) ((((x) + (1 << 6) - 1) >> 6) << 6) +#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) +#define ALIGN_TO_2KB(x) ((((x) + (1 << 11) - 1) >> 11) << 11) +#define ALIGN_TO_4KB(x) ((((x) + (1 << 12) - 1) >> 12) << 12) +#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) +#define ALIGN_TO_64KB(x) ((((x) + (1 << 16) - 1) >> 16) << 16) +#define ALIGN_TO_128KB(x) ((((x) + (1 << 17) - 1) >> 17) << 17) + +#define PIXEL_CACHE_ON_ONLY_P_PICTURE 0 +#define PIXEL_CACHE_ON_ONLY_B_PICTURE 1 +#define PIXEL_CACHE_ON_BOTH_P_B_PICTURE 2 +#define PIXEL_CACHE_DISABLE 3 + +#define BOUND_MEMORY_SIZE 921600 + +enum mfc_inst_state { + MFCINST_STATE_NULL = 0, + + /* Instance is created */ + MFCINST_STATE_OPENED = 10, + + /* channel_set and init_codec is completed */ + MFCINST_STATE_DEC_INITIALIZE = 20, + + MFCINST_STATE_DEC_EXE = 30, + MFCINST_STATE_DEC_EXE_DONE, + + /* Instance is initialized for encoding */ + MFCINST_STATE_ENC_INITIALIZE = 40, + MFCINST_STATE_ENC_EXE, + MFCINST_STATE_ENC_EXE_DONE +}; + +enum mfc_mem_type { + MEM_STRUCT_LINEAR = 0, + MEM_STRUCT_TILE_ENC = 3 /* 64x32 */ +}; + +enum mfc_dec_type { + SEQ_HEADER = 1, + FRAME = 2, + LAST_FRAME = 3, + INIT_BUFFER = 4, + FRAME_RUN_REALLOC = 5, +}; + +enum mfc_facade_cmd { + H2R_CMD_EMPTY = 0, + H2R_CMD_OPEN_INSTANCE = 1, + H2R_CMD_CLOSE_INSTANCE = 2, + H2R_CMD_SYS_INIT = 3, + H2R_CMD_SLEEP = 5, + H2R_CMD_WAKEUP = 6, +}; + +enum mfc_wait_done_type { + R2H_CMD_EMPTY = 0, + R2H_CMD_OPEN_INSTANCE_RET = 1, + R2H_CMD_CLOSE_INSTANCE_RET = 2, + R2H_CMD_ERROR_RET = 3, + R2H_CMD_SEQ_DONE_RET = 4, + R2H_CMD_FRAME_DONE_RET = 5, + R2H_CMD_SLICE_DONE_RET = 6, + R2H_CMD_ENC_COMPLETE_RET = 6, + R2H_CMD_SYS_INIT_RET = 8, + R2H_CMD_FW_STATUS_RET = 9, + R2H_CMD_SLEEP_RET = 10, + R2H_CMD_WAKEUP_RET = 11, + R2H_CMD_INIT_BUFFERS_RET = 15, + R2H_CMD_EDFU_INT_RET = 16, + R2H_CMD_DECODE_ERR_RET = 32 +}; + +enum mfc_display_status { + DECODING_ONLY = 0, + DECODING_DISPLAY = 1, + DISPLAY_ONLY = 2, + DECODING_EMPTY = 3 +}; + +/* In case of decoder */ +enum mfc_frame_type { + MFC_RET_FRAME_NOT_SET = 0, + MFC_RET_FRAME_I_FRAME = 1, + MFC_RET_FRAME_P_FRAME = 2, + MFC_RET_FRAME_B_FRAME = 3 +}; + +struct mfc_inst_ctx { + int InstNo; + unsigned int DPBCnt; + unsigned int totalDPBCnt; + unsigned int extraDPB; + unsigned int displayDelay; + unsigned int postEnable; + unsigned int endOfFrame; + unsigned int forceSetFrameType; + unsigned int img_width; + unsigned int img_height; + unsigned int dwAccess; /* for Power Management. */ + unsigned int IsPackedPB; + unsigned int interlace_mode; + unsigned int sliceEnable; + unsigned int crcEnable; + unsigned int widthFIMV1; + unsigned int heightFIMV1; + int mem_inst_no; + enum mfc_frame_type FrameType; + enum ssbsip_mfc_codec_type MfcCodecType; + enum mfc_inst_state MfcState; + unsigned int port0_mmap_size; + unsigned int codec_buff_paddr; + unsigned int pred_buff_paddr; + struct mfc_frame_buf_arg dec_dpb_buff_paddr; + unsigned int shared_mem_paddr; + unsigned int shared_mem_vaddr; + unsigned int IsStartedIFrame; + struct mfc_shared_mem shared_mem; + enum mfc_buffer_type buf_type; + unsigned int desc_buff_paddr; +}; + +int mfc_load_firmware(const unsigned char *data, size_t size); +bool mfc_cmd_reset(void); + +enum mfc_error_code mfc_init_hw(void); +enum mfc_error_code mfc_init_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +enum mfc_error_code mfc_exe_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +enum mfc_error_code mfc_init_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +enum mfc_error_code mfc_exe_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +enum mfc_error_code mfc_get_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +enum mfc_error_code mfc_set_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args); +enum mfc_error_code mfc_deinit_hw(struct mfc_inst_ctx *mfc_ctx); +enum mfc_error_code mfc_set_sleep(void); +enum mfc_error_code mfc_set_wakeup(void); + +int mfc_return_inst_no(int inst_no, enum ssbsip_mfc_codec_type codec_type); +int mfc_set_state(struct mfc_inst_ctx *ctx, enum mfc_inst_state state); +void mfc_init_mem_inst_no(void); +int mfc_get_mem_inst_no(void); +void mfc_return_mem_inst_no(int inst_no); +bool mfc_is_running(void); +bool is_dec_codec(enum ssbsip_mfc_codec_type codec_type); + + +#endif /* _MFC_OPR_H_ */ diff --git a/drivers/media/video/samsung/mfc50/mfc_shared_mem.c b/drivers/media/video/samsung/mfc50/mfc_shared_mem.c new file mode 100644 index 0000000..813c2db --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_shared_mem.c @@ -0,0 +1,123 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_shared_mem.c + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Key-Young Park, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.10.08 - Apply 9/30 firmware(Key Young, Park) + * 2009.11.06 - clean & invalidate shared mem area (Key Young, Park) + * + * 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/delay.h> +#include <linux/errno.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/io.h> +#include <asm/cacheflush.h> + +#include "mfc_shared_mem.h" +#include "mfc_logmsg.h" + +#define DEBUG_ENABLE 0 + +static inline void mfc_write_shared_mem_item(unsigned int host_wr_addr, unsigned int addr, unsigned int value) +{ + MEM_WRITE(host_wr_addr + addr, value); +} + +static inline unsigned int mfc_read_shared_mem_item(unsigned int host_wr_addr, unsigned int addr) +{ + return MEM_READ(host_wr_addr + addr); +} + +void mfc_write_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem) +{ + mfc_write_shared_mem_item(host_wr_addr, RC_CONTROL_ENABLE, 1);/* RC_CONTROL_CONFIG : enable (1), disable(0) */ + + mfc_write_shared_mem_item(host_wr_addr, SET_FRAME_TAG, shared_mem->set_frame_tag); + mfc_write_shared_mem_item(host_wr_addr, START_BYTE_NUM, shared_mem->start_byte_num); + mfc_write_shared_mem_item(host_wr_addr, EXT_ENC_CONTROL, shared_mem->ext_enc_control); + mfc_write_shared_mem_item(host_wr_addr, ENC_PARAM_CHANGE, shared_mem->enc_param_change); + mfc_write_shared_mem_item(host_wr_addr, VOP_TIMING, shared_mem->vop_timing); + mfc_write_shared_mem_item(host_wr_addr, HEC_PERIOD, shared_mem->hec_period); + mfc_write_shared_mem_item(host_wr_addr, P_B_FRAME_QP, shared_mem->P_B_frame_qp); + mfc_write_shared_mem_item(host_wr_addr, METADATA_ENABLE, shared_mem->metadata_enable); + mfc_write_shared_mem_item(host_wr_addr, EXT_METADATA_START_ADDR, shared_mem->ext_metadata_start_addr); + mfc_write_shared_mem_item(host_wr_addr, PUT_EXTRADATA, shared_mem->put_extradata); + mfc_write_shared_mem_item(host_wr_addr, DBG_INFO_INPUT0, shared_mem->dbg_info_input0); + mfc_write_shared_mem_item(host_wr_addr, DBG_INFO_INPUT1, shared_mem->dbg_info_input1); + mfc_write_shared_mem_item(host_wr_addr, ALLOCATED_LUMA_DPB_SIZE, shared_mem->allocated_luma_dpb_size); + mfc_write_shared_mem_item(host_wr_addr, ALLOCATED_CHROMA_DPB_SIZE, shared_mem->allocated_chroma_dpb_size); + mfc_write_shared_mem_item(host_wr_addr, ALLOCATED_MV_SIZE, shared_mem->allocated_mv_size); + mfc_write_shared_mem_item(host_wr_addr, P720_LIMIT_ENABLE, shared_mem->p720_limit_enable); + + dmac_flush_range((void *)host_wr_addr, (void *)host_wr_addr + SHARED_MEM_MAX); + +#if DEBUG_ENABLE + mfc_print_shared_mem(host_wr_addr); +#endif +} + +void mfc_read_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem) +{ + invalidate_kernel_vmap_range((void *)host_wr_addr, SHARED_MEM_MAX); + + shared_mem->extended_decode_status = mfc_read_shared_mem_item(host_wr_addr, EXTENEDED_DECODE_STATUS); + shared_mem->get_frame_tag_top = mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_TOP); + shared_mem->get_frame_tag_bot = mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_BOT); + shared_mem->pic_time_top = mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_TOP); + shared_mem->pic_time_bot = mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_BOT); + shared_mem->start_byte_num = mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM); + shared_mem->dec_frm_size = mfc_read_shared_mem_item(host_wr_addr, DEC_FRM_SIZE); + shared_mem->crop_info1 = mfc_read_shared_mem_item(host_wr_addr, CROP_INFO1); + shared_mem->crop_info2 = mfc_read_shared_mem_item(host_wr_addr, CROP_INFO2); + shared_mem->metadata_status = mfc_read_shared_mem_item(host_wr_addr, METADATA_STATUS); + shared_mem->metadata_display_index = mfc_read_shared_mem_item(host_wr_addr, METADATA_DISPLAY_INDEX); + shared_mem->dbg_info_output0 = mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT0); + shared_mem->dbg_info_output1 = mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT1); + +#if DEBUG_ENABLE + mfc_print_shared_mem(host_wr_addr); +#endif +} + +void mfc_print_shared_mem(unsigned int host_wr_addr) +{ + mfc_info("set_frame_tag = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, SET_FRAME_TAG)); + mfc_info("start_byte_num = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM)); + mfc_info("ext_enc_control = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, EXT_ENC_CONTROL)); + mfc_info("enc_param_change = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ENC_PARAM_CHANGE)); + mfc_info("vop_timing = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, VOP_TIMING)); + mfc_info("hec_period = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, HEC_PERIOD)); + mfc_info("p_b_frame_qp = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, P_B_FRAME_QP)); + mfc_info("metadata_enable = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_ENABLE)); + mfc_info("ext_metadata_start_addr= 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, EXT_METADATA_START_ADDR)); + mfc_info("put_extradata = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PUT_EXTRADATA)); + mfc_info("dbg_info_input0 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_INPUT0)); + mfc_info("dbg_info_input1 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_INPUT1)); + mfc_info("luma_dpb_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_LUMA_DPB_SIZE)); + mfc_info("chroma_dpb_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_CHROMA_DPB_SIZE)); + mfc_info("mv_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_MV_SIZE)); + mfc_info("extended_decode_status = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, EXTENEDED_DECODE_STATUS)); + mfc_info("get_frame_tag_top = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_TOP)); + mfc_info("get_frame_tag_bot = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_BOT)); + mfc_info("pic_time_top = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_TOP)); + mfc_info("pic_time_bot = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_BOT)); + mfc_info("start_byte_num = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM)); + mfc_info("dec_frm_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DEC_FRM_SIZE)); + mfc_info("crop_info1 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, CROP_INFO1)); + mfc_info("crop_info2 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, CROP_INFO2)); + mfc_info("metadata_status = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_STATUS)); + mfc_info("metadata_display_index = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_DISPLAY_INDEX)); + mfc_info("dbg_info_output0 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT0)); + mfc_info("dbg_info_output1 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT1)); + mfc_info("720p_limit_enable = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, P720_LIMIT_ENABLE)); + mfc_info("RC_CONTROL_ENABLE = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, RC_CONTROL_ENABLE)); +} diff --git a/drivers/media/video/samsung/mfc50/mfc_shared_mem.h b/drivers/media/video/samsung/mfc50/mfc_shared_mem.h new file mode 100644 index 0000000..ca86876 --- /dev/null +++ b/drivers/media/video/samsung/mfc50/mfc_shared_mem.h @@ -0,0 +1,97 @@ +/* + * drivers/media/video/samsung/mfc50/mfc_shared_mem.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * + * Key-Young Park, Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * Change Logs + * 2009.10.08 - Apply 9/30 firmware(Key Young, Park) + * 2009.11.06 - clean & invalidate shared mem area (Key Young, Park) + * + * 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 _MFC_SHARED_MEM_H_ +#define _MFC_SHARED_MEM_H_ + +#define MEM_WRITE(ADDR, VALUE) (*(volatile unsigned int *)(ADDR) = (VALUE)) +#define MEM_READ(ADDR) (*(volatile unsigned int *)(ADDR)) + +enum mfc_shared { + EXTENEDED_DECODE_STATUS = 0x0, + SET_FRAME_TAG = 0x4, + GET_FRAME_TAG_TOP = 0x8, + GET_FRAME_TAG_BOT = 0xC, + PIC_TIME_TOP = 0x10, + PIC_TIME_BOT = 0x14, + START_BYTE_NUM = 0x18, + DEC_FRM_SIZE = 0x1C, + CROP_INFO1 = 0x20, + CROP_INFO2 = 0x24, + EXT_ENC_CONTROL = 0x28, + ENC_PARAM_CHANGE = 0x2C, + VOP_TIMING = 0x30, + HEC_PERIOD = 0x34, + METADATA_ENABLE = 0x38, + METADATA_STATUS = 0x3C, + METADATA_DISPLAY_INDEX = 0x40, + EXT_METADATA_START_ADDR = 0x44, + PUT_EXTRADATA = 0x48, + DBG_INFO_OUTPUT0 = 0x4C, + DBG_INFO_OUTPUT1 = 0x50, + DBG_INFO_INPUT0 = 0x54, + DBG_INFO_INPUT1 = 0x58, + REF_L0_PHY_IDX = 0x5C, + REF_L1_PHY_IDX = 0x60, + ALLOCATED_LUMA_DPB_SIZE = 0x64, + ALLOCATED_CHROMA_DPB_SIZE = 0x68, + ALLOCATED_MV_SIZE = 0x6C, + P_B_FRAME_QP = 0x70, + RC_CONTROL_ENABLE = 0xA0, + P720_LIMIT_ENABLE = 0xB4, + SHARED_MEM_MAX = 0x1000, +}; + +struct mfc_shared_mem { + unsigned int num_dpb; + unsigned int allocated_dpb_size; + unsigned int extended_decode_status; + unsigned int set_frame_tag; + unsigned int get_frame_tag_top; + unsigned int get_frame_tag_bot; + unsigned int pic_time_top; + unsigned int pic_time_bot; + unsigned int start_byte_num; + unsigned int dec_frm_size; + unsigned int crop_info1; + unsigned int crop_info2; + unsigned int ext_enc_control; + unsigned int enc_param_change; + unsigned int vop_timing; + unsigned int hec_period; + unsigned int P_B_frame_qp; + unsigned int metadata_enable; + unsigned int metadata_status; + unsigned int metadata_display_index; + unsigned int ext_metadata_start_addr; + unsigned int put_extradata; + unsigned int dbg_info_output0; + unsigned int dbg_info_output1; + unsigned int dbg_info_input0; + unsigned int dbg_info_input1; + unsigned int ref_l0_phy_idx; + unsigned int ref_l1_phy_idx; + unsigned int allocated_luma_dpb_size; + unsigned int allocated_chroma_dpb_size; + unsigned int allocated_mv_size; + unsigned int p720_limit_enable; +}; + +void mfc_write_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem); +void mfc_read_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem); +void mfc_print_shared_mem(unsigned int host_wr_addr); +#endif 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..9ed45c0 --- /dev/null +++ b/drivers/media/video/samsung/tv20/s5p_stda_grp.c @@ -0,0 +1,1102 @@ +/* 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 + } + + (s5ptv_status.fb->var).bits_per_pixel = (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; +} + |