msm: camera: cpp: Add cpp bus error handler

Reset and halt the bus when bus hang with cpp timeout.

CRs-Fixed: 961394
Change-Id: Id3612b134e3db19f1f8e2e2b3b444f0b6284c4d1
Signed-off-by: Peter Liu <pingchie@codeaurora.org>
Signed-off-by: Rajakumar Govindaram <rajakuma@codeaurora.org>
This commit is contained in:
Peter Liu 2016-01-21 13:57:51 -08:00 committed by Gerrit - the friendly Code Review server
parent 6428373814
commit ea445a93a0
2 changed files with 86 additions and 0 deletions

View file

@ -102,6 +102,7 @@
#define IS_DEFAULT_OUTPUT_BUF_INDEX(index) \
((index == DEFAULT_OUTPUT_BUF_INDEX) ? 1 : 0)
static struct msm_cpp_vbif_data cpp_vbif;
static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
uint32_t buff_mgr_ops, uint32_t ids, void *arg);
@ -171,6 +172,26 @@ struct msm_cpp_timer_t {
struct msm_cpp_timer_t cpp_timer;
static void msm_cpp_set_vbif_reg_values(struct cpp_device *cpp_dev);
void msm_cpp_vbif_register_error_handler(void *dev,
enum cpp_vbif_client client,
int (*client_vbif_error_handler)(void *, uint32_t))
{
if (dev == NULL || client >= VBIF_CLIENT_MAX) {
pr_err("%s: Fail to register handler! dev = %p, client %d\n",
__func__, dev, client);
return;
}
if (client_vbif_error_handler != NULL) {
cpp_vbif.dev[client] = dev;
cpp_vbif.err_handler[client] = client_vbif_error_handler;
} else {
/* if handler = NULL, is unregister case */
cpp_vbif.dev[client] = NULL;
cpp_vbif.err_handler[client] = NULL;
}
}
static int msm_cpp_init_bandwidth_mgr(struct cpp_device *cpp_dev)
{
int rc = 0;
@ -1215,6 +1236,32 @@ end:
return rc;
}
int cpp_vbif_error_handler(void *dev, uint32_t vbif_error)
{
struct cpp_device *cpp_dev = NULL;
if (dev == NULL || vbif_error >= CPP_VBIF_ERROR_MAX) {
pr_err("failed: dev %p, vbif error %d\n", dev, vbif_error);
return -EINVAL;
}
cpp_dev = (struct cpp_device *) dev;
/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
pr_err("%s: before reset halt... read MMSS_A_CPP_IRQ_STATUS_0 = 0x%x",
__func__, msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
pr_err("%s: start reset bus bridge on FD + CPP!\n", __func__);
/* MMSS_A_CPP_RST_CMD_0 = 0x8, firmware reset = 0x3DF77 */
msm_camera_io_w(0x3DF77, cpp_dev->cpp_hw_base + 0x8);
/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
pr_err("%s: after reset halt... read MMSS_A_CPP_IRQ_STATUS_0 = 0x%x",
__func__, msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
return 0;
}
static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
int rc;
@ -1284,6 +1331,10 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
rc = -ENOMEM;
}
}
msm_cpp_vbif_register_error_handler(cpp_dev,
VBIF_CLIENT_CPP, cpp_vbif_error_handler);
mutex_unlock(&cpp_dev->mutex);
return 0;
}
@ -1383,6 +1434,9 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
}
}
/* unregister vbif error handler */
msm_cpp_vbif_register_error_handler(cpp_dev,
VBIF_CLIENT_CPP, NULL);
mutex_unlock(&cpp_dev->mutex);
return 0;
}
@ -1637,6 +1691,15 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
goto end;
}
pr_err("%s: handle vbif hang...\n", __func__);
for (i = 0; i < VBIF_CLIENT_MAX; i++) {
if (cpp_dev->vbif_data->err_handler[i] == NULL)
continue;
cpp_dev->vbif_data->err_handler[i](
cpp_dev->vbif_data->dev[i], CPP_VBIF_ERROR_HANG);
}
pr_debug("Reloading firmware %d\n", queue_len);
rc = cpp_load_fw(cpp_timer.data.cpp_dev,
cpp_timer.data.cpp_dev->fw_name_bin);
@ -4195,6 +4258,8 @@ static int cpp_probe(struct platform_device *pdev)
spin_lock_init(&cpp_timer.data.processed_frame_lock);
cpp_dev->pdev = pdev;
memset(&cpp_vbif, 0, sizeof(struct msm_cpp_vbif_data));
cpp_dev->vbif_data = &cpp_vbif;
cpp_dev->camss_cpp_base =
msm_camera_get_reg_base(pdev, "camss_cpp", true);

View file

@ -23,6 +23,7 @@
#include "msm_sd.h"
#include "cam_soc_api.h"
#include "cam_hw_ops.h"
#include <media/msmb_pproc.h>
/* hw version info:
31:28 Major version
@ -95,6 +96,22 @@
#define MSM_CPP_TX_FIFO_LEVEL 16
#define MSM_CPP_RX_FIFO_LEVEL 512
enum cpp_vbif_error {
CPP_VBIF_ERROR_HANG,
CPP_VBIF_ERROR_MAX,
};
enum cpp_vbif_client {
VBIF_CLIENT_CPP,
VBIF_CLIENT_FD,
VBIF_CLIENT_MAX,
};
struct msm_cpp_vbif_data {
int (*err_handler[VBIF_CLIENT_MAX])(void *, uint32_t);
void *dev[VBIF_CLIENT_MAX];
};
struct cpp_subscribe_info {
struct v4l2_fh *vfh;
uint32_t active;
@ -266,6 +283,7 @@ struct cpp_device {
uint32_t bus_master_flag;
uint32_t micro_reset;
struct msm_cpp_payload_params payload_params;
struct msm_cpp_vbif_data *vbif_data;
};
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
@ -274,5 +292,8 @@ int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name);
long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx);
void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev);
int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev);
void msm_cpp_vbif_register_error_handler(void *dev,
enum cpp_vbif_client client,
int (*client_vbif_error_handler)(void *, uint32_t));
#endif /* __MSM_CPP_H__ */