mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 21:22:09 -04:00
Merge "msm: camera: cpas: Add mechanism to check camnoc idle status" into camera-kernel.lnx.4.0
This commit is contained in:
commit
03e07e03dc
11 changed files with 126 additions and 0 deletions
|
|
@ -1544,6 +1544,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
|
|||
struct cam_cpas_private_soc *soc_private = NULL;
|
||||
int rc = 0;
|
||||
long result;
|
||||
int retry_camnoc_idle = 0;
|
||||
|
||||
if (!hw_priv || !stop_args) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
|
||||
|
|
@ -1597,6 +1598,18 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
|
|||
}
|
||||
}
|
||||
|
||||
if (cpas_core->internal_ops.qchannel_handshake) {
|
||||
rc = cpas_core->internal_ops.qchannel_handshake(
|
||||
cpas_hw, false);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"failed in qchannel_handshake rc=%d",
|
||||
rc);
|
||||
retry_camnoc_idle = 1;
|
||||
/* Do not return error, passthrough */
|
||||
}
|
||||
}
|
||||
|
||||
rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc);
|
||||
|
|
@ -1612,6 +1625,19 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
|
|||
atomic_read(&cpas_core->irq_count));
|
||||
}
|
||||
|
||||
/* try again incase camnoc is still not idle */
|
||||
if (cpas_core->internal_ops.qchannel_handshake &&
|
||||
retry_camnoc_idle) {
|
||||
rc = cpas_core->internal_ops.qchannel_handshake(
|
||||
cpas_hw, false);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"failed in qchannel_handshake rc=%d",
|
||||
rc);
|
||||
/* Do not return error, passthrough */
|
||||
}
|
||||
}
|
||||
|
||||
rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info,
|
||||
true, false);
|
||||
if (rc) {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ enum cam_cpas_access_type {
|
|||
* @power_off: Function pointer for hw core specific power off settings
|
||||
* @setup_qos_settings: Function pointer for hw to select a specific qos header
|
||||
* @print_poweron_settings: Function pointer for hw to print poweron settings
|
||||
* @qchannel_handshake: Function pointer for hw core specific qchannel
|
||||
* handshake settings
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_internal_ops {
|
||||
|
|
@ -85,6 +87,7 @@ struct cam_cpas_internal_ops {
|
|||
int (*setup_qos_settings)(struct cam_hw_info *cpas_hw,
|
||||
uint32_t selection_mask);
|
||||
int (*print_poweron_settings)(struct cam_hw_info *cpas_hw);
|
||||
int (*qchannel_handshake)(struct cam_hw_info *cpas_hw, bool power_on);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
#define CAM_CPAS_POLL_MIN_USECS 200
|
||||
/* Maximum usecs to sleep while polling */
|
||||
#define CAM_CPAS_POLL_MAX_USECS 250
|
||||
/* Number of times to retry while polling */
|
||||
#define CAM_CPAS_POLL_QH_RETRY_CNT 50
|
||||
|
||||
/**
|
||||
* enum cam_cpas_hw_type - Enum for CPAS HW type
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops)
|
|||
internal_ops->power_off = NULL;
|
||||
internal_ops->setup_qos_settings = NULL;
|
||||
internal_ops->print_poweron_settings = NULL;
|
||||
internal_ops->qchannel_handshake = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
#include "cam_req_mgr_workq.h"
|
||||
|
||||
struct cam_camnoc_info *camnoc_info;
|
||||
struct cam_cpas_camnoc_qchannel *qchannel_info;
|
||||
|
||||
|
||||
#define CAMNOC_SLAVE_MAX_ERR_CODE 7
|
||||
static const char * const camnoc_salve_err_code[] = {
|
||||
|
|
@ -818,11 +820,65 @@ static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
|
||||
bool power_on)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
|
||||
int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP];
|
||||
uint32_t mask = 0;
|
||||
uint32_t wait_data, qchannel_status, qdeny;
|
||||
int rc = 0;
|
||||
|
||||
if (reg_indx == -1)
|
||||
return -EINVAL;
|
||||
|
||||
if (!qchannel_info)
|
||||
return 0;
|
||||
|
||||
if (power_on) {
|
||||
/* wait for QACCEPTN in QCHANNEL status*/
|
||||
mask = BIT(0);
|
||||
wait_data = 1;
|
||||
} else {
|
||||
/* Clear the quiecience request in QCHANNEL ctrl*/
|
||||
cam_io_w_mb(0, soc_info->reg_map[reg_indx].mem_base +
|
||||
qchannel_info->qchannel_ctrl);
|
||||
/* wait for QACCEPTN and QDENY in QCHANNEL status*/
|
||||
mask = BIT(1) | BIT(0);
|
||||
wait_data = 0;
|
||||
}
|
||||
|
||||
rc = cam_io_poll_value_wmask(
|
||||
soc_info->reg_map[reg_indx].mem_base +
|
||||
qchannel_info->qchannel_status,
|
||||
wait_data, mask, CAM_CPAS_POLL_QH_RETRY_CNT,
|
||||
CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"camnoc idle sequence failed, qstat 0x%x",
|
||||
cam_io_r(soc_info->reg_map[reg_indx].mem_base +
|
||||
qchannel_info->qchannel_status));
|
||||
/* Do not return error, passthrough */
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
/* check if deny bit is set */
|
||||
qchannel_status = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base +
|
||||
qchannel_info->qchannel_status);
|
||||
qdeny = (qchannel_status & BIT(1));
|
||||
if (!power_on && qdeny)
|
||||
rc = -EBUSY;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
|
||||
struct cam_cpas_hw_caps *hw_caps)
|
||||
{
|
||||
int rc = 0;
|
||||
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
|
||||
qchannel_info = NULL;
|
||||
|
||||
CAM_DBG(CAM_CPAS,
|
||||
"hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d",
|
||||
|
|
@ -864,18 +920,23 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
|
|||
break;
|
||||
case CAM_CPAS_TITAN_580_V100:
|
||||
camnoc_info = &cam580_cpas100_camnoc_info;
|
||||
qchannel_info = &cam580_cpas100_qchannel_info;
|
||||
break;
|
||||
case CAM_CPAS_TITAN_540_V100:
|
||||
camnoc_info = &cam540_cpas100_camnoc_info;
|
||||
qchannel_info = &cam540_cpas100_qchannel_info;
|
||||
break;
|
||||
case CAM_CPAS_TITAN_520_V100:
|
||||
camnoc_info = &cam520_cpas100_camnoc_info;
|
||||
qchannel_info = &cam520_cpas100_qchannel_info;
|
||||
break;
|
||||
case CAM_CPAS_TITAN_545_V100:
|
||||
camnoc_info = &cam545_cpas100_camnoc_info;
|
||||
qchannel_info = &cam545_cpas100_qchannel_info;
|
||||
break;
|
||||
case CAM_CPAS_TITAN_570_V200:
|
||||
camnoc_info = &cam570_cpas200_camnoc_info;
|
||||
qchannel_info = &cam570_cpas200_qchannel_info;
|
||||
break;
|
||||
case CAM_CPAS_TITAN_680_V100:
|
||||
camnoc_info = &cam680_cpas100_camnoc_info;
|
||||
|
|
@ -961,6 +1022,7 @@ int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops)
|
|||
internal_ops->setup_qos_settings = cam_cpastop_setup_qos_settings;
|
||||
internal_ops->print_poweron_settings =
|
||||
cam_cpastop_print_poweron_settings;
|
||||
internal_ops->qchannel_handshake = cam_cpastop_qchannel_handshake;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,4 +356,16 @@ struct cam_cpas_work_payload {
|
|||
struct work_struct work;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_camnoc_qchannel : Cpas camnoc qchannel info
|
||||
*
|
||||
* @qchannel_ctrl: offset to configure to control camnoc qchannel interface
|
||||
* @qchannel_status: offset to read camnoc qchannel interface status
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_camnoc_qchannel {
|
||||
uint32_t qchannel_ctrl;
|
||||
uint32_t qchannel_status;
|
||||
};
|
||||
|
||||
#endif /* _CAM_CPASTOP_HW_H_ */
|
||||
|
|
|
|||
|
|
@ -237,4 +237,8 @@ static struct cam_camnoc_info cam520_cpas100_camnoc_info = {
|
|||
.errata_wa_list = NULL,
|
||||
};
|
||||
|
||||
static struct cam_cpas_camnoc_qchannel cam520_cpas100_qchannel_info = {
|
||||
.qchannel_ctrl = 0x14,
|
||||
.qchannel_status = 0x18,
|
||||
};
|
||||
#endif /* _CPASTOP_V520_100_H_ */
|
||||
|
|
|
|||
|
|
@ -238,4 +238,8 @@ static struct cam_camnoc_info cam540_cpas100_camnoc_info = {
|
|||
.errata_wa_list = NULL,
|
||||
};
|
||||
|
||||
static struct cam_cpas_camnoc_qchannel cam540_cpas100_qchannel_info = {
|
||||
.qchannel_ctrl = 0x14,
|
||||
.qchannel_status = 0x18,
|
||||
};
|
||||
#endif /* _CPASTOP_V540_100_H_ */
|
||||
|
|
|
|||
|
|
@ -315,4 +315,8 @@ static struct cam_camnoc_info cam545_cpas100_camnoc_info = {
|
|||
.errata_wa_list = NULL,
|
||||
};
|
||||
|
||||
static struct cam_cpas_camnoc_qchannel cam545_cpas100_qchannel_info = {
|
||||
.qchannel_ctrl = 0x14,
|
||||
.qchannel_status = 0x18,
|
||||
};
|
||||
#endif /* _CPASTOP_V545_100_H_ */
|
||||
|
|
|
|||
|
|
@ -881,4 +881,8 @@ static struct cam_camnoc_info cam570_cpas200_camnoc_info = {
|
|||
.errata_wa_list = &cam570_cpas200_errata_wa_list,
|
||||
};
|
||||
|
||||
static struct cam_cpas_camnoc_qchannel cam570_cpas200_qchannel_info = {
|
||||
.qchannel_ctrl = 0x5C,
|
||||
.qchannel_status = 0x60,
|
||||
};
|
||||
#endif /* _CPASTOP_V570_200_H_ */
|
||||
|
|
|
|||
|
|
@ -1043,5 +1043,9 @@ static struct cam_camnoc_info cam580_cpas100_camnoc_info = {
|
|||
.errata_wa_list = &cam580_cpas100_errata_wa_list,
|
||||
};
|
||||
|
||||
static struct cam_cpas_camnoc_qchannel cam580_cpas100_qchannel_info = {
|
||||
.qchannel_ctrl = 0x5C,
|
||||
.qchannel_status = 0x60,
|
||||
};
|
||||
#endif /* _CPASTOP_V580_100_H_ */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue