From ea445a93a03fe68f643e18cfc7c87c8c1c28c225 Mon Sep 17 00:00:00 2001 From: Peter Liu Date: Thu, 21 Jan 2016 13:57:51 -0800 Subject: [PATCH] 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 Signed-off-by: Rajakumar Govindaram --- .../msm/camera_v2/pproc/cpp/msm_cpp.c | 65 +++++++++++++++++++ .../msm/camera_v2/pproc/cpp/msm_cpp.h | 21 ++++++ 2 files changed, 86 insertions(+) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 7e452e9e4ee2..51bf6f9df853 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -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); diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index f46cc10cef46..470c0cf1131b 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -23,6 +23,7 @@ #include "msm_sd.h" #include "cam_soc_api.h" #include "cam_hw_ops.h" +#include /* 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__ */