From d43c0f4f90faff6b4c61c3763649ec74e4dda237 Mon Sep 17 00:00:00 2001 From: Qiang Guo Date: Tue, 28 Sep 2021 18:02:51 +0800 Subject: [PATCH] camera: porting dw9781c ois porting: (CR) milanf: dw9781c ois bringup Change-Id: Ibc40c253f4e4d04df41feeda4af41829b53e906c Signed-off-by: Qiang Guo Reviewed-on: https://gerrit.mot.com/2078610 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Shanghui Zhang Reviewed-by: Bolei Shang Reviewed-by: XiaoFeng Wang Reviewed-by: Quanlin Zhu Reviewed-by: Zhuoran Xu Reviewed-by: Ji Zhao Submit-Approved: Jira Key --- drivers/Makefile | 1 + .../cam_sensor_module/cam_ois/cam_ois_core.c | 64 +++- .../cam_ois/cam_ois_dw9781.c | 324 ++++++++++++++++++ 3 files changed, 381 insertions(+), 8 deletions(-) create mode 100644 drivers/cam_sensor_module/cam_ois/cam_ois_dw9781.c diff --git a/drivers/Makefile b/drivers/Makefile index c2349c1f090e..47797e2972cb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -162,6 +162,7 @@ camera-$(CONFIG_SPECTRA_SENSOR) += \ cam_sensor_module/cam_ois/cam_ois_dev.o \ cam_sensor_module/cam_ois/cam_ois_core.o \ cam_sensor_module/cam_ois/cam_ois_soc.o \ + cam_sensor_module/cam_ois/cam_ois_dw9781.o \ cam_sensor_module/cam_sensor/cam_sensor_dev.o \ cam_sensor_module/cam_sensor/cam_sensor_core.o \ cam_sensor_module/cam_sensor/cam_sensor_soc.o \ diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index 4cde98f2ba6f..165376ff152f 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -15,6 +15,9 @@ #include "cam_common_util.h" #include "cam_packet_util.h" +extern int dw9781c_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize); +extern void dw9781_post_firmware_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize); + int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) { @@ -302,6 +305,13 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, i2c_list->i2c_settings.addr_type, i2c_list->i2c_settings.data_type, i2c_list->i2c_settings.reg_setting[i].delay); + if (rc == 1) { + CAM_ERR(CAM_OIS, + "i2c poll fails addr:data %x:%x", + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data); + return rc; + } if (rc < 0) { CAM_ERR(CAM_OIS, "i2c poll apply setting Fail"); @@ -390,6 +400,15 @@ static int cam_ois_fw_prog_download(struct cam_ois_ctrl_t *o_ctrl) return rc; } + if (strstr(o_ctrl->ois_name, "dw9781")) { + if (!dw9781c_check_fw_download(&(o_ctrl->io_master_info), fw->data, fw->size)) { + CAM_INFO(CAM_OIS, "Skip firmware download."); + release_firmware(fw); + return 0; + } + CAM_INFO(CAM_OIS, "Firmware download started."); + } + total_bytes = fw->size; if(o_ctrl->ois_fw_txn_data_sz == 0) txn_data_size = total_bytes; @@ -407,31 +426,55 @@ static int cam_ois_fw_prog_download(struct cam_ois_ctrl_t *o_ctrl) return -ENOMEM; } + CAM_DBG(CAM_OIS, "fw len: %d, addr_type: %d, data_type: %d, chunck: %d, ois_fw_data_type:%d", total_bytes, + i2c_reg_setting.addr_type, + i2c_reg_setting.data_type, + txn_data_size, + o_ctrl->ois_fw_data_type); + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (vaddr); for (total_idx = 0, ptr = (uint8_t *)fw->data; total_idx < total_bytes;) { - for(packet_idx = 0; - (packet_idx < txn_data_size) && (total_idx + packet_idx < total_bytes); - packet_idx++, ptr++) + for (packet_idx = 0; + (packet_idx < (txn_data_size/o_ctrl->ois_fw_data_type)) && (total_idx + (packet_idx*o_ctrl->ois_fw_data_type) < total_bytes); + packet_idx ++, ptr += o_ctrl->ois_fw_data_type) { int regAddrOffset = 0; if(o_ctrl->ois_fw_inc_addr == 1) - regAddrOffset = total_idx + packet_idx; + regAddrOffset = total_idx/o_ctrl->ois_fw_data_type + packet_idx; i2c_reg_setting.reg_setting[packet_idx].reg_addr = o_ctrl->opcode.prog + regAddrOffset; - i2c_reg_setting.reg_setting[packet_idx].reg_data = *ptr; + if (o_ctrl->ois_fw_data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + i2c_reg_setting.reg_setting[packet_idx].reg_data = (uint32_t)(*ptr << 8) | *(ptr+1); + } else { + i2c_reg_setting.reg_setting[packet_idx].reg_data = *ptr; + } i2c_reg_setting.reg_setting[packet_idx].delay = 0; i2c_reg_setting.reg_setting[packet_idx].data_mask = 0; + CAM_DBG(CAM_OIS, "OIS_FW Reg:[0x%04x]: 0x%04x P:0x%x", + i2c_reg_setting.reg_setting[packet_idx].reg_addr, + i2c_reg_setting.reg_setting[packet_idx].reg_data, + (ptr-(uint8_t *)fw->data)); } i2c_reg_setting.size = packet_idx; - rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), - &i2c_reg_setting, 1); + if (o_ctrl->ois_fw_inc_addr == 1) { + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 0); + } else { + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 1); + } if (rc < 0) { CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); goto release_firmware; } - total_idx += packet_idx; + total_idx += packet_idx*o_ctrl->ois_fw_data_type; + CAM_DBG(CAM_OIS, "packet_idx: %d, total_idx: %d", packet_idx, total_idx); + } + + if (strstr(o_ctrl->ois_name, "dw9781")) { + dw9781_post_firmware_download(&(o_ctrl->io_master_info), fw->data, fw->size); } release_firmware: @@ -461,6 +504,11 @@ static int cam_ois_fw_coeff_download(struct cam_ois_ctrl_t *o_ctrl) return -EINVAL; } + if (strstr(o_ctrl->ois_name, "dw9781")) { + CAM_DBG(CAM_OIS, "not need download coeff fw!"); + return 0; + } + snprintf(name_coeff, 32, "%s.coeff", o_ctrl->ois_name); fw_name_coeff = name_coeff; diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dw9781.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dw9781.c new file mode 100644 index 000000000000..752920e203c3 --- /dev/null +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dw9781.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2021 Motorola Mobility LLC. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "cam_ois_core.h" +#include "cam_ois_soc.h" +#include "cam_sensor_util.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" + +#define DW9781C_CHIP_ID_ADDRESS 0x7000 +#define DW9781C_CHECKSUM_ADDRESS 0x7007 +#define DW9781C_CHIP_ID 0x9781 +#define FW_VER_CURR_ADDR 0x7001 +#define FW_TYPE_ADDR 0x700D +#define SET_FW 0x8001 + +#define EOK 0 + +#define FW_VERSION_OFFSET 10235 +#define FW_CHECKSUM_OFFSET 10234 + +typedef struct +{ + unsigned int driverIc; + unsigned int size; + const uint16_t *fwContentPtr; + uint16_t version; + uint16_t checksum; +} FirmwareContex; + +static FirmwareContex g_dw9781FirmwareContext; + +static int32_t dw9781_cci_write(struct camera_io_master * io_master_info, uint16_t reg, uint16_t val) +{ + int32_t rc = 0; + struct cam_sensor_i2c_reg_array reg_setting; + struct cam_sensor_i2c_reg_setting wr_setting; + + reg_setting.reg_addr = reg; + reg_setting.reg_data = val; + reg_setting.delay = 0; + reg_setting.data_mask = 0; + wr_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + wr_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + wr_setting.reg_setting = ®_setting; + wr_setting.size = 1; + wr_setting.delay = 0; + rc = camera_io_dev_write(io_master_info, &wr_setting); + return rc; +} + +static int32_t dw9781_cci_read(struct camera_io_master * io_master_info, uint16_t reg, uint16_t *val) +{ + int32_t rc = 0; + uint32_t regVal = 0; + rc = camera_io_dev_read(io_master_info, reg, ®Val, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_WORD); + if (!rc) { + *val = (uint16_t)regVal; + } + return rc; +} + +static void dw9781_delay_ms(uint32_t ms) +{ + usleep_range(ms*1000, ms*1000+10); + return; +} + +void dw9781_ois_reset(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "[dw9781c_ois_reset] ois reset"); + dw9781_cci_write(io_master_info, 0xD002, 0x0001); /* DW9781_DBGc reset */ + dw9781_delay_ms(4); + dw9781_cci_write(io_master_info, 0xD001, 0x0001); /* Active mode (DSP ON) */ + dw9781_delay_ms(25); /* ST gyro - over wait 25ms, default Servo On */ + dw9781_cci_write(io_master_info, 0xEBF1, 0x56FA); /* User protection release */ +} + +void dw9781_ois_ready_check(struct camera_io_master * io_master_info) +{ + uint16_t fw_flag; + dw9781_cci_write(io_master_info, 0xD001, 0x0000); /* dsp off mode */ + dw9781_cci_write(io_master_info, 0xFAFA, 0x98AC); /* All protection(1) */ + dw9781_cci_write(io_master_info, 0xF053, 0x70BD); /* All protection(2) */ + dw9781_cci_read(io_master_info, 0xA7F9, &fw_flag); /* check checksum flag */ + CAM_DBG(CAM_OIS, "[dw9781c_ois_ready_check] checksum flag : 0x%04x", fw_flag); + if(fw_flag == 0xCC33) + { + CAM_DBG(CAM_OIS, "[dw9781c_ois_ready_check] checksum flag is ok"); + dw9781_ois_reset(io_master_info); /* ois reset */ + } else { + dw9781_cci_write(io_master_info, 0xD002, 0x0001); /* dw9781c reset */ + dw9781_delay_ms(4); + CAM_ERR(CAM_OIS, "[dw9781c_ois_ready_check] previous firmware download fail"); + } +} + +void dw9781_all_protection_release(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "[dw9781c_all_protection_release] execution"); + /* release all protection */ + dw9781_cci_write(io_master_info, 0xFAFA, 0x98AC); + dw9781_delay_ms(1); + dw9781_cci_write(io_master_info, 0xF053, 0x70BD); + dw9781_delay_ms(1); +} + +static uint16_t dw9781_fw_checksum_verify(struct camera_io_master * io_master_info) +{ + uint16_t data; + + /* FW checksum command */ + dw9781_cci_write(io_master_info, 0x7011, 0x2000); + /* command start */ + dw9781_cci_write(io_master_info, 0x7010, 0x8000); + dw9781_delay_ms(10); + /* calc the checksum to write the 0x7005 */ + dw9781_cci_read(io_master_info, 0x7005, &data); + CAM_DBG(CAM_OIS, "F/W Checksum calculated value : 0x%04X", data); + + return data; +} + +static int dw9781_erase_mtp_rewritefw(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "dw9781c erase for rewritefw starting.."); + + /* 512 byte page */ + dw9781_cci_write(io_master_info, 0xde03, 0x0027); + /* page erase */ + dw9781_cci_write(io_master_info, 0xde04, 0x0008); + dw9781_delay_ms(10); + + CAM_DBG(CAM_OIS, "dw9781c checksum flag erase : 0xCC33"); + return 0; +} + +static void dw9781_erase_mtp(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "[dw9781c_erase_mtp] start erasing firmware flash"); + /* 12c level adjust */ + dw9781_cci_write(io_master_info, 0xd005, 0x0001); + dw9781_cci_write(io_master_info, 0xdd03, 0x0002); + dw9781_cci_write(io_master_info, 0xdd04, 0x0002); + + /* 4k Sector_0 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0000); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_1 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0008); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_2 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0010); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_3 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0018); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_4 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0020); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + CAM_DBG(CAM_OIS, "[dw9781c_erase_mtp] complete erasing firmware flash"); +} + +static int dw9781_prepare_fw_download(struct camera_io_master * io_master_info) +{ + /* step 1: MTP Erase and DSP Disable for firmware 0x8000 write */ + /* step 2: MTP setup */ + /* step 3: firmware sequential write to flash */ + /* step 4: firmware sequential read from flash */ + /* step 5: firmware verify */ + dw9781_cci_write(io_master_info, 0xd001, 0x0000); + dw9781_all_protection_release(io_master_info); + dw9781_erase_mtp(io_master_info); + CAM_DBG(CAM_OIS, "[dw9781c_download_fw] start firmware download"); + return 0; +} + +int dw9781c_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize) +{ + uint8_t ret; + uint8_t needDownload = 0; + uint16_t fwchecksum = 0; + uint16_t first_chip_id = 0; + uint16_t chip_checksum = 0; + uint16_t second_chip_id = 0; + uint16_t fw_version_current = 0; + uint16_t fw_version_latest = 0; + + if (io_master_info == NULL) { + printk("FATAL: OIS CCI context error!!!"); + return -1; + } + + if (fwData == NULL || fwSize < FW_VERSION_OFFSET*sizeof(uint16_t)) { + printk("FATAL: firmware buffer(%p) is NULL or size(%d) abnormal!!!", fwData, fwSize); + return -1; + } + + g_dw9781FirmwareContext.driverIc = 0x9781; + g_dw9781FirmwareContext.fwContentPtr = (const uint16_t *)fwData; + g_dw9781FirmwareContext.size = fwSize; + g_dw9781FirmwareContext.version = *(g_dw9781FirmwareContext.fwContentPtr+FW_VERSION_OFFSET); + g_dw9781FirmwareContext.version = ((g_dw9781FirmwareContext.version << 8) & 0xff00) | + ((g_dw9781FirmwareContext.version >> 8) & 0xff); + g_dw9781FirmwareContext.checksum = *(g_dw9781FirmwareContext.fwContentPtr+FW_CHECKSUM_OFFSET); + g_dw9781FirmwareContext.checksum = ((g_dw9781FirmwareContext.checksum << 8) & 0xff00) | + ((g_dw9781FirmwareContext.checksum >> 8) & 0xff); + + dw9781_ois_ready_check(io_master_info); + + dw9781_cci_read(io_master_info, DW9781C_CHIP_ID_ADDRESS, &first_chip_id); + dw9781_cci_read(io_master_info, 0x7001, &chip_checksum); + CAM_DBG(CAM_OIS, "[dw9781c] FW_VER_PHONE_MAKER : 0x%x", chip_checksum); + dw9781_cci_read(io_master_info, 0x7002, &chip_checksum); + CAM_DBG(CAM_OIS, "[dw9781c] FW_DATE_PHONE_MAKER : 0x%x", chip_checksum); + + CAM_DBG(CAM_OIS, "[dw9781c] first_chip_id : 0x%x", first_chip_id); + if (first_chip_id != DW9781C_CHIP_ID) { /* first_chip_id verification failed */ + dw9781_all_protection_release(io_master_info); + dw9781_cci_read(io_master_info, 0xd060, &second_chip_id); /* second_chip_id: 0x0020 */ + if ( second_chip_id == 0x0020 ) /* Check the second_chip_id*/ + { + CAM_DBG(CAM_OIS, "[dw9781c] start flash download:: size:%d, version:0x%x", + g_dw9781FirmwareContext.size, g_dw9781FirmwareContext.version); + needDownload = 1; + ret = dw9781_prepare_fw_download(io_master_info); /* Need to forced update OIS firmware again. */ + } else { + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */ + CAM_ERR(CAM_OIS, "[dw9781c] second_chip_id check fail"); + CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode"); + return needDownload; + } + } else { + + + dw9781_cci_read(io_master_info, FW_VER_CURR_ADDR, &fw_version_current); + fw_version_latest = g_dw9781FirmwareContext.version; /*Firmware version read from file content.*/ + + CAM_DBG(CAM_OIS, "[dw9781c] fw_version_current = 0x%x, fw_version_latest = 0x%x", + fw_version_current, fw_version_latest); + + /* download firmware, check if need update, download firmware to flash */ + if (((fw_version_current & 0xFF) != (fw_version_latest & 0xFF))) { + + fwchecksum = dw9781_fw_checksum_verify(io_master_info); + if(fwchecksum != g_dw9781FirmwareContext.checksum) + { + needDownload = 1; + CAM_DBG(CAM_OIS, "[dw9781c] firmware checksum error 0x%04X, 0x%04X", + g_dw9781FirmwareContext.checksum, fwchecksum); + } + + if (needDownload) + { + CAM_DBG(CAM_OIS, "[dw9781c] start flash download:: size:%d, version:0x%x needDownload %d", + g_dw9781FirmwareContext.size, g_dw9781FirmwareContext.version, needDownload); + + ret = dw9781_prepare_fw_download(io_master_info); + CAM_DBG(CAM_OIS, "[dw9781c] flash download::vendor_dw9781c"); + if (ret != EOK) { + dw9781_erase_mtp_rewritefw(io_master_info); + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shut download mode */ + CAM_ERR(CAM_OIS, "[dw9781c] firmware download error, ret = 0x%x", ret); + CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode"); + needDownload = 1; + } + } else { + CAM_DBG(CAM_OIS, "[dw9781c] ois firmware version is updated, skip download"); + } + } else { + CAM_DBG(CAM_OIS, "[dw9781c] ois firmware version is updated, skip download"); + } + } + return needDownload; +} +EXPORT_SYMBOL(dw9781c_check_fw_download); + +void dw9781_post_firmware_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize) +{ + uint16_t fwchecksum = 0; + + g_dw9781FirmwareContext.checksum = *(g_dw9781FirmwareContext.fwContentPtr+FW_CHECKSUM_OFFSET); + g_dw9781FirmwareContext.checksum = ((g_dw9781FirmwareContext.checksum << 8) & 0xff00) | + ((g_dw9781FirmwareContext.checksum >> 8) & 0xff); + + dw9781_ois_ready_check(io_master_info); + + fwchecksum = dw9781_fw_checksum_verify(io_master_info); + if(fwchecksum != g_dw9781FirmwareContext.checksum) + { + CAM_ERR(CAM_OIS, "[dw9781c] firmware checksum error 0x%04X, 0x%04X", g_dw9781FirmwareContext.checksum, fwchecksum); + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */ + dw9781_delay_ms(100); + dw9781_cci_write(io_master_info, 0xd000, 0x0001); /* Standby mode */ + dw9781_delay_ms(100); + dw9781_all_protection_release(io_master_info); /* Disable write protect */ + dw9781_erase_mtp_rewritefw(io_master_info); + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */ + CAM_ERR(CAM_OIS, "[dw9781c] firmware download error"); + CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode"); + } else { + CAM_DBG(CAM_OIS, "[dw9781c] Firmware download succes..."); + } + + return; +} + +EXPORT_SYMBOL(dw9781_post_firmware_download);