Эх сурвалжийг харах

msm: camera: sensor: Infrastructure to support OIS FW download V2

Add 16 bit data read/write. Add new FW information
cmd parser. Add new FW download v2. Force CCI burst/
sequential write to be queued into Q0.

CRs-Fixed: 3322287
External Impact: No.

Change-Id: I8a1ea42b01a3748f466a9bc6083a799b939e6d02
Signed-off-by: Yulei Yao <[email protected]>
Yulei Yao 2 жил өмнө
parent
commit
8202146af3

+ 7 - 2
drivers/cam_sensor_module/cam_cci/cam_cci_core.c

@@ -1910,8 +1910,6 @@ static int32_t cam_cci_write(struct v4l2_subdev *sd,
 			SYNC_QUEUE, MSM_SYNC_ENABLE);
 		break;
 	case MSM_CCI_I2C_WRITE:
-	case MSM_CCI_I2C_WRITE_SEQ:
-	case MSM_CCI_I2C_WRITE_BURST:
 		for (i = 0; i < NUM_QUEUES; i++) {
 			if (mutex_trylock(&cci_master_info->mutex_q[i])) {
 				rc = cam_cci_i2c_write(sd, c_ctrl, i,
@@ -1925,6 +1923,13 @@ static int32_t cam_cci_write(struct v4l2_subdev *sd,
 			PRIORITY_QUEUE, MSM_SYNC_DISABLE);
 		mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]);
 		break;
+	case MSM_CCI_I2C_WRITE_SEQ:
+	case MSM_CCI_I2C_WRITE_BURST:
+		mutex_lock(&cci_master_info->mutex_q[PRIORITY_QUEUE]);
+		rc = cam_cci_i2c_write(sd, c_ctrl,
+			PRIORITY_QUEUE, MSM_SYNC_DISABLE);
+		mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]);
+		break;
 	case MSM_CCI_I2C_WRITE_ASYNC:
 		rc = cam_cci_i2c_write_async(sd, c_ctrl,
 			PRIORITY_QUEUE, MSM_SYNC_DISABLE);

+ 583 - 39
drivers/cam_sensor_module/cam_ois/cam_ois_core.c

@@ -239,16 +239,34 @@ static int cam_ois_update_time(struct i2c_settings_array *i2c_set)
 		if (i2c_list->op_code ==  CAM_SENSOR_I2C_WRITE_SEQ) {
 			size = i2c_list->i2c_settings.size;
 			/* qtimer is 8 bytes so validate here*/
-			if (size < 8) {
+			if (size * (uint32_t)(i2c_list->i2c_settings.data_type) != 8) {
 				CAM_ERR(CAM_OIS, "Invalid write time settings");
 				return -EINVAL;
 			}
-			for (i = 0; i < size; i++) {
-				CAM_DBG(CAM_OIS, "time: reg_data[%d]: 0x%x",
-					i, (qtime_ns & 0xFF));
-				i2c_list->i2c_settings.reg_setting[i].reg_data =
-					(qtime_ns & 0xFF);
-				qtime_ns >>= 8;
+			switch (i2c_list->i2c_settings.data_type) {
+			case CAMERA_SENSOR_I2C_TYPE_BYTE:
+				for (i = 0; i < size; i++) {
+					CAM_DBG(CAM_OIS, "time: reg_data[%d]: 0x%x",
+						i, (qtime_ns & 0xFF));
+					i2c_list->i2c_settings.reg_setting[i].reg_data =
+						(qtime_ns & 0xFF);
+					qtime_ns >>= 8;
+				}
+
+				break;
+			case CAMERA_SENSOR_I2C_TYPE_WORD:
+				for (i = 0; i < size; i++) {
+					CAM_DBG(CAM_OIS, "time: reg_data[%d]: 0x%x",
+						i, (qtime_ns & 0xFFFF));
+					i2c_list->i2c_settings.reg_setting[i].reg_data =
+						(qtime_ns & 0xFFFF);
+					qtime_ns >>= 16;
+				}
+
+				break;
+			default:
+				CAM_ERR(CAM_OIS, "Unsupported reg data type!");
+				return -EINVAL;
 			}
 		}
 	}
@@ -356,6 +374,244 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl,
 	return rc;
 }
 
+static int cam_ois_parse_fw_setting(uint8_t *cmd_buf, uint32_t size,
+	struct i2c_settings_array *reg_settings)
+{
+	int32_t                 rc = 0;
+	uint32_t                byte_cnt = 0;
+	struct common_header   *cmm_hdr;
+	uint16_t                op_code;
+	uint32_t                j = 0;
+	struct list_head       *list = NULL;
+
+	while (byte_cnt < size) {
+		if ((size - byte_cnt) < sizeof(struct common_header)) {
+			CAM_ERR(CAM_SENSOR, "Not enough buffer");
+			rc = -EINVAL;
+			goto end;
+		}
+		cmm_hdr = (struct common_header *)cmd_buf;
+		op_code = cmm_hdr->fifth_byte;
+		CAM_DBG(CAM_SENSOR, "Command Type:%d, Op code:%d",
+				 cmm_hdr->cmd_type, op_code);
+
+		switch (cmm_hdr->cmd_type) {
+		case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: {
+			uint32_t cmd_length_in_bytes = 0;
+			struct cam_cmd_i2c_random_wr
+			*cam_cmd_i2c_random_wr =
+			(struct cam_cmd_i2c_random_wr *)cmd_buf;
+
+			if ((size - byte_cnt) < sizeof(struct cam_cmd_i2c_random_wr)) {
+				CAM_ERR(CAM_SENSOR,
+					"Not enough buffer provided,size %d,byte_cnt %d",
+					size, byte_cnt);
+				rc = -EINVAL;
+				goto end;
+			}
+
+			rc = cam_sensor_handle_random_write(
+				cam_cmd_i2c_random_wr,
+				reg_settings,
+				&cmd_length_in_bytes, &j, &list);
+			if (rc < 0) {
+				CAM_ERR(CAM_SENSOR,
+				"Failed in random write %d", rc);
+				goto end;
+			}
+
+			byte_cnt += sizeof(struct cam_cmd_i2c_random_wr);
+			cmd_buf += sizeof(struct cam_cmd_i2c_random_wr);
+
+			break;
+		}
+		case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR: {
+			uint32_t cmd_length_in_bytes = 0;
+			struct cam_cmd_i2c_continuous_wr
+			*cam_cmd_i2c_continuous_wr =
+			(struct cam_cmd_i2c_continuous_wr *)cmd_buf;
+
+			if ((size - byte_cnt) < sizeof(struct cam_cmd_i2c_continuous_wr)) {
+				CAM_ERR(CAM_SENSOR,
+					"Not enough buffer provided,size %d,byte_cnt %d",
+					size, byte_cnt);
+				rc = -EINVAL;
+				goto end;
+			}
+
+			rc = cam_sensor_handle_continuous_write(
+				cam_cmd_i2c_continuous_wr,
+				reg_settings,
+				&cmd_length_in_bytes, &j, &list);
+			if (rc < 0) {
+				CAM_ERR(CAM_SENSOR,
+				"Failed in continuous write %d", rc);
+				goto end;
+			}
+
+			byte_cnt += sizeof(struct cam_cmd_i2c_continuous_wr);
+			cmd_buf += sizeof(struct cam_cmd_i2c_continuous_wr);
+
+			break;
+		}
+		case CAMERA_SENSOR_CMD_TYPE_WAIT: {
+			if (op_code == CAMERA_SENSOR_WAIT_OP_HW_UCND ||
+				op_code == CAMERA_SENSOR_WAIT_OP_SW_UCND) {
+				if ((size - byte_cnt) <
+					sizeof(struct cam_cmd_unconditional_wait)) {
+					CAM_ERR(CAM_SENSOR,
+						"Not enough buffer provided,size %d,byte_cnt %d",
+						size, byte_cnt);
+					rc = -EINVAL;
+					goto end;
+				}
+
+				rc = cam_sensor_handle_delay(
+					(uint32_t **)(&cmd_buf), op_code,
+					reg_settings, j, &byte_cnt,
+					list);
+				if (rc < 0) {
+					CAM_ERR(CAM_SENSOR,
+						"delay hdl failed: %d",
+						rc);
+					goto end;
+				}
+			}
+			break;
+		}
+		case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_RD: {
+			uint16_t cmd_length_in_bytes = 0;
+			struct cam_cmd_i2c_random_rd *i2c_random_rd =
+			(struct cam_cmd_i2c_random_rd *)cmd_buf;
+
+			if ((size - byte_cnt) < sizeof(struct cam_cmd_i2c_random_rd)) {
+				CAM_ERR(CAM_SENSOR,
+					"Not enough buffer provided,size %d,byte_cnt %d",
+					size, byte_cnt);
+				rc = -EINVAL;
+				goto end;
+			}
+
+			rc = cam_sensor_handle_random_read(
+				i2c_random_rd,
+				reg_settings,
+				&cmd_length_in_bytes, &j, &list,
+				NULL);
+			if (rc < 0) {
+				CAM_ERR(CAM_SENSOR,
+				"Failed in random read %d", rc);
+				goto end;
+			}
+
+			byte_cnt += sizeof(struct cam_cmd_i2c_random_rd);
+			cmd_buf += sizeof(struct cam_cmd_i2c_random_rd);
+
+			break;
+		}
+		case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: {
+			uint16_t cmd_length_in_bytes = 0;
+			struct cam_cmd_i2c_continuous_rd
+			*i2c_continuous_rd =
+			(struct cam_cmd_i2c_continuous_rd *)cmd_buf;
+
+			if ((size - byte_cnt) < sizeof(struct cam_cmd_i2c_continuous_rd)) {
+				CAM_ERR(CAM_SENSOR,
+					"Not enough buffer provided,size %d,byte_cnt %d",
+					size, byte_cnt);
+				rc = -EINVAL;
+				goto end;
+			}
+
+			rc = cam_sensor_handle_continuous_read(
+				i2c_continuous_rd,
+				reg_settings,
+				&cmd_length_in_bytes, &j, &list,
+				NULL);
+			if (rc < 0) {
+				CAM_ERR(CAM_SENSOR,
+				"Failed in continuous read %d", rc);
+				goto end;
+			}
+
+			byte_cnt += sizeof(struct cam_cmd_i2c_continuous_rd);
+			cmd_buf += sizeof(struct cam_cmd_i2c_continuous_rd);
+
+			break;
+		}
+		default:
+			CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d",
+				 cmm_hdr->cmd_type);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+
+end:
+	return rc;
+}
+
+static int cam_ois_fw_info_pkt_parser(struct cam_ois_ctrl_t *o_ctrl,
+	uint32_t *cmd_buf, size_t len)
+{
+	int32_t                         rc = 0;
+	struct cam_cmd_ois_fw_info     *ois_fw_info;
+	uint8_t                        *pSettingData = NULL;
+	uint32_t                        size;
+	struct i2c_settings_array      *reg_settings = NULL;
+	uint8_t                         count = 0;
+	uint32_t                        idx;
+
+	if (!o_ctrl || !cmd_buf || len < sizeof(struct cam_cmd_ois_fw_info)) {
+		CAM_ERR(CAM_OIS, "Invalid Args,o_ctrl %p,cmd_buf %p,len %d",
+			o_ctrl, cmd_buf, len);
+		return -EINVAL;
+	}
+
+	ois_fw_info = (struct cam_cmd_ois_fw_info *)cmd_buf;
+	CAM_DBG(CAM_SENSOR, "fw_count %d, endianness %d",
+		ois_fw_info->fw_count, ois_fw_info->endianness);
+
+	if (ois_fw_info->fw_count <= MAX_OIS_FW_COUNT) {
+		memcpy(&o_ctrl->fw_info, ois_fw_info, sizeof(struct cam_cmd_ois_fw_info));
+		pSettingData = (uint8_t *)cmd_buf + sizeof(struct cam_cmd_ois_fw_info);
+
+		for (count = 0; count < ois_fw_info->fw_count*2; count++) {
+			idx = count / 2;
+			/* init settings */
+			if ((count & 0x1) == 0) {
+				size = ois_fw_info->fw_param[idx].fw_init_size;
+				reg_settings = &o_ctrl->i2c_fw_init_data[idx];
+				CAM_DBG(CAM_SENSOR, "init size %d", size);
+			/* finalize settings */
+			} else if ((count & 0x1) == 1) {
+				size = ois_fw_info->fw_param[idx].fw_finalize_size;
+				reg_settings = &o_ctrl->i2c_fw_finalize_data[idx];
+				CAM_DBG(CAM_SENSOR, "finalize size %d", size);
+			} else {
+				size = 0;
+				CAM_DBG(CAM_SENSOR, "Unsupported case!");
+				return -EINVAL;
+			}
+
+			if (size != 0) {
+				reg_settings->is_settings_valid = 1;
+				rc = cam_ois_parse_fw_setting(pSettingData, size, reg_settings);
+			}
+
+			if (rc) {
+				CAM_ERR(CAM_OIS, "Failed to parse fw setting!");
+				return rc;
+			}
+
+			pSettingData += size;
+		}
+	} else {
+		CAM_ERR(CAM_OIS, "Exceed max fw count!");
+	}
+
+	return rc;
+}
+
 static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl)
 {
 	uint16_t                           total_bytes = 0;
@@ -480,6 +736,207 @@ release_firmware:
 	return rc;
 }
 
+static inline uint32_t swap_high_byte_and_low_byte(uint8_t *src,
+	uint8_t data_type)
+{
+	uint32_t ret_value = 0x00;
+	uint8_t  cycle = 0;
+
+	for (cycle = 0; cycle < data_type; cycle++)
+		ret_value = ((ret_value<<8) | ((*(src+cycle))&0xff));
+
+	return ret_value;
+}
+
+static int write_ois_fw(uint8_t *fw_data, enum cam_endianness_type endianness,
+	struct cam_cmd_ois_fw_param *fw_param, struct camera_io_master io_master_info,
+	uint8_t i2c_operation)
+{
+	int32_t                             rc = 0;
+	struct cam_sensor_i2c_reg_setting   setting;
+	uint8_t                            *ptr = fw_data;
+	int32_t                             cnt = 0, wcnt = 0;
+	void                               *vaddr = NULL;
+	uint16_t                            data_type = fw_param->fw_data_type;
+	uint16_t                            len_per_write = fw_param->fw_len_per_write /
+								fw_param->fw_data_type;
+
+	vaddr = vmalloc((sizeof(struct cam_sensor_i2c_reg_array) * len_per_write));
+	if (!vaddr) {
+		CAM_ERR(CAM_OIS,
+			"Failed in allocating i2c_array: size: %u",
+			(sizeof(struct cam_sensor_i2c_reg_array) * len_per_write));
+		return -ENOMEM;
+	}
+
+	setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (vaddr);
+	setting.addr_type   = fw_param->fw_addr_type;
+	setting.data_type   = fw_param->fw_data_type;
+	setting.size        = len_per_write;
+	setting.delay       = fw_param->fw_delayUs;
+
+	for (wcnt = 0; wcnt < (fw_param->fw_size/data_type); wcnt += len_per_write) {
+		for (cnt = 0; cnt < len_per_write; cnt++, ptr += data_type) {
+			setting.reg_setting[cnt].reg_addr =
+				fw_param->fw_reg_addr + wcnt + cnt;
+			/* Big */
+			if (endianness == CAM_ENDIANNESS_BIG) {
+				setting.reg_setting[cnt].reg_data =
+					swap_high_byte_and_low_byte(ptr, data_type);
+			/* Little */
+			} else if (endianness == CAM_ENDIANNESS_LITTLE) {
+				switch (data_type) {
+				case CAMERA_SENSOR_I2C_TYPE_BYTE:
+					setting.reg_setting[cnt].reg_data = *((uint8_t *)ptr);
+					break;
+				case CAMERA_SENSOR_I2C_TYPE_WORD:
+					setting.reg_setting[cnt].reg_data = *((uint16_t *)ptr);
+					break;
+				default:
+					CAM_ERR(CAM_OIS,
+						"Unsupported data type");
+					rc = -EINVAL;
+					goto End;
+				}
+			}
+
+			setting.reg_setting[cnt].delay = fw_param->fw_delayUs;
+			setting.reg_setting[cnt].data_mask = 0;
+		}
+
+		if (i2c_operation == CAM_SENSOR_I2C_WRITE_RANDOM) {
+			rc = camera_io_dev_write(&(io_master_info),
+				&setting);
+		} else if (i2c_operation == CAM_SENSOR_I2C_WRITE_BURST ||
+			i2c_operation == CAM_SENSOR_I2C_WRITE_SEQ) {
+			rc = camera_io_dev_write_continuous(&io_master_info,
+				&setting, i2c_operation);
+		}
+
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS,
+				"Failed in Applying i2c wrt settings");
+			break;
+		}
+	}
+
+End:
+	vfree(vaddr);
+	vaddr = NULL;
+
+	return rc;
+}
+
+static int cam_ois_fw_download_v2(struct cam_ois_ctrl_t *o_ctrl)
+{
+	int32_t                             rc = 0;
+	struct cam_cmd_ois_fw_param        *fw_param = NULL;
+	uint32_t                            fw_size;
+	uint16_t                            len_per_write = 0;
+	uint8_t                            *ptr = NULL;
+	const struct firmware              *fw = NULL;
+	struct device                      *dev = &(o_ctrl->pdev->dev);
+	uint8_t                             count = 0;
+	uint8_t                             cont_wr_flag = 0;
+
+	if (!o_ctrl) {
+		CAM_ERR(CAM_OIS, "Invalid Args");
+		return -EINVAL;
+	}
+
+	for (count = 0; count < o_ctrl->fw_info.fw_count; count++) {
+		fw_param      = &o_ctrl->fw_info.fw_param[count];
+		fw_size       = fw_param->fw_size;
+		len_per_write = fw_param->fw_len_per_write / fw_param->fw_data_type;
+
+		CAM_DBG(CAM_OIS, "count: %d, fw_size: %d, data_type: %d, len_per_write: %d",
+			count, fw_size, fw_param->fw_data_type, len_per_write);
+
+		/* Load FW */
+		rc = request_firmware(&fw, fw_param->fw_name, dev);
+		if (rc) {
+			CAM_ERR(CAM_OIS, "Failed to locate %s", fw_param->fw_name);
+			return rc;
+		}
+
+		if (0 == rc && NULL != fw &&
+			(fw_size <= fw->size - fw_param->fw_start_pos)) {
+			/* fw init */
+			CAM_DBG(CAM_OIS, "fw init");
+			if (o_ctrl->i2c_fw_init_data[count].is_settings_valid == 1) {
+				rc = cam_ois_apply_settings(o_ctrl,
+					&o_ctrl->i2c_fw_init_data[count]);
+				if ((rc == -EAGAIN) &&
+					(o_ctrl->io_master_info.master_type == CCI_MASTER)) {
+					CAM_WARN(CAM_OIS,
+					"CCI HW is resetting: Reapplying FW init settings");
+					usleep_range(1000, 1010);
+					rc = cam_ois_apply_settings(o_ctrl,
+						&o_ctrl->i2c_fw_init_data[count]);
+				}
+				if (rc) {
+					CAM_ERR(CAM_OIS,
+						"Cannot apply FW init settings %d",
+						rc);
+					goto release_firmware;
+				} else {
+					CAM_DBG(CAM_OIS, "OIS FW init settings success");
+				}
+			}
+
+			/* send fw */
+			CAM_DBG(CAM_OIS, "send fw, operation %d", fw_param->fw_operation);
+
+			ptr = (uint8_t *)(fw->data + fw_param->fw_start_pos);
+			if (fw_param->fw_operation == CAMERA_SENSOR_I2C_OP_RNDM_WR)
+				cont_wr_flag = CAM_SENSOR_I2C_WRITE_RANDOM;
+			else if (fw_param->fw_operation == CAMERA_SENSOR_I2C_OP_CONT_WR_BRST)
+				cont_wr_flag = CAM_SENSOR_I2C_WRITE_BURST;
+			else if (fw_param->fw_operation == CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN)
+				cont_wr_flag = CAM_SENSOR_I2C_WRITE_SEQ;
+
+			write_ois_fw(ptr, o_ctrl->fw_info.endianness, fw_param,
+					o_ctrl->io_master_info, cont_wr_flag);
+
+			/* fw finalize */
+			CAM_DBG(CAM_OIS, "fw finalize");
+			if (o_ctrl->i2c_fw_finalize_data[count].is_settings_valid == 1) {
+				rc = cam_ois_apply_settings(o_ctrl,
+					&o_ctrl->i2c_fw_finalize_data[count]);
+				if ((rc == -EAGAIN) &&
+					(o_ctrl->io_master_info.master_type == CCI_MASTER)) {
+					CAM_WARN(CAM_OIS,
+					"CCI HW is resetting: Reapplying FW finalize settings");
+					usleep_range(1000, 1010);
+					rc = cam_ois_apply_settings(o_ctrl,
+						&o_ctrl->i2c_fw_finalize_data[count]);
+				}
+				if (rc) {
+					CAM_ERR(CAM_OIS,
+						"Cannot apply FW finalize settings %d",
+						rc);
+					goto release_firmware;
+				} else {
+					CAM_DBG(CAM_OIS, "OIS FW finalize settings success");
+				}
+			}
+		}
+
+		if (fw != NULL) {
+			release_firmware(fw);
+			fw = NULL;
+		}
+	}
+
+release_firmware:
+	if (fw != NULL) {
+		release_firmware(fw);
+		fw = NULL;
+	}
+
+	return rc;
+}
+
 /**
  * cam_ois_pkt_parse - Parse csl packet
  * @o_ctrl:     ctrl structure
@@ -543,13 +1000,13 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 
 	switch (csl_packet->header.op_code & 0xFFFFFF) {
 	case CAM_OIS_PACKET_OPCODE_INIT:
+		CAM_DBG(CAM_OIS, "CAM_OIS_PACKET_OPCODE_INIT,num_cmd_buf %d",
+			csl_packet->num_cmd_buf);
+
 		offset = (uint32_t *)&csl_packet->payload;
 		offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
 		cmd_desc = (struct cam_cmd_buf_desc *)(offset);
 
-		CAM_DBG(CAM_OIS, "num_cmd_buf %d",
-			csl_packet->num_cmd_buf);
-
 		/* Loop through multiple command buffers */
 		for (i = 0; i < csl_packet->num_cmd_buf; i++) {
 			total_cmd_buf_in_bytes = cmd_desc[i].length;
@@ -580,6 +1037,8 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 			cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
 			cmm_hdr = (struct common_header *)cmd_buf;
 
+			CAM_DBG(CAM_OIS,
+					"cmm_hdr->cmd_type: %d", cmm_hdr->cmd_type);
 			switch (cmm_hdr->cmd_type) {
 			case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
 				rc = cam_ois_slaveInfo_pkt_parser(
@@ -604,6 +1063,18 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 					return rc;
 				}
 				break;
+			case CAMERA_SENSOR_OIS_CMD_TYPE_FW_INFO:
+				CAM_DBG(CAM_OIS,
+					"Received fwInfo buffer,total_cmd_buf_in_bytes: %d",
+					total_cmd_buf_in_bytes);
+				rc = cam_ois_fw_info_pkt_parser(
+					o_ctrl, cmd_buf, total_cmd_buf_in_bytes);
+				if (rc) {
+					CAM_ERR(CAM_OIS,
+					"Failed: parse fw info settings");
+					return rc;
+				}
+				break;
 			default:
 			if (o_ctrl->i2c_init_data.is_settings_valid == 0) {
 				CAM_DBG(CAM_OIS,
@@ -649,9 +1120,8 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 					i2c_reg_settings,
 					&cmd_desc[i], 1, NULL);
 				if (rc < 0) {
-					CAM_ERR(CAM_OIS,
+					CAM_DBG(CAM_OIS,
 					"fw init parsing failed: %d", rc);
-					return rc;
 				}
 			}
 			break;
@@ -667,32 +1137,43 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 			o_ctrl->cam_ois_state = CAM_OIS_CONFIG;
 		}
 
-		if (o_ctrl->i2c_fwinit_data.is_settings_valid == 1) {
-			rc = cam_ois_apply_settings(o_ctrl,
-				&o_ctrl->i2c_fwinit_data);
-			if ((rc == -EAGAIN) &&
-				(o_ctrl->io_master_info.master_type == CCI_MASTER)) {
-				CAM_WARN(CAM_OIS,
-					"CCI HW is restting: Reapplying fwinit settings");
-				usleep_range(1000, 1010);
-				rc = cam_ois_apply_settings(o_ctrl,
-					&o_ctrl->i2c_fwinit_data);
-			}
-			if (rc) {
-				CAM_ERR(CAM_OIS,
-					"Cannot apply fwinit data %d",
-					rc);
-				goto pwr_dwn;
-			} else {
-				CAM_DBG(CAM_OIS, "OIS fwinit settings success");
-			}
-		}
-
+		CAM_DBG(CAM_OIS, "ois_fw_flag: %d", o_ctrl->ois_fw_flag);
 		if (o_ctrl->ois_fw_flag) {
-			rc = cam_ois_fw_download(o_ctrl);
-			if (rc) {
-				CAM_ERR(CAM_OIS, "Failed OIS FW Download");
-				goto pwr_dwn;
+			CAM_DBG(CAM_OIS, "fw_count: %d", o_ctrl->fw_info.fw_count);
+			if (o_ctrl->fw_info.fw_count != 0) {
+				rc = cam_ois_fw_download_v2(o_ctrl);
+				if (rc) {
+					CAM_ERR(CAM_OIS, "Failed OIS FW Download v2");
+					goto pwr_dwn;
+				}
+			} else {
+				if (o_ctrl->i2c_fwinit_data.is_settings_valid == 1) {
+					rc = cam_ois_apply_settings(o_ctrl,
+						&o_ctrl->i2c_fwinit_data);
+					if ((rc == -EAGAIN) &&
+						(o_ctrl->io_master_info.master_type ==
+							CCI_MASTER)) {
+						CAM_WARN(CAM_OIS,
+							"Reapplying fwinit settings");
+						usleep_range(1000, 1010);
+						rc = cam_ois_apply_settings(o_ctrl,
+							&o_ctrl->i2c_fwinit_data);
+					}
+					if (rc) {
+						CAM_ERR(CAM_OIS,
+							"Cannot apply fwinit data %d",
+							rc);
+						goto pwr_dwn;
+					} else {
+						CAM_DBG(CAM_OIS, "OIS fwinit settings success");
+					}
+
+					rc = cam_ois_fw_download(o_ctrl);
+					if (rc) {
+						CAM_ERR(CAM_OIS, "Failed OIS FW Download");
+						goto pwr_dwn;
+					}
+				}
 			}
 		}
 
@@ -705,6 +1186,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 			rc = cam_ois_apply_settings(o_ctrl,
 				&o_ctrl->i2c_init_data);
 		}
+
 		if (rc < 0) {
 			CAM_ERR(CAM_OIS,
 				"Cannot apply Init settings: rc = %d",
@@ -740,6 +1222,25 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 			rc = 0;
 		}
 
+		for (i = 0; i < MAX_OIS_FW_COUNT; i++) {
+			if (o_ctrl->i2c_fw_init_data[i].is_settings_valid == 1) {
+				rc = delete_request(&o_ctrl->i2c_fw_init_data[i]);
+				if (rc < 0) {
+					CAM_WARN(CAM_OIS,
+						"Fail deleting i2c_fw_init_data: rc: %d", rc);
+					rc = 0;
+				}
+			}
+			if (o_ctrl->i2c_fw_finalize_data[i].is_settings_valid == 1) {
+				rc = delete_request(&o_ctrl->i2c_fw_finalize_data[i]);
+				if (rc < 0) {
+					CAM_WARN(CAM_OIS,
+						"Fail deleting i2c_fw_finalize_data: rc: %d", rc);
+					rc = 0;
+				}
+			}
+		}
+
 		rc = delete_request(&o_ctrl->i2c_init_data);
 		if (rc < 0) {
 			CAM_WARN(CAM_OIS,
@@ -754,6 +1255,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 		}
 		break;
 	case CAM_OIS_PACKET_OPCODE_OIS_CONTROL:
+		CAM_DBG(CAM_OIS, "CAM_OIS_PACKET_OPCODE_OIS_CONTROL");
 		if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) {
 			rc = -EINVAL;
 			CAM_WARN(CAM_OIS,
@@ -793,6 +1295,8 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 		struct cam_buf_io_cfg *io_cfg;
 		struct i2c_settings_array i2c_read_settings;
 
+		CAM_DBG(CAM_OIS, "CAM_OIS_PACKET_OPCODE_READ");
+
 		if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) {
 			rc = -EINVAL;
 			CAM_WARN(CAM_OIS,
@@ -869,6 +1373,8 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 		break;
 	}
 	case CAM_OIS_PACKET_OPCODE_WRITE_TIME: {
+		CAM_DBG(CAM_OIS,
+				"CAM_OIS_PACKET_OPCODE_WRITE_TIME");
 		if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) {
 			rc = -EINVAL;
 			CAM_ERR(CAM_OIS,
@@ -925,7 +1431,7 @@ pwr_dwn:
 
 void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl)
 {
-	int rc = 0;
+	int rc = 0, i = 0;
 	struct cam_ois_soc_private *soc_private =
 		(struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private;
 	struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info;
@@ -952,6 +1458,25 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl)
 	if (o_ctrl->i2c_fwinit_data.is_settings_valid == 1)
 		delete_request(&o_ctrl->i2c_fwinit_data);
 
+	for (i = 0; i < MAX_OIS_FW_COUNT; i++) {
+		if (o_ctrl->i2c_fw_init_data[i].is_settings_valid == 1) {
+			rc = delete_request(&o_ctrl->i2c_fw_init_data[i]);
+			if (rc < 0) {
+				CAM_WARN(CAM_OIS,
+					"Fail deleting i2c_fw_init_data: rc: %d", rc);
+				rc = 0;
+			}
+		}
+		if (o_ctrl->i2c_fw_finalize_data[i].is_settings_valid == 1) {
+			rc = delete_request(&o_ctrl->i2c_fw_finalize_data[i]);
+			if (rc < 0) {
+				CAM_WARN(CAM_OIS,
+					"Fail deleting i2c_fw_finalize_data: rc: %d", rc);
+				rc = 0;
+			}
+		}
+	}
+
 	if (o_ctrl->i2c_mode_data.is_settings_valid == 1)
 		delete_request(&o_ctrl->i2c_mode_data);
 
@@ -980,7 +1505,7 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl)
  */
 int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 {
-	int                              rc = 0;
+	int                              rc = 0, i = 0;
 	struct cam_ois_query_cap_t       ois_cap = {0};
 	struct cam_control              *cmd = (struct cam_control *)arg;
 	struct cam_ois_soc_private      *soc_private = NULL;
@@ -1091,6 +1616,25 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg)
 		if (o_ctrl->i2c_fwinit_data.is_settings_valid == 1)
 			delete_request(&o_ctrl->i2c_fwinit_data);
 
+		for (i = 0; i < MAX_OIS_FW_COUNT; i++) {
+			if (o_ctrl->i2c_fw_init_data[i].is_settings_valid == 1) {
+				rc = delete_request(&o_ctrl->i2c_fw_init_data[i]);
+				if (rc < 0) {
+					CAM_WARN(CAM_OIS,
+						"Fail deleting i2c_fw_init_data: rc: %d", rc);
+					rc = 0;
+				}
+			}
+			if (o_ctrl->i2c_fw_finalize_data[i].is_settings_valid == 1) {
+				rc = delete_request(&o_ctrl->i2c_fw_finalize_data[i]);
+				if (rc < 0) {
+					CAM_WARN(CAM_OIS,
+						"Fail deleting i2c_fw_finalize_data: rc: %d", rc);
+					rc = 0;
+				}
+			}
+		}
+
 		break;
 	case CAM_STOP_DEV:
 		if (o_ctrl->cam_ois_state != CAM_OIS_START) {

+ 7 - 1
drivers/cam_sensor_module/cam_ois/cam_ois_dev.c

@@ -334,7 +334,7 @@ static int cam_ois_i2c_driver_remove(struct i2c_client *client)
 static int cam_ois_component_bind(struct device *dev,
 	struct device *master_dev, void *data)
 {
-	int32_t                         rc = 0;
+	int32_t                         rc = 0, i = 0;
 	struct cam_ois_ctrl_t          *o_ctrl = NULL;
 	struct cam_ois_soc_private     *soc_private = NULL;
 	bool                            i3c_i2c_target;
@@ -370,9 +370,15 @@ static int cam_ois_component_bind(struct device *dev,
 	o_ctrl->soc_info.soc_private = soc_private;
 	soc_private->power_info.dev  = &pdev->dev;
 
+	memset(&o_ctrl->fw_info, 0, sizeof(struct cam_cmd_ois_fw_info));
+
 	INIT_LIST_HEAD(&(o_ctrl->i2c_init_data.list_head));
 	INIT_LIST_HEAD(&(o_ctrl->i2c_calib_data.list_head));
 	INIT_LIST_HEAD(&(o_ctrl->i2c_fwinit_data.list_head));
+	for (i = 0; i < MAX_OIS_FW_COUNT; i++) {
+		INIT_LIST_HEAD(&(o_ctrl->i2c_fw_init_data[i].list_head));
+		INIT_LIST_HEAD(&(o_ctrl->i2c_fw_finalize_data[i].list_head));
+	}
 	INIT_LIST_HEAD(&(o_ctrl->i2c_mode_data.list_head));
 	INIT_LIST_HEAD(&(o_ctrl->i2c_time_data.list_head));
 	mutex_init(&(o_ctrl->ois_mutex));

+ 3 - 0
drivers/cam_sensor_module/cam_ois/cam_ois_dev.h

@@ -121,6 +121,9 @@ struct cam_ois_ctrl_t {
 	uint8_t ois_fw_flag;
 	uint8_t is_ois_calib;
 	struct cam_ois_opcode opcode;
+	struct cam_cmd_ois_fw_info fw_info;
+	struct i2c_settings_array i2c_fw_init_data[MAX_OIS_FW_COUNT];
+	struct i2c_settings_array i2c_fw_finalize_data[MAX_OIS_FW_COUNT];
 };
 
 /**

+ 3 - 3
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c

@@ -304,7 +304,7 @@ int32_t cam_sensor_handle_random_write(
 	return rc;
 }
 
-static int32_t cam_sensor_handle_continuous_write(
+int32_t cam_sensor_handle_continuous_write(
 	struct cam_cmd_i2c_continuous_wr *cam_cmd_i2c_continuous_wr,
 	struct i2c_settings_array *i2c_reg_settings,
 	uint32_t *cmd_length_in_bytes, int32_t *offset,
@@ -450,7 +450,7 @@ int32_t cam_sensor_util_write_qtimer_to_io_buffer(
 	return rc;
 }
 
-static int32_t cam_sensor_handle_random_read(
+int32_t cam_sensor_handle_random_read(
 	struct cam_cmd_i2c_random_rd *cmd_i2c_random_rd,
 	struct i2c_settings_array *i2c_reg_settings,
 	uint16_t *cmd_length_in_bytes,
@@ -498,7 +498,7 @@ static int32_t cam_sensor_handle_random_read(
 	return rc;
 }
 
-static int32_t cam_sensor_handle_continuous_read(
+int32_t cam_sensor_handle_continuous_read(
 	struct cam_cmd_i2c_continuous_rd *cmd_i2c_continuous_rd,
 	struct i2c_settings_array *i2c_reg_settings,
 	uint16_t *cmd_length_in_bytes, int32_t *offset,

+ 34 - 0
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h

@@ -52,6 +52,40 @@ int32_t cam_sensor_util_get_current_qtimer_ns(uint64_t *qtime_ns);
 int32_t cam_sensor_util_write_qtimer_to_io_buffer(
 	uint64_t qtime_ns, struct cam_buf_io_cfg *io_cfg);
 
+int32_t cam_sensor_handle_random_write(
+	struct cam_cmd_i2c_random_wr *cam_cmd_i2c_random_wr,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint32_t *cmd_length_in_bytes, int32_t *offset,
+	struct list_head **list);
+
+int32_t cam_sensor_handle_continuous_write(
+	struct cam_cmd_i2c_continuous_wr *cam_cmd_i2c_continuous_wr,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint32_t *cmd_length_in_bytes, int32_t *offset,
+	struct list_head **list);
+
+int32_t cam_sensor_handle_delay(
+	uint32_t **cmd_buf,
+	uint16_t generic_op_code,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint32_t offset, uint32_t *byte_cnt,
+	struct list_head *list_ptr);
+
+int32_t cam_sensor_handle_random_read(
+	struct cam_cmd_i2c_random_rd *cmd_i2c_random_rd,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint16_t *cmd_length_in_bytes,
+	int32_t *offset,
+	struct list_head **list,
+	struct cam_buf_io_cfg *io_cfg);
+
+int32_t cam_sensor_handle_continuous_read(
+	struct cam_cmd_i2c_continuous_rd *cmd_i2c_continuous_rd,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint16_t *cmd_length_in_bytes, int32_t *offset,
+	struct list_head **list,
+	struct cam_buf_io_cfg *io_cfg);
+
 int cam_sensor_i2c_command_parser(struct camera_io_master *io_master,
 	struct i2c_settings_array *i2c_reg_settings,
 	struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers,

+ 71 - 0
include/uapi/camera/media/cam_sensor.h

@@ -14,6 +14,7 @@
 #define CAM_SENSOR_PROBE_CMD      (CAM_COMMON_OPCODE_MAX + 1)
 #define CAM_FLASH_MAX_LED_TRIGGERS 2
 #define MAX_OIS_NAME_SIZE 32
+#define MAX_OIS_FW_COUNT  2
 #define CAM_CSIPHY_SECURE_MODE_ENABLED 1
 #define CAM_SENSOR_NAME_MAX_SIZE 32
 
@@ -57,6 +58,7 @@ enum camera_sensor_cmd_type {
 	CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET,
 	CAMERA_SENSOR_CMD_TYPE_RD_DATA,
 	CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE,
+	CAMERA_SENSOR_OIS_CMD_TYPE_FW_INFO,
 	CAMERA_SENSOR_CMD_TYPE_MAX,
 };
 
@@ -87,6 +89,8 @@ enum camera_sensor_i2c_op_code {
 	CAMERA_SENSOR_I2C_OP_CONT_WR_BRST_VERF,
 	CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN,
 	CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN_VERF,
+	CAMERA_SENSOR_I2C_OP_RNDM_RD,
+	CAMERA_SENSOR_I2C_OP_CONT_RD,
 	CAMERA_SENSOR_I2C_OP_MAX,
 };
 
@@ -120,6 +124,11 @@ enum cam_sensor_packet_opcodes {
 	CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP = 127,
 };
 
+enum cam_endianness_type {
+	CAM_ENDIANNESS_BIG,
+	CAM_ENDIANNESS_LITTLE,
+};
+
 enum tpg_command_type_t {
 	TPG_CMD_TYPE_INVALID = 0,
 	TPG_CMD_TYPE_GLOBAL_CONFIG,
@@ -394,6 +403,68 @@ struct cam_cmd_ois_info {
 	struct cam_ois_opcode opcode;
 } __attribute__((packed));
 
+
+/**
+ * struct cam_cmd_ois_fw_param - Contains OIS firmware param
+ *
+ * NOTE: if this struct is updated,
+ * please also update version in struct cam_cmd_ois_fw_info
+ *
+ * @fw_name         :       firmware file name
+ * @fw_start_pos    :       data start position in file
+ * @fw_size         :       firmware size
+ * @fw_len_per_write:       data length per write in bytes
+ * @fw_addr_type    :       addr type
+ * @fw_data_type    :       data type
+ * @fw_operation    :       type of operation
+ * @reserved        :       reserved for 32-bit alignment
+ * @fw_delayUs      :       delay in cci write
+ * @fw_reg_addr     :       start register addr to write
+ * @fw_init_size    :       size of fw download init settings
+ * @fw_finalize_size:       size of fw download finalize settings
+ */
+struct cam_cmd_ois_fw_param {
+	char        fw_name[MAX_OIS_NAME_SIZE];
+	__u32       fw_start_pos;
+	__u32       fw_size;
+	__u32       fw_len_per_write;
+	__u8        fw_addr_type;
+	__u8        fw_data_type;
+	__u8        fw_operation;
+	__u8        reserved;
+	__u32       fw_delayUs;
+	__u32       fw_reg_addr;
+	__u32       fw_init_size;
+	__u32       fw_finalize_size;
+} __attribute__((packed));
+
+/**
+ * struct cam_cmd_ois_fw_info - Contains OIS firmware info
+ *
+ * @version         :       version info
+ *                          NOTE: if struct cam_cmd_ois_fw_param is updated,
+ *                          version here needs to be updated too.
+ * @reserved        :       reserved
+ * @cmd_type        :       Explains type of command
+ * @fw_count        :       firmware count
+ * @endianness      :       firmware data's endianness
+ * @fw_param        :       includes firmware parameters
+ * @num_valid_params:       Number of valid params
+ * @param_mask      :       Mask to indicate fields in params
+ * @params          :       Additional Params
+ */
+struct cam_cmd_ois_fw_info {
+	__u32                           version;
+	__u8                            reserved;
+	__u8                            cmd_type;
+	__u8                            fw_count;
+	__u8                            endianness;
+	struct cam_cmd_ois_fw_param     fw_param[MAX_OIS_FW_COUNT];
+	__u32                           num_valid_params;
+	__u32                           param_mask;
+	__u32                           params[4];
+} __attribute__((packed));
+
 /**
  * struct cam_cmd_probe - Contains sensor slave info
  *