diff options
Diffstat (limited to 'drivers/media/video')
12 files changed, 320 insertions, 112 deletions
diff --git a/drivers/media/video/s5c73m3.c b/drivers/media/video/s5c73m3.c index ea07a34..5db5f7f 100644 --- a/drivers/media/video/s5c73m3.c +++ b/drivers/media/video/s5c73m3.c @@ -37,6 +37,7 @@ #endif #include <linux/regulator/machine.h> +#include <linux/leds-aat1290a.h> #include <media/s5c73m3_platform.h> #include "s5c73m3.h" @@ -163,6 +164,8 @@ static u8 sysfs_phone_fw[10] = {0,}; static u8 sysfs_sensor_type[15] = {0,}; static u8 sysfs_isp_core[10] = {0,}; static u8 data_memory[500000] = {0,}; +static u32 crc_table[256] = {0,}; +static int copied_fw_binary; static u16 isp_chip_info1; static u16 isp_chip_info2; @@ -312,6 +315,48 @@ static int s5c73m3_read(struct v4l2_subdev *sd, return err; } +static int s5c73m3_i2c_check_status_with_CRC(struct v4l2_subdev *sd) +{ + int err = 0; + int index = 0; + u16 status = 0; + u16 i2c_status = 0; + u16 i2c_seq_status = 0; + + do { + err = s5c73m3_read(sd, 0x0009, S5C73M3_STATUS, &status); + err = s5c73m3_read(sd, 0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + if (i2c_status & ERROR_STATUS_CHECK_BIN_CRC) { + cam_dbg("failed to check CRC value of ISP Ram\n"); + err = -1; + break; + } + + if (status == 0xffff) + break; + + index++; + udelay(500); + } while (index < 2000); /* 1 sec */ + + if (index >= 2000) { + err = s5c73m3_read(sd, 0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + err = s5c73m3_read(sd, 0x0009, + S5C73M3_I2C_SEQ_STATUS, &i2c_seq_status); + cam_dbg("TimeOut!! index:%d,status:%#x,i2c_stauts:%#x,i2c_seq_status:%#x\n", + index, + status, + i2c_status, + i2c_seq_status); + + err = -1; + } + + return err; +} + static int s5c73m3_i2c_check_status(struct v4l2_subdev *sd) { int err = 0; @@ -346,6 +391,46 @@ static int s5c73m3_i2c_check_status(struct v4l2_subdev *sd) return err; } +void s5c73m3_make_CRC_table(u32 *table, u32 id) +{ + u32 i, j, k; + + for(i = 0; i < 256; ++i) { + k = i; + for(j = 0; j < 8; ++j) { + if(k & 1) + k = (k >> 1) ^ id; + else + k >>= 1; + } + table[i] = k; + } +} + +static int s5c73m3_reset_module(struct v4l2_subdev *sd, bool powerReset) +{ + struct s5c73m3_state *state = to_state(sd); + int err = 0; + + cam_trace("E\n"); + + if (powerReset) { + err = state->pdata->power_on_off(0); + CHECK_ERR(err); + err = state->pdata->power_on_off(1); + CHECK_ERR(err); + } else { + err = state->pdata->is_isp_reset(); + CHECK_ERR(err); + } + err = s5c73m3_set_timing_register_for_vdd(sd); + CHECK_ERR(err); + + cam_trace("X\n"); + + return err; +} + static int s5c73m3_writeb(struct v4l2_subdev *sd, unsigned short addr, unsigned short data) { @@ -487,6 +572,27 @@ static int s5c73m3_get_sensor_fw_binary(struct v4l2_subdev *sd) mm_segment_t old_fs; long ret = 0; char fw_path[25] = {0,}; + u8 mem0 =0, mem1 = 0; + u32 CRC = 0; + u32 DataCRC = 0; + u32 IntOriginalCRC = 0; + u32 crc_index = 0; + int retryCnt = 2; + + if (state->sensor_fw[0] == 'O') { + sprintf(fw_path, "/data/cfw/SlimISP_G%c.bin", + state->sensor_fw[1]); + } else if (state->sensor_fw[0] == 'S') { + sprintf(fw_path, "/data/cfw/SlimISP_Z%c.bin", + state->sensor_fw[1]); + } else { + sprintf(fw_path, "/data/cfw/SlimISP_%c%c.bin", + state->sensor_fw[0], + state->sensor_fw[1]); + } + + /* Make CRC Table */ + s5c73m3_make_CRC_table((u32 *)&crc_table, 0xEDB88320); /*ARM go*/ err = s5c73m3_write(sd, 0x3000, 0x0004, 0xFFFF); @@ -554,32 +660,18 @@ static int s5c73m3_get_sensor_fw_binary(struct v4l2_subdev *sd) mdelay(200); - old_fs = get_fs(); - set_fs(KERNEL_DS); - - if (state->sensor_fw[0] == 'O') { - sprintf(fw_path, "/data/cfw/SlimISP_G%c.bin", - state->sensor_fw[1]); - } else if (state->sensor_fw[0] == 'S') { - sprintf(fw_path, "/data/cfw/SlimISP_Z%c.bin", - state->sensor_fw[1]); - } else { - sprintf(fw_path, "/data/cfw/SlimISP_%c%c.bin", - state->sensor_fw[0], - state->sensor_fw[1]); - } - - fp = filp_open(fw_path, O_WRONLY|O_CREAT, 0644); - if (IS_ERR(fp) || fp == NULL) { - cam_err("failed to open %s, err %ld\n", - fw_path, PTR_ERR(fp)); - err = -EINVAL; - goto out; - } +retry: + memset(data_memory, 0, sizeof(data_memory)); + mem0 =0, mem1 = 0; + CRC = 0; + DataCRC = 0; + IntOriginalCRC = 0; + crc_index = 0; /* SPI Copy mode ready I2C CMD */ err = s5c73m3_writeb(sd, 0x0924, 0x0000); CHECK_ERR(err); + cam_dbg("sent SPI ready CMD\n"); rxSize = 64*1024; mdelay(10); @@ -589,19 +681,72 @@ static int s5c73m3_get_sensor_fw_binary(struct v4l2_subdev *sd) state->sensor_size, rxSize); CHECK_ERR(err); - ret = vfs_write(fp, (char __user *)data_memory, - state->sensor_size, &fp->f_pos); + CRC = ~CRC; + for(crc_index = 0;crc_index < (state->sensor_size-4)/2;crc_index++) { + /*low byte*/ + mem0 = (unsigned char)(data_memory[crc_index*2] & 0x00ff); + /*high byte*/ + mem1 = (unsigned char)(data_memory[crc_index*2+1] & 0x00ff); + CRC = crc_table[(CRC ^ (mem0)) & 0xFF] ^ (CRC >> 8); + CRC = crc_table[(CRC ^ (mem1)) & 0xFF] ^ (CRC >> 8); + } + CRC = ~CRC; + + DataCRC = (CRC&0x000000ff)<<24; + DataCRC += (CRC&0x0000ff00)<<8; + DataCRC += (CRC&0x00ff0000)>>8; + DataCRC += (CRC&0xff000000)>>24; + cam_err("made CSC value by S/W = 0x%x\n", DataCRC); + + IntOriginalCRC = (data_memory[state->sensor_size-4]&0x00ff)<<24; + IntOriginalCRC += (data_memory[state->sensor_size-3]&0x00ff)<<16; + IntOriginalCRC += (data_memory[state->sensor_size-2]&0x00ff)<<8; + IntOriginalCRC += (data_memory[state->sensor_size-1]&0x00ff); + cam_err("Original CRC Int = 0x%x\n", IntOriginalCRC); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (IntOriginalCRC == DataCRC) { + fp = filp_open(fw_path, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (IS_ERR(fp) || fp == NULL) { + cam_err("failed to open %s, err %ld\n", + fw_path, PTR_ERR(fp)); + err = -EINVAL; + goto out; + } + + ret = vfs_write(fp, (char __user *)data_memory, + state->sensor_size, &fp->f_pos); + + if (camfw_info[S5C73M3_SD_CARD].opened == 0) { + memcpy(state->phone_fw, + state->sensor_fw, + S5C73M3_FW_VER_LEN); + state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; + + memcpy(sysfs_phone_fw, + state->phone_fw, + sizeof(state->phone_fw)); + cam_dbg("Changed to Phone_version = %s\n", + state->phone_fw); + } + } else { + if (retryCnt > 0) { + set_fs(old_fs); + retryCnt--; + goto retry; + } + } if (fp != NULL) filp_close(fp, current->files); out: set_fs(old_fs); - return err; } - static int s5c73m3_get_sensor_fw_version(struct v4l2_subdev *sd) { struct s5c73m3_state *state = to_state(sd); @@ -802,7 +947,6 @@ static int s5c73m3_get_phone_fw_version(struct v4l2_subdev *sd) int err = 0; int retVal = 0; int fw_requested = 1; - int copied_fw_binary = 0; if (state->sensor_fw[0] == 'O') { sprintf(fw_path, "SlimISP_G%c.bin", @@ -885,14 +1029,12 @@ request_fw: state->fw_index = S5C73M3_IN_DATA; } } else { - cam_dbg("get new fw to F-ROM : %s Version\n", + cam_dbg("can't open %s Ver. Firmware. so, download from F-ROM\n", state->sensor_fw); if (fw != NULL) release_firmware(fw); - retVal = state->pdata->is_isp_reset(); - CHECK_ERR(retVal); - retVal = s5c73m3_set_timing_register_for_vdd(sd); + retVal = s5c73m3_reset_module(sd, true); CHECK_ERR(retVal); retVal = s5c73m3_get_sensor_fw_binary(sd); CHECK_ERR(retVal); @@ -901,17 +1043,13 @@ request_fw: } } - if (copied_fw_binary) { + if (!copied_fw_binary) { memcpy(state->phone_fw, - state->sensor_fw, + camfw_info[state->fw_index].ver, S5C73M3_FW_VER_LEN); state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; - } else { - memcpy(state->phone_fw, - camfw_info[state->fw_index].ver, - S5C73M3_FW_VER_LEN); - state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; } + memcpy(sysfs_phone_fw, state->phone_fw, sizeof(state->phone_fw)); @@ -1049,10 +1187,11 @@ static int s5c73m3_check_fw_date(struct v4l2_subdev *sd) static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) { - struct s5c73m3_state *state = to_state(sd); int err, i; int retVal; + copied_fw_binary = 0; + if (!download) { for (i = 0; i < S5C73M3_PATH_MAX; i++) camfw_info[i].opened = 0; @@ -1065,16 +1204,22 @@ static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) } retVal = s5c73m3_check_fw_date(sd); - err = state->pdata->is_isp_reset(); - CHECK_ERR(err); - err = s5c73m3_set_timing_register_for_vdd(sd); - CHECK_ERR(err); /* retVal = 0 : Same Version - retVal < 0 : Phone Version is latest Version than sensorFW. - retVal > 0 : Sensor Version is latest version than phoenFW. */ - if (retVal <= 0 || download) { + retVal < 0 : Phone Version is latest Version than sensorFW. + retVal > 0 : Sensor Version is latest version than phoenFW. */ + if (retVal <= 0||download) { cam_dbg("Loading From PhoneFW......\n"); + + /* In case that there is no FW in phone and FW needs to be + downloaded from F-ROM, ISP power reset is required before + loading FW to ISP for F-ROM to work properly.*/ + if (copied_fw_binary) + err = s5c73m3_reset_module(sd, true); + else + err = s5c73m3_reset_module(sd, false); + CHECK_ERR(err); + err = s5c73m3_SPI_booting(sd); CHECK_ERR(err); @@ -1084,26 +1229,13 @@ static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) } } else { cam_dbg("Loading From SensorFW......\n"); -#if 0 - err = s5c73m3_SPI_booting_by_ISP(sd); + err = s5c73m3_reset_module(sd, true); CHECK_ERR(err); -#else err = s5c73m3_get_sensor_fw_binary(sd); CHECK_ERR(err); - - memcpy(state->phone_fw, - state->sensor_fw, - S5C73M3_FW_VER_LEN); - state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; - - memcpy(sysfs_phone_fw, - state->phone_fw, - sizeof(state->phone_fw)); - cam_dbg("Changed to Phone_version = %s\n", - state->phone_fw); -#endif } + return 0; } @@ -1927,6 +2059,27 @@ static int s5c73m3_aeawb_lock_unlock(struct v4l2_subdev *sd, int val) return 0; } +static void s5c73m3_wait_for_preflash_fire(struct v4l2_subdev *sd) +{ + u16 pre_flash = false; + u16 timeout_cnt = 0; + + do { + s5c73m3_read(sd, 0x0009, + S5C73M3_STILL_PRE_FLASH | 0x5000, &pre_flash); + if (pre_flash || timeout_cnt > 20) { + if (!pre_flash) { + cam_dbg("pre_Flash = %d, timeout_cnt = %d\n", + pre_flash, timeout_cnt); + } + break; + } else + timeout_cnt++; + + mdelay(15); + } while (1); +} + static int s5c73m3_start_capture(struct v4l2_subdev *sd, int val) { struct s5c73m3_state *state = to_state(sd); @@ -1940,7 +2093,7 @@ static int s5c73m3_start_capture(struct v4l2_subdev *sd, int val) if (!pre_flash) { err = s5c73m3_writeb(sd, S5C73M3_STILL_PRE_FLASH , S5C73M3_STILL_PRE_FLASH_FIRE); - msleep(100); + s5c73m3_wait_for_preflash_fire(sd); } err = s5c73m3_writeb(sd, S5C73M3_STILL_MAIN_FLASH , S5C73M3_STILL_MAIN_FLASH_FIRE); @@ -1954,7 +2107,7 @@ static int s5c73m3_start_capture(struct v4l2_subdev *sd, int val) if (isneed_flash) { err = s5c73m3_writeb(sd, S5C73M3_STILL_PRE_FLASH , S5C73M3_STILL_PRE_FLASH_FIRE); - msleep(100); + s5c73m3_wait_for_preflash_fire(sd); err = s5c73m3_writeb(sd, S5C73M3_STILL_MAIN_FLASH, S5C73M3_STILL_MAIN_FLASH_FIRE); @@ -3109,7 +3262,7 @@ static int s5c73m3_read_vdd_core(struct v4l2_subdev *sd) set_fs(KERNEL_DS); fp = filp_open(S5C73M3_CORE_VDD, - O_WRONLY|O_CREAT, 0666); + O_WRONLY|O_CREAT|O_TRUNC, 0644); if (IS_ERR(fp)) goto out; @@ -3197,34 +3350,31 @@ static int s5c73m3_init(struct v4l2_subdev *sd, u32 val) #endif CHECK_ERR(err); - err = s5c73m3_i2c_check_status(sd); + err = s5c73m3_i2c_check_status_with_CRC(sd); if (err < 0) { cam_err("ISP is not ready. retry loading fw!!\n"); /* retry */ retVal = s5c73m3_check_fw_date(sd); - err = state->pdata->is_isp_reset(); - CHECK_ERR(err); - err = s5c73m3_set_timing_register_for_vdd(sd); - CHECK_ERR(err); - /* retVal = 0 : Same Version retVal < 0 : Phone Version is latest Version than sensorFW. retVal > 0 : Sensor Version is latest version than phoenFW. */ if (retVal <= 0) { cam_dbg("Loading From PhoneFW......\n"); + err = s5c73m3_reset_module(sd, false); + CHECK_ERR(err); err = s5c73m3_SPI_booting(sd); CHECK_ERR(err); } else { cam_dbg("Loading From SensorFW......\n"); + err = s5c73m3_reset_module(sd, true); + CHECK_ERR(err); err = s5c73m3_get_sensor_fw_binary(sd); CHECK_ERR(err); } - } state->isp.bad_fw = 0; - s5c73m3_init_param(sd); return 0; @@ -3271,18 +3421,7 @@ static ssize_t s5c73m3_camera_rear_flash(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int err; - - if (buf[0] == '0') - err = s5c73m3_writeb(sd_internal, S5C73M3_FLASH_TORCH, - S5C73M3_FLASH_TORCH_OFF); - else - err = s5c73m3_writeb(sd_internal, S5C73M3_FLASH_TORCH, - S5C73M3_FLASH_TORCH_ON); - - CHECK_ERR(err); - - return count; + return aat1290a_power(dev, attr, buf, count); } static ssize_t s5c73m3_camera_isp_core_show(struct device *dev, diff --git a/drivers/media/video/s5c73m3.h b/drivers/media/video/s5c73m3.h index 97a697b..40d7eaf 100644 --- a/drivers/media/video/s5c73m3.h +++ b/drivers/media/video/s5c73m3.h @@ -450,10 +450,10 @@ struct s5c73m3_state { #define ERR_STATUS_FROM_INIT (1<<0x4) #define ERR_STATUS_I2C_CIS_STREAM_OFF (1<<0x5) #define ERR_STATUS_I2C_N_CMD_OVER (1<<0x6) -#define ERR_STATUS_I2C_N_CMD_MISMATCH0 (1<<0x7) -#define ERR_STATUS_I2C_N_CMD_MISMATCH1 (1<<0x8) -#define ERR_STATUS_EXCEPTION (1<<0x9) - +#define ERROR_STATUS_I2C_N_CMD_MISMATCH (1<<0x7) +#define ERROR_STATUS_CHECK_BIN_CRC (1<<0x8) +#define ERROR_STATUS_EXCEPTION (1<<0x9) +#define ERROR_STATUS_INIF_INIT_STATE (0x8) #ifdef CONFIG_VIDEO_S5C73M3_SPI extern int s5c73m3_spi_write(const u8 *addr, const int len, const int txSize); diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h index 97fc4cb..2d8f3b7 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h @@ -40,6 +40,7 @@ #define FIMG2D_BITBLT_BLIT _IOWR(FIMG2D_IOCTL_MAGIC, 0, struct fimg2d_blit) #define FIMG2D_BITBLT_SYNC _IOW(FIMG2D_IOCTL_MAGIC, 1, int) #define FIMG2D_BITBLT_VERSION _IOR(FIMG2D_IOCTL_MAGIC, 2, struct fimg2d_version) +#define FIMG2D_BITBLT_SECURE _IOW(FIMG2D_IOCTL_MAGIC, 3, unsigned int) struct fimg2d_version { unsigned int hw; @@ -483,8 +484,8 @@ struct fimg2d_control { struct resource *mem; void __iomem *regs; - bool err; int irq; + unsigned int secure; atomic_t nctx; atomic_t busy; atomic_t active; diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x.h b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x.h index 9165d6f..4bf8f74 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x.h +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x.h @@ -172,6 +172,7 @@ struct fimg2d_blend_coeff { enum fimg2d_coeff d_coeff; }; +void fimg2d4x_sw_reset(struct fimg2d_control *info); void fimg2d4x_reset(struct fimg2d_control *info); void fimg2d4x_enable_irq(struct fimg2d_control *info); void fimg2d4x_disable_irq(struct fimg2d_control *info); diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c index 9a4f8ad..fc6016c 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c @@ -38,7 +38,9 @@ static inline void fimg2d4x_blit_wait(struct fimg2d_control *info, struct fimg2d fimg2d_dump_command(cmd); if (!fimg2d4x_blit_done_status(info)) - info->err = true; /* device error */ + printk(KERN_ERR "[%s] G2D operation is not finished", __func__); + + fimg2d4x_sw_reset(info); } } @@ -63,19 +65,16 @@ void fimg2d4x_bitblt(struct fimg2d_control *info) fimg2d_clk_on(info); while (1) { + spin_lock(&info->bltlock); cmd = fimg2d_get_first_command(info); if (!cmd) { - spin_lock(&info->bltlock); atomic_set(&info->active, 0); spin_unlock(&info->bltlock); break; } + spin_unlock(&info->bltlock); ctx = cmd->ctx; - if (info->err) { - printk(KERN_ERR "[%s] device error\n", __func__); - goto blitend; - } atomic_set(&info->busy, 1); diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c index 8135ecd..4eb4d04 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c @@ -28,6 +28,17 @@ static const int msk_oprmode = (int)MSK_ARGB; static const int premult_round_mode = (int)PREMULT_ROUND_1; /* (A+1)*B) >> 8 */ static const int blend_round_mode = (int)BLEND_ROUND_0; /* (A+1)*B) >> 8 */ +void fimg2d4x_sw_reset(struct fimg2d_control *info) +{ + wr(FIMG2D_SOFT_RESET, FIMG2D_SOFT_RESET_REG); + /* turn off wince option */ + wr(0x0, FIMG2D_BLEND_FUNCTION_REG); + + /* set default repeat mode to reflect(mirror) */ + wr(FIMG2D_SRC_REPEAT_REFLECT, FIMG2D_SRC_REPEAT_MODE_REG); + wr(FIMG2D_MSK_REPEAT_REFLECT, FIMG2D_MSK_REPEAT_MODE_REG); +} + void fimg2d4x_reset(struct fimg2d_control *info) { #ifdef SOFT_RESET_ENABLED diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c index 26ea56b..eaa722c 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c @@ -295,16 +295,20 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx, if (copy_from_user(&cmd->image[i], buf[i], sizeof(struct fimg2d_image))) { if ((blit->dst) && (type == ADDR_USER)) - if (!down_write_trylock(&page_alloc_slow_rwsem)) - return -EAGAIN; + if (!down_write_trylock(&page_alloc_slow_rwsem)) { + ret = -EAGAIN; + goto err_user; + } ret = -EFAULT; goto err_user; } } if ((blit->dst) && (type == ADDR_USER)) - if (!down_write_trylock(&page_alloc_slow_rwsem)) - return -EAGAIN; + if (!down_write_trylock(&page_alloc_slow_rwsem)) { + ret = -EAGAIN; + goto err_user; + } cmd->ctx = ctx; cmd->op = blit->op; diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c index 6ae4d6e..ed14901 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c @@ -38,8 +38,14 @@ #include "fimg2d_clk.h" #include "fimg2d_ctx.h" #include "fimg2d_helper.h" +#include "fimg2d_cache.h" #define CTX_TIMEOUT msecs_to_jiffies(1000) +#define LV1_SHIFT 20 +#define LV2_BASE_MASK 0x3ff +#define LV2_PT_MASK 0xff000 +#define LV2_SHIFT 12 +#define LV1_DESC_MASK 0x3 static struct fimg2d_control *info; @@ -58,7 +64,13 @@ static DECLARE_WORK(fimg2d_work, fimg2d_worker); static irqreturn_t fimg2d_irq(int irq, void *dev_id) { fimg2d_debug("irq\n"); - info->stop(info); + if (!atomic_read(&info->clkon)) { + fimg2d_clk_on(info); + info->stop(info); + fimg2d_clk_off(info); + } else { + info->stop(info); + } return IRQ_HANDLED; } @@ -67,6 +79,8 @@ static int fimg2d_sysmmu_fault_handler(enum S5P_SYSMMU_INTERRUPT_TYPE itype, unsigned long pgtable_base, unsigned long fault_addr) { struct fimg2d_bltcmd *cmd; + unsigned long *pgd; + unsigned long *lv1d, *lv2d; if (itype == SYSMMU_PAGEFAULT) { printk(KERN_ERR "[%s] sysmmu page fault(0x%lx), pgd(0x%lx)\n", @@ -91,11 +105,20 @@ static int fimg2d_sysmmu_fault_handler(enum S5P_SYSMMU_INTERRUPT_TYPE itype, fimg2d_dump_command(cmd); + pgd = (unsigned long *)cmd->ctx->mm->pgd; + lv1d = pgd + (fault_addr >> LV1_SHIFT); + printk(KERN_ERR " Level 1 descriptor(0x%lx)\n", *lv1d); + if ((*lv1d & LV1_DESC_MASK) != 0x1) { + fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4); + goto next; + } + + lv2d = (unsigned long *)phys_to_virt(*lv1d & ~LV2_BASE_MASK) + + ((fault_addr & LV2_PT_MASK) >> LV2_SHIFT); + printk(KERN_ERR " Level 2 descriptor(0x%lx)\n", *lv2d); + fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4); next: - fimg2d_clk_dump(info); - info->dump(info); - BUG(); return 0; } @@ -106,8 +129,6 @@ static void fimg2d_context_wait(struct fimg2d_context *ctx) atomic_set(&info->active, 1); queue_work(info->work_q, &fimg2d_work); printk(KERN_ERR "[%s] ctx %p cmd wait timeout\n", __func__, ctx); - if (info->err) - break; } } } @@ -188,11 +209,8 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case FIMG2D_BITBLT_BLIT: - if (info->err) { - printk(KERN_ERR "[%s] device error, do sw fallback\n", - __func__); + if (info->secure) return -EFAULT; - } if (copy_from_user(&blit, (void *)arg, sizeof(blit))) return -EFAULT; @@ -245,6 +263,24 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -EFAULT; break; + case FIMG2D_BITBLT_SECURE: + if (copy_from_user(&info->secure, + (unsigned int *)arg, + sizeof(unsigned int))) { + printk(KERN_ERR + "[%s] failed to FIMG2D_BITBLT_SECURE: copy_from_user error\n\n", + __func__); + return -EFAULT; + } + + while (1) { + if (fimg2d_queue_is_empty(&info->cmd_q)) + break; + mdelay(2); + } + + break; + default: printk(KERN_ERR "[%s] unknown ioctl\n", __func__); ret = -EFAULT; @@ -278,6 +314,7 @@ static int fimg2d_setup_controller(struct fimg2d_control *info) atomic_set(&info->busy, 0); atomic_set(&info->nctx, 0); atomic_set(&info->active, 0); + info->secure = 0; spin_lock_init(&info->bltlock); diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_notification.c b/drivers/media/video/samsung/mali/linux/mali_osk_notification.c index 74a18e8..eef839f 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_notification.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_notification.c @@ -15,6 +15,8 @@ #include "mali_osk.h" #include "mali_kernel_common.h" +#include "mali_pmm.h" +#include "mali_pmm_state.h" /* needed to detect kernel version specific code */ #include <linux/version.h> @@ -65,6 +67,11 @@ _mali_osk_notification_t *_mali_osk_notification_create( u32 type, u32 size ) /* OPT Recycling of notification objects */ _mali_osk_notification_wrapper_t *notification; + if (MALI_PMM_NOTIFICATION_TYPE == type) { + if (size != sizeof(mali_pmm_message_t)) + return NULL; + } + notification = (_mali_osk_notification_wrapper_t *)kmalloc( sizeof(_mali_osk_notification_wrapper_t) + size, GFP_KERNEL ); if (NULL == notification) { diff --git a/drivers/media/video/samsung/mfc5x/mfc_dec.c b/drivers/media/video/samsung/mfc5x/mfc_dec.c index 6e0645d..fd78b7d 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_dec.c +++ b/drivers/media/video/samsung/mfc5x/mfc_dec.c @@ -2388,6 +2388,12 @@ int mfc_exec_decoding(struct mfc_inst_ctx *ctx, union mfc_args *args) offset = CheckMPEG4StartCode(stream_vir+consumed, dec_ctx->streamsize - consumed); + + if (offset == -1) { + mfc_warn("No start code in remained bitstream: %d\n", offset); + return ret; + } + if (offset > 4) consumed += offset; diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c b/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c index 7af8a15..68508e7 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c @@ -953,8 +953,11 @@ static int s5p_tvout_tvif_release(struct file *file) tvout_dbg("on_stop_process(%d)\n", on_stop_process); atomic_dec(&s5p_tvout_v4l2_private.tvif_use); - if (atomic_read(&s5p_tvout_v4l2_private.tvif_use) == 0) + if (atomic_read(&s5p_tvout_v4l2_private.tvif_use) == 0) { + s5p_tvout_mutex_lock(); s5p_tvif_ctrl_stop(); + s5p_tvout_mutex_unlock(); + } on_stop_process = false; tvout_dbg("on_stop_process(%d)\n", on_stop_process); diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c index 323c13c..07fbd3f 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c @@ -142,10 +142,10 @@ static int os_allocate(void* ctx, ump_dd_mem * descriptor) if (is_cached) { - new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NORETRY | __GFP_NOWARN ); + new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN ); } else { - new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NORETRY | __GFP_NOWARN | __GFP_COLD); + new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN | __GFP_COLD); } if (NULL == new_page) { |