diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-diag.txt b/Documentation/devicetree/bindings/media/video/msm-cam-diag.txt new file mode 100644 index 000000000000..6dfe8ffac828 --- /dev/null +++ b/Documentation/devicetree/bindings/media/video/msm-cam-diag.txt @@ -0,0 +1,164 @@ +* Qualcomm Technologies, Inc. MSM Camera diag + +[Root level node] +================== +Required properties: +- compatible: Must be "qcom,diag-cam". + +[Subnode] +========== +Required properties: +- mmagic-supply: should contain mmagic regulator used for mmagic clocks. +- gdscr-supply: should contain gdsr regulator used for cci clocks. +- vfe0-vdd-supply: phandle to vfe0 regulator. +- qcom,cam-vreg-name: name of the voltage regulators required for the device. +- clocks: List of clock handles. The parent clocks of the input clocks to the + devices in this power domain are set to oscclk before power gating + and restored back after powering on a domain. This is required for + all domains which are powered on and off and not required for unused + domains. +- clock-names: name of the clock used by the driver. +- qcom,clock-rates: clock rate in Hz. +- qcom,clock-control: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property qcom,clock-rates. + +Example: + + qcom,diag-cam { + cell-index = <0>; + compatible = "qcom,diag-cam"; + status = "ok"; + mmagic-supply = <&gdsc_mmagic_camss>; + gdscr-supply = <&gdsc_camss_top>; + vfe0-vdd-supply = <&gdsc_vfe0>; + vfe1-vdd-supply = <&gdsc_vfe1>; + qcom,cam-vreg-name = "mmagic", "gdscr", + "vfe0-vdd", "vfe1-vdd"; + clocks = <&clock_mmss clk_mmss_mmagic_ahb_clk>, + <&clock_mmss clk_camss_top_ahb_clk>, + <&clock_mmss clk_camss_ispif_ahb_clk>, + <&clock_mmss clk_csi0phytimer_clk_src>, + <&clock_mmss clk_camss_csi0phytimer_clk>, + <&clock_mmss clk_camss_ahb_clk>, + <&clock_mmss clk_csi1phytimer_clk_src>, + <&clock_mmss clk_camss_csi1phytimer_clk>, + <&clock_mmss clk_csi2phytimer_clk_src>, + <&clock_mmss clk_camss_csi2phytimer_clk>, + <&clock_mmss clk_csi0_clk_src>, + <&clock_mmss clk_camss_csi0_clk>, + <&clock_mmss clk_camss_csi0phy_clk>, + <&clock_mmss clk_camss_csi0_ahb_clk>, + <&clock_mmss clk_camss_csi0rdi_clk>, + <&clock_mmss clk_camss_csi0pix_clk>, + <&clock_mmss clk_csi1_clk_src>, + <&clock_mmss clk_camss_csi1_clk>, + <&clock_mmss clk_camss_csi1phy_clk>, + <&clock_mmss clk_camss_csi1_ahb_clk>, + <&clock_mmss clk_camss_csi1rdi_clk>, + <&clock_mmss clk_camss_csi1pix_clk>, + <&clock_mmss clk_csi2_clk_src>, + <&clock_mmss clk_camss_csi2_clk>, + <&clock_mmss clk_camss_csi2phy_clk>, + <&clock_mmss clk_camss_csi2_ahb_clk>, + <&clock_mmss clk_camss_csi2rdi_clk>, + <&clock_mmss clk_camss_csi2pix_clk>, + <&clock_mmss clk_csi3_clk_src>, + <&clock_mmss clk_camss_csi3_clk>, + <&clock_mmss clk_camss_csi3phy_clk>, + <&clock_mmss clk_camss_csi3_ahb_clk>, + <&clock_mmss clk_camss_csi3rdi_clk>, + <&clock_mmss clk_camss_csi3pix_clk>, + <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_camss_vfe0_clk>, + <&clock_mmss clk_camss_csi_vfe0_clk>, + <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_camss_vfe1_clk>, + <&clock_mmss clk_camss_csi_vfe1_clk>, + <&clock_mmss clk_mmagic_camss_axi_clk>, + <&clock_mmss clk_camss_vfe_ahb_clk>, + <&clock_mmss clk_camss_vfe0_ahb_clk>, + <&clock_mmss clk_camss_vfe_axi_clk>, + <&clock_mmss clk_camss_vfe0_stream_clk>, + <&clock_mmss clk_smmu_vfe_axi_clk>, + <&clock_mmss clk_camss_vfe1_ahb_clk>, + <&clock_mmss clk_camss_vfe1_stream_clk>; + clock-names = + "clk_mmss_mmagic_ahb_clk", + "clk_camss_top_ahb_clk", + "clk_camss_ispif_ahb_clk", + "clk_csi0phytimer_clk_src", + "clk_camss_csi0phytimer_clk", + "clk_camss_ahb_clk", + "clk_csi1phytimer_clk_src", + "clk_camss_csi1phytimer_clk", + "clk_csi2phytimer_clk_src", + "clk_camss_csi2phytimer_clk", + "clk_csi0_clk_src", + "clk_camss_csi0_clk", + "clk_camss_csi0phy_clk", + "clk_camss_csi0_ahb_clk", + "clk_camss_csi0rdi_clk", + "clk_camss_csi0pix_clk", + "clk_csi1_clk_src", + "clk_camss_csi1_clk", + "clk_camss_csi1phy_clk", + "clk_camss_csi1_ahb_clk", + "clk_camss_csi1rdi_clk", + "clk_camss_csi1pix_clk", + "clk_csi2_clk_src", + "clk_camss_csi2_clk", + "clk_camss_csi2phy_clk", + "clk_camss_csi2_ahb_clk", + "clk_camss_csi2rdi_clk", + "clk_camss_csi2pix_clk", + "clk_csi3_clk_src", + "clk_camss_csi3_clk", + "clk_camss_csi3phy_clk", + "clk_camss_csi3_ahb_clk", + "clk_camss_csi3rdi_clk", + "clk_camss_csi3pix_clk", + "clk_vfe0_clk_src", + "clk_camss_vfe0_clk", + "clk_camss_csi_vfe0_clk", + "clk_vfe1_clk_src", + "clk_camss_vfe1_clk", + "clk_camss_csi_vfe1_clk", + "clk_mmagic_camss_axi_clk", + "clk_camss_vfe_ahb_clk", + "clk_camss_vfe0_ahb_clk", + "clk_camss_vfe_axi_clk", + "clk_camss_vfe0_stream_clk", + "clk_smmu_vfe_axi_clk", + "clk_camss_vfe1_ahb_clk", + "clk_camss_vfe1_stream_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + >; + qcom,clock-cntl-support; + qcom,clock-control = "NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE", + "INIT_RATE","NO_SET_RATE","NO_SET_RATE", + "INIT_RATE","NO_SET_RATE","INIT_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE", + "NO_SET_RATE","NO_SET_RATE","NO_SET_RATE"; + }; + diff --git a/drivers/media/platform/msm/ais/Makefile b/drivers/media/platform/msm/ais/Makefile index 4387b96f01d0..8c596dfcdcd8 100644 --- a/drivers/media/platform/msm/ais/Makefile +++ b/drivers/media/platform/msm/ais/Makefile @@ -22,4 +22,5 @@ obj-$(CONFIG_MSM_AIS_JPEG) += jpeg_10/ obj-$(CONFIG_MSM_AIS_JPEGDMA) += jpeg_dma/ obj-$(CONFIG_MSM_AIS) += msm_buf_mgr/ obj-$(CONFIG_MSM_AIS) += msm_ais_mgr/ +obj-$(CONFIG_MSM_AIS) += msm_ais_diag/ obj-$(CONFIG_MSM_AIS_FD) += fd/ diff --git a/drivers/media/platform/msm/ais/common/Makefile b/drivers/media/platform/msm/ais/common/Makefile index e1fa3f2ea848..1849d9c9af4c 100644 --- a/drivers/media/platform/msm/ais/common/Makefile +++ b/drivers/media/platform/msm/ais/common/Makefile @@ -1,2 +1,2 @@ ccflags-y += -Idrivers/media/platform/msm/ais/ -obj-$(CONFIG_MSM_AIS) += msm_camera_io_util.o cam_smmu_api.o cam_hw_ops.o cam_soc_api.o +obj-$(CONFIG_MSM_AIS) += msm_camera_io_util.o cam_smmu_api.o cam_hw_ops.o cam_soc_api.o msm_camera_diag_util.o diff --git a/drivers/media/platform/msm/ais/common/cam_hw_ops.c b/drivers/media/platform/msm/ais/common/cam_hw_ops.c index cf28e0ca6536..9110c88f9d8a 100644 --- a/drivers/media/platform/msm/ais/common/cam_hw_ops.c +++ b/drivers/media/platform/msm/ais/common/cam_hw_ops.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ #include #include #include "cam_hw_ops.h" +#include "msm_camera_diag_util.h" #ifdef CONFIG_CAM_AHB_DBG #define CDBG(fmt, args...) pr_err(fmt, ##args) @@ -242,6 +243,8 @@ static int cam_consolidate_ahb_vote(enum cam_ahb_clk_client id, data.ahb_clk_state = max; CDBG("dbg: state : %u, vector : %d\n", data.ahb_clk_state, max); + + msm_camera_diag_update_ahb_state(data.ahb_clk_state); } } else { pr_err("err: no bus vector found\n"); diff --git a/drivers/media/platform/msm/ais/common/cam_hw_ops.h b/drivers/media/platform/msm/ais/common/cam_hw_ops.h index 32f93f7b6e0e..e3e9f1381ad8 100644 --- a/drivers/media/platform/msm/ais/common/cam_hw_ops.h +++ b/drivers/media/platform/msm/ais/common/cam_hw_ops.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,16 +12,7 @@ #ifndef _CAM_HW_OPS_H_ #define _CAM_HW_OPS_H_ -enum cam_ahb_clk_vote { - /* need to update the voting requests - * according to dtsi entries. - */ - CAM_AHB_SUSPEND_VOTE = 0x0, - CAM_AHB_SVS_VOTE = 0x01, - CAM_AHB_NOMINAL_VOTE = 0x02, - CAM_AHB_TURBO_VOTE = 0x03, - CAM_AHB_DYNAMIC_VOTE = 0xFF, -}; +#include enum cam_ahb_clk_client { CAM_AHB_CLIENT_CSIPHY, diff --git a/drivers/media/platform/msm/ais/common/cam_soc_api.c b/drivers/media/platform/msm/ais/common/cam_soc_api.c index 92f3e4007390..520940c74d69 100644 --- a/drivers/media/platform/msm/ais/common/cam_soc_api.c +++ b/drivers/media/platform/msm/ais/common/cam_soc_api.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,6 +25,7 @@ #include #include #include "cam_soc_api.h" +#include "msm_camera_diag_util.h" struct msm_cam_bus_pscale_data { struct msm_bus_scale_pdata *pdata; @@ -374,6 +375,8 @@ int msm_camera_clk_enable(struct device *dev, if (clk_rate == 0) { clk_rate = clk_round_rate(clk_ptr[i], 0); + + if (clk_rate < 0) { pr_err("%s round rate failed\n", clk_info[i].clk_name); @@ -410,6 +413,8 @@ int msm_camera_clk_enable(struct device *dev, } } } + + msm_camera_diag_update_clklist(clk_info, clk_ptr, num_clk, enable); return rc; cam_clk_enable_err: diff --git a/drivers/media/platform/msm/ais/common/msm_camera_diag_util.c b/drivers/media/platform/msm/ais/common/msm_camera_diag_util.c new file mode 100644 index 000000000000..d4d417090210 --- /dev/null +++ b/drivers/media/platform/msm/ais/common/msm_camera_diag_util.c @@ -0,0 +1,364 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "msm_camera_diag_util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_camera_io_util.h" +#include "msm.h" + + +#define MAX_CLK_NUM 100 +struct camera_diag_clk_list { + struct msm_ais_diag_clk_info_t *clk_infolist; + struct clk **ppclk; + uint32_t clk_num; + uint32_t clk_capacity; + struct mutex lock; +}; + +struct camera_diag_ddrbw { + struct msm_ais_diag_bus_info_t bus_info; + struct mutex lock; +}; + +static struct camera_diag_clk_list s_diag_clk_list; +static struct camera_diag_ddrbw s_ddrbw; + +int msm_camera_get_reg_list(void __iomem *base, + struct msm_camera_reg_list_cmd *reg_list) +{ + int rc = 0; + uint32_t i; + uint32_t *reg_values = NULL; + uint32_t addrs_size = sizeof(uint32_t) * reg_list->reg_num; + uint32_t *reg_addrs = kzalloc(addrs_size, GFP_KERNEL); + + if (!reg_addrs) { + rc = -ENOMEM; + goto alloc_addr_failed; + } + + if (copy_from_user(reg_addrs, + (void __user *)(reg_list->regaddr_list), + sizeof(uint32_t) * reg_list->reg_num)) { + rc = -EFAULT; + pr_err("%s copy_from_user fail\n", __func__); + goto copy_addr_failed; + } + + reg_values = kzalloc(addrs_size, GFP_KERNEL); + if (!reg_values) { + rc = -ENOMEM; + goto copy_addr_failed; + } + + for (i = 0 ; i < reg_list->reg_num; ++i) { + reg_values[i] = msm_camera_io_r(base + reg_addrs[i]); + pr_debug("reg 0x%x 0x%x\n", + reg_addrs[i], + reg_values[i]); + } + + if (copy_to_user(reg_list->value_list, reg_values, + sizeof(uint32_t) * reg_list->reg_num)) { + rc = -EFAULT; + pr_err("%s copy_to_user fail %u\n", + __func__, + reg_list->reg_num); + goto copy_value_failed; + } + +copy_value_failed: + kfree(reg_values); + +copy_addr_failed: + kfree(reg_addrs); + +alloc_addr_failed: + + return rc; +} + +int msm_camera_diag_init(void) +{ + s_diag_clk_list.clk_num = 0; + s_diag_clk_list.clk_capacity = MAX_CLK_NUM; + s_diag_clk_list.clk_infolist = kzalloc( + sizeof(struct msm_ais_diag_clk_info_t) * + s_diag_clk_list.clk_capacity, + GFP_KERNEL); + + if (!s_diag_clk_list.clk_infolist) + return -ENOMEM; + + s_diag_clk_list.ppclk = kzalloc(sizeof(struct clk *) * + s_diag_clk_list.clk_capacity, + GFP_KERNEL); + if (!s_diag_clk_list.ppclk) { + kfree(s_diag_clk_list.clk_infolist); + return -ENOMEM; + } + + mutex_init(&s_diag_clk_list.lock); + mutex_init(&s_ddrbw.lock); + return 0; +} + +int msm_camera_diag_uninit(void) +{ + mutex_destroy(&s_ddrbw.lock); + mutex_destroy(&s_diag_clk_list.lock); + + kfree(s_diag_clk_list.clk_infolist); + s_diag_clk_list.clk_infolist = NULL; + + kfree(s_diag_clk_list.ppclk); + s_diag_clk_list.ppclk = NULL; + + return 0; +} + +static uint32_t msm_camera_diag_find_clk_idx( + struct msm_cam_clk_info *clk_info, + struct clk *clk_ptr) +{ + uint32_t i = 0; + + for (; i < s_diag_clk_list.clk_num; ++i) { + if (clk_ptr == s_diag_clk_list.ppclk[i]) + return i; + } + + return s_diag_clk_list.clk_capacity; +} + +int msm_camera_diag_update_clklist( + struct msm_cam_clk_info *clk_info, + struct clk **clk_ptr, int num_clk, int enable) +{ + uint32_t i = 0; + uint32_t idx = 0; + uint32_t actual_idx = 0; + struct msm_ais_diag_clk_info_t *pclk_info = NULL; + + mutex_lock(&s_diag_clk_list.lock); + for (; i < num_clk; ++i) { + idx = msm_camera_diag_find_clk_idx(&clk_info[i], clk_ptr[i]); + if (idx < s_diag_clk_list.clk_num) { + actual_idx = idx; + pclk_info = + &s_diag_clk_list.clk_infolist[actual_idx]; + } else if (s_diag_clk_list.clk_num < + s_diag_clk_list.clk_capacity) { + actual_idx = s_diag_clk_list.clk_num++; + memset(&s_diag_clk_list.clk_infolist[actual_idx], + 0, + sizeof(struct msm_ais_diag_clk_info_t)); + pclk_info = + &s_diag_clk_list.clk_infolist[actual_idx]; + memcpy(pclk_info->clk_name, + clk_info[i].clk_name, + sizeof(pclk_info->clk_name)); + s_diag_clk_list.ppclk[actual_idx] = clk_ptr[i]; + pr_debug("%s new clk %s clk_num %u\n", + __func__, + clk_info[i].clk_name, + s_diag_clk_list.clk_num); + } else { + pr_err("%s too many clks\n", __func__); + continue; + } + + pclk_info->clk_rate = clk_get_rate(clk_ptr[i]); + if (enable) { + ++pclk_info->enable; + } else { + int cnt = pclk_info->enable; + + if (cnt > 0) + --pclk_info->enable; + } + } + + mutex_unlock(&s_diag_clk_list.lock); + return 0; +} + +int msm_camera_diag_get_clk_list( + struct msm_ais_diag_clk_list_t *clk_infolist) +{ + int rc = 0; + + mutex_lock(&s_diag_clk_list.lock); + clk_infolist->clk_num = s_diag_clk_list.clk_num; + if (copy_to_user(clk_infolist->clk_info, + s_diag_clk_list.clk_infolist, + sizeof(struct msm_ais_diag_clk_info_t) * + s_diag_clk_list.clk_num)) { + rc = -EFAULT; + } + mutex_unlock(&s_diag_clk_list.lock); + return rc; +} + +int msm_camera_diag_get_gpio_list( + struct msm_ais_diag_gpio_list_t *gpio_list) +{ + int rc = 0; + uint32_t gpio_num = gpio_list->gpio_num; + uint32_t i = 0; + int32_t *vals = NULL; + uint32_t idxs_size = sizeof(uint32_t) * gpio_num; + uint32_t vals_size = sizeof(int32_t) * gpio_num; + uint32_t *idxs = kzalloc(idxs_size, GFP_KERNEL); + + if (!idxs) { + rc = -ENOMEM; + goto alloc_idxs_failed; + } + + if (copy_from_user(idxs, + (void __user *)(gpio_list->gpio_idx_list), + idxs_size)) { + rc = -EFAULT; + pr_err("%s copy_from_user fail\n", __func__); + goto copy_idxs_failed; + } + + vals = kzalloc(vals_size, GFP_KERNEL); + if (!vals) { + rc = -ENOMEM; + goto copy_idxs_failed; + } + + for (; i < gpio_num; ++i) + vals[i] = + gpio_get_value(idxs[i]); + + if (copy_to_user(gpio_list->gpio_val_list, vals, + vals_size)) { + rc = -EFAULT; + pr_err("%s copy_to_user fail %u\n", + __func__, + gpio_num); + } + + kfree(vals); + +copy_idxs_failed: + kfree(idxs); + +alloc_idxs_failed: + return rc; +} + +int msm_camera_diag_set_gpio_list( + struct msm_ais_diag_gpio_list_t *gpio_list) +{ + int rc = 0; + uint32_t gpio_num = gpio_list->gpio_num; + uint32_t i = 0; + int32_t val; + int32_t *vals = NULL; + uint32_t idxs_size = sizeof(uint32_t) * gpio_num; + uint32_t vals_size = sizeof(int32_t) * gpio_num; + uint32_t *idxs = kzalloc(idxs_size, GFP_KERNEL); + + if (!idxs) { + rc = -ENOMEM; + goto alloc_idxs_failed; + } + + if (copy_from_user(idxs, + (void __user *)(gpio_list->gpio_idx_list), + idxs_size)) { + rc = -EFAULT; + pr_err("%s copy_from_user fail\n", __func__); + goto copy_idxs_failed; + } + + vals = kzalloc(vals_size, GFP_KERNEL); + if (!vals) { + rc = -ENOMEM; + goto copy_idxs_failed; + } + + if (copy_from_user(vals, + (void __user *)(gpio_list->gpio_val_list), + vals_size)) { + rc = -EFAULT; + pr_err("%s copy_from_user fail\n", __func__); + goto copy_vals_failed; + } + + for (; i < gpio_num; ++i) { + gpio_set_value(idxs[i], vals[i]); + val = gpio_get_value(idxs[i]); + pr_debug("val set %d after %d\n", vals[i], val); + } + +copy_vals_failed: + kfree(vals); + +copy_idxs_failed: + kfree(idxs); + +alloc_idxs_failed: + return rc; +} + +int msm_camera_diag_update_ahb_state(enum cam_ahb_clk_vote vote) +{ + mutex_lock(&s_ddrbw.lock); + s_ddrbw.bus_info.ahb_clk_vote_state = vote; + mutex_unlock(&s_ddrbw.lock); + return 0; +} + +int msm_camera_diag_update_isp_state( + uint32_t isp_bus_vector_idx, + uint64_t isp_ab, uint64_t isp_ib) +{ + mutex_lock(&s_ddrbw.lock); + s_ddrbw.bus_info.isp_bus_vector_idx = isp_bus_vector_idx; + s_ddrbw.bus_info.isp_ab = isp_ab; + s_ddrbw.bus_info.isp_ib = isp_ib; + mutex_unlock(&s_ddrbw.lock); + return 0; +} + +int msm_camera_diag_get_ddrbw(struct msm_ais_diag_bus_info_t *info) +{ + int rc = 0; + + mutex_lock(&s_ddrbw.lock); + info->ahb_clk_vote_state = s_ddrbw.bus_info.ahb_clk_vote_state; + info->isp_bus_vector_idx = s_ddrbw.bus_info.isp_bus_vector_idx; + info->isp_ab = s_ddrbw.bus_info.isp_ab; + info->isp_ib = s_ddrbw.bus_info.isp_ib; + + mutex_unlock(&s_ddrbw.lock); + return rc; +} + + diff --git a/drivers/media/platform/msm/ais/common/msm_camera_diag_util.h b/drivers/media/platform/msm/ais/common/msm_camera_diag_util.h new file mode 100644 index 000000000000..1d4b09d726e6 --- /dev/null +++ b/drivers/media/platform/msm/ais/common/msm_camera_diag_util.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __MSM_CAMERA_DIAG_UTIL_H +#define __MSM_CAMERA_DIAG_UTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int msm_camera_get_reg_list(void __iomem *base, + struct msm_camera_reg_list_cmd *reg_list); +int msm_camera_diag_init(void); +int msm_camera_diag_uninit(void); + +int msm_camera_diag_update_clklist(struct msm_cam_clk_info *clk_info, + struct clk **clk_ptr, int num_clk, int enable); +int msm_camera_diag_get_clk_list( + struct msm_ais_diag_clk_list_t *clk_infolist); + +int msm_camera_diag_update_ahb_state(enum cam_ahb_clk_vote vote); +int msm_camera_diag_update_isp_state(uint32_t isp_bus_vector_idx, + uint64_t isp_ab, uint64_t isp_ib); +int msm_camera_diag_get_ddrbw(struct msm_ais_diag_bus_info_t *info); +int msm_camera_diag_get_gpio_list( + struct msm_ais_diag_gpio_list_t *gpio_list); +int msm_camera_diag_set_gpio_list( + struct msm_ais_diag_gpio_list_t *gpio_list); + +#endif diff --git a/drivers/media/platform/msm/ais/common/msm_camera_io_util.c b/drivers/media/platform/msm/ais/common/msm_camera_io_util.c index a09237f3d5ef..c6c2e0d02b65 100644 --- a/drivers/media/platform/msm/ais/common/msm_camera_io_util.c +++ b/drivers/media/platform/msm/ais/common/msm_camera_io_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ #include #include #include "msm_camera_io_util.h" +#include "msm_camera_diag_util.h" #define BUFF_SIZE_128 128 @@ -365,6 +366,8 @@ int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, } } } + + msm_camera_diag_update_clklist(clk_info, clk_ptr, num_clk, enable); return rc; diff --git a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c index 585865b12387..c23fddf6e52f 100644 --- a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1144,6 +1144,43 @@ static void msm_isp_release_all_bufq( } } +static int msm_isp_get_bufq_state(struct msm_isp_buf_mgr *buf_mgr, + struct msm_vfe_bufq_state *bufq_state) +{ + int rc = 0; + struct msm_isp_bufq *bufq = NULL; + uint32_t i = 0; + int32_t *k_bufq_states = NULL; + uint32_t size = 0; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_state->handle); + if (bufq) { + bufq_state->nbufs = bufq->num_bufs; + size = bufq->num_bufs*sizeof(int32_t); + k_bufq_states = kzalloc(size, GFP_KERNEL); + if (!k_bufq_states) { + rc = -ENOMEM; + goto alloc_states_failed; + } + + for (i = 0; i < bufq_state->nbufs; ++i) + k_bufq_states[i] = bufq->bufs[i].state; + + if (copy_to_user(bufq_state->buf_state, + k_bufq_states, + sizeof(int32_t) * bufq->num_bufs)) { + rc = -EFAULT; + pr_err("%s copy_to_user fail\n", __func__); + goto copy_failed; + } + +copy_failed: + kfree(k_bufq_states); + } + +alloc_states_failed: + return rc; +} /** * msm_isp_buf_put_scratch() - Release scratch buffers @@ -1357,6 +1394,14 @@ int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, rc = buf_mgr->ops->unmap_buf(buf_mgr, unmap_req->fd); break; } + case VIDIOC_MSM_ISP_CMD_EXT: { + struct msm_vfe_cmd_ext *cmd_ext = (struct msm_vfe_cmd_ext *)arg; + + if (cmd_ext->type == VFE_GET_BUFQ_STATE) + rc = buf_mgr->ops->get_bufq_state(buf_mgr, + &cmd_ext->data.bufq_state); + break; + } } return rc; } @@ -1507,6 +1552,7 @@ static struct msm_isp_buf_ops isp_buf_ops = { .buf_mgr_debug = msm_isp_buf_mgr_debug, .get_bufq = msm_isp_get_bufq, .update_put_buf_cnt = msm_isp_update_put_buf_cnt, + .get_bufq_state = msm_isp_get_bufq_state, }; int msm_isp_create_isp_buf_mgr( diff --git a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.h b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.h index 4794771d3213..d9a3661306e3 100644 --- a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.h +++ b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,16 +44,6 @@ enum msm_isp_buffer_src_t { MSM_ISP_BUFFER_SRC_MAX, }; -enum msm_isp_buffer_state { - MSM_ISP_BUFFER_STATE_UNUSED, /* not used */ - MSM_ISP_BUFFER_STATE_INITIALIZED, /* REQBUF done */ - MSM_ISP_BUFFER_STATE_PREPARED, /* BUF mapped */ - MSM_ISP_BUFFER_STATE_QUEUED, /* buf queued */ - MSM_ISP_BUFFER_STATE_DEQUEUED, /* in use in VFE */ - MSM_ISP_BUFFER_STATE_DIVERTED, /* Sent to other hardware*/ - MSM_ISP_BUFFER_STATE_DISPATCHED, /* Sent to HAL*/ -}; - enum msm_isp_buffer_put_state { MSM_ISP_BUFFER_STATE_PUT_PREPARED, /* on init */ MSM_ISP_BUFFER_STATE_PUT_BUF, /* on rotation */ @@ -182,6 +172,9 @@ struct msm_isp_buf_ops { int (*update_put_buf_cnt)(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, uint32_t bufq_handle, int32_t buf_index, struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit); + + int (*get_bufq_state)(struct msm_isp_buf_mgr *buf_mgr, + struct msm_vfe_bufq_state *bufq_state); }; struct msm_isp_buf_mgr { diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.c b/drivers/media/platform/msm/ais/isp/msm_isp47.c index 52bf8121f32b..1ddcab3ed331 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.c @@ -22,6 +22,7 @@ #include "cam_hw_ops.h" #include "msm_isp47.h" #include "cam_soc_api.h" +#include "msm_camera_diag_util.h" #undef CDBG #define CDBG(fmt, args...) pr_debug(fmt, ##args) @@ -2396,6 +2397,8 @@ int msm_vfe47_update_bandwidth( ab, ib, isp_bandwidth_mgr->client_info, sched_clock()); + msm_camera_diag_update_isp_state( + isp_bandwidth_mgr->bus_vector_active_idx, ab, ib); return 0; } diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_util.c index 2ba19b13535b..64a3c7cde26b 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_util.c @@ -847,6 +847,24 @@ static int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg) } #endif /* CONFIG_COMPAT */ +static int process_isp_cmd_ext(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_cmd_ext *cmd = (struct msm_vfe_cmd_ext *)arg; + + switch (cmd->type) { + case VFE_GET_BUFQ_STATE: { + mutex_lock(&vfe_dev->buf_mgr->lock); + rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, + VIDIOC_MSM_ISP_CMD_EXT, arg); + mutex_unlock(&vfe_dev->buf_mgr->lock); + break; + } + } + + return rc; +} + static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -983,12 +1001,14 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_FETCH_ENG_START: - case VIDIOC_MSM_ISP_MAP_BUF_START_FE: mutex_lock(&vfe_dev->core_mutex); rc = msm_isp_start_fetch_engine(vfe_dev, arg); mutex_unlock(&vfe_dev->core_mutex); break; + case VIDIOC_MSM_ISP_CMD_EXT: + process_isp_cmd_ext(vfe_dev, arg); + break; case VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START: case VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE: mutex_lock(&vfe_dev->core_mutex); @@ -2350,16 +2370,6 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_lock(&vfe_dev->realtime_mutex); mutex_lock(&vfe_dev->core_mutex); - /* Enable vfe clks to wake up from XO shutdown mode */ - if (vfe_dev->pdev->id == 0) - id = CAM_AHB_CLIENT_VFE0; - else - id = CAM_AHB_CLIENT_VFE1; - if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE) < 0) - pr_err("%s: failed to vote for AHB\n", __func__); - vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 1); - vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 1); - if (!vfe_dev->vfe_open_cnt) { pr_err("%s invalid state open cnt %d\n", __func__, vfe_dev->vfe_open_cnt); @@ -2374,6 +2384,17 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_unlock(&vfe_dev->realtime_mutex); return 0; } + + /* Enable vfe clks to wake up from XO shutdown mode */ + if (vfe_dev->pdev->id == 0) + id = CAM_AHB_CLIENT_VFE0; + else + id = CAM_AHB_CLIENT_VFE1; + if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE) < 0) + pr_err("%s: failed to vote for AHB\n", __func__); + vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 1); + /* Unregister page fault handler */ cam_smmu_reg_client_page_fault_handler( vfe_dev->buf_mgr->iommu_hdl, diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif.c b/drivers/media/platform/msm/ais/ispif/msm_ispif.c index a72ac566bb8c..5ddf554d6ef3 100644 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/ais/ispif/msm_ispif.c @@ -29,6 +29,7 @@ #include "msm_camera_io_util.h" #include "cam_hw_ops.h" #include "cam_soc_api.h" +#include "msm_camera_diag_util.h" #ifdef CONFIG_AIS_MSM_ISPIF_V1 #include "msm_ispif_hwreg_v1.h" @@ -1526,6 +1527,22 @@ static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) case ISPIF_SET_VFE_INFO: rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info); break; + case ISPIF_READ_REG_LIST_CMD: + { + struct msm_camera_reg_list_cmd reg_list_cmd; + + if (copy_from_user(®_list_cmd, + (void __user *)pcdata->reg_list, + sizeof(struct msm_camera_reg_list_cmd))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_camera_get_reg_list(ispif->base, ®_list_cmd); + break; + } + case ISPIF_WRITE_REG_LIST_CMD: + break; default: pr_err("%s: invalid cfg_type\n", __func__); rc = -EINVAL; diff --git a/drivers/media/platform/msm/ais/msm.c b/drivers/media/platform/msm/ais/msm.c index 902e05b3329b..c3f3542cc87a 100644 --- a/drivers/media/platform/msm/ais/msm.c +++ b/drivers/media/platform/msm/ais/msm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,6 +31,7 @@ #include "msm_sd.h" #include "cam_hw_ops.h" #include +#include "msm_camera_diag_util.h" static struct v4l2_device *msm_v4l2_dev; @@ -1384,6 +1385,12 @@ static int msm_probe(struct platform_device *pdev) goto v4l2_fail; } + rc = msm_camera_diag_init(); + if (rc < 0) { + pr_err("%s: failed to init diag clk list\n", __func__); + goto v4l2_fail; + } + goto probe_end; v4l2_fail: @@ -1428,6 +1435,7 @@ static int __init msm_init(void) static void __exit msm_exit(void) { + msm_camera_diag_uninit(); platform_driver_unregister(&msm_driver); } diff --git a/drivers/media/platform/msm/ais/msm_ais_diag/Makefile b/drivers/media/platform/msm/ais/msm_ais_diag/Makefile new file mode 100644 index 000000000000..7c40ea02b70a --- /dev/null +++ b/drivers/media/platform/msm/ais/msm_ais_diag/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/ais +ccflags-y += -Idrivers/media/platform/msm/ais/common +ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io +obj-$(CONFIG_MSM_AIS) += msm_diag_cam.o diff --git a/drivers/media/platform/msm/ais/msm_ais_diag/msm_diag_cam.c b/drivers/media/platform/msm/ais/msm_ais_diag/msm_diag_cam.c new file mode 100644 index 000000000000..c2933d79babc --- /dev/null +++ b/drivers/media/platform/msm/ais/msm_ais_diag/msm_diag_cam.c @@ -0,0 +1,267 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include "msm_sd.h" +#include "msm_diag_cam.h" +#include "msm_camera_io_util.h" +#include "msm_camera_dt_util.h" +#include "cam_hw_ops.h" +#include "msm_camera_diag_util.h" + +#undef CDBG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) + +#undef DIAG_CAM_DBG +#ifdef MSM_DIAG_CAM_DEBUG +#define DIAG_CAM_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define DIAG_CAM_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define MSM_DIAG_CAM_DRV_NAME "msm_diag_cam" +static struct platform_driver msm_diag_camera_driver; +static struct diag_cam_device *new_diag_cam_dev; + +int msm_ais_enable_allclocks(void) +{ + int rc = 0; + + CDBG("%s:\n", __func__); + /* Vote ON for clocks */ + if (new_diag_cam_dev == NULL) { + rc = -EINVAL; + pr_err("%s: clock structure uninitialised %d\n", __func__, + rc); + return rc; + } + + rc = msm_camera_enable_vreg(&new_diag_cam_dev->pdev->dev, + new_diag_cam_dev->diag_cam_vreg, + new_diag_cam_dev->regulator_count, + NULL, + 0, + &new_diag_cam_dev->diag_cam_reg_ptr[0], 1); + if (rc < 0) + pr_err("%s:%d diag_cam enable_vreg failed\n", __func__, + __LINE__); + + rc = msm_camera_clk_enable(&new_diag_cam_dev->pdev->dev, + new_diag_cam_dev->diag_cam_clk_info, + new_diag_cam_dev->diag_cam_clk, + new_diag_cam_dev->num_clk, true); + + if (rc < 0) { + pr_err("%s: clk enable failed %d\n", __func__, rc); + rc = 0; + return rc; + } + pr_debug("Turned ON camera clocks\n"); + return 0; + +} + +int msm_ais_disable_allclocks(void) +{ + int rc = 0; + + CDBG("%s:\n", __func__); + /* Vote OFF for clocks */ + if (new_diag_cam_dev == NULL) { + rc = -EINVAL; + pr_err("%s: clock structure uninitialised %d\n", __func__, + rc); + return rc; + } + + if ((new_diag_cam_dev->pdev == NULL) || + (new_diag_cam_dev->diag_cam_clk_info == NULL) || + (new_diag_cam_dev->diag_cam_clk == NULL) || + (new_diag_cam_dev->num_clk == 0)) { + rc = -EINVAL; + pr_err("%s: Clock details uninitialised %d\n", __func__, + rc); + return rc; + } + + rc = msm_camera_clk_enable(&new_diag_cam_dev->pdev->dev, + new_diag_cam_dev->diag_cam_clk_info, + new_diag_cam_dev->diag_cam_clk, + new_diag_cam_dev->num_clk, false); + if (rc < 0) { + pr_err("%s: clk disable failed %d\n", __func__, rc); + return rc; + } + + rc = msm_camera_enable_vreg(&new_diag_cam_dev->pdev->dev, + new_diag_cam_dev->diag_cam_vreg, + new_diag_cam_dev->regulator_count, + NULL, + 0, + &new_diag_cam_dev->diag_cam_reg_ptr[0], 0); + if (rc < 0) + pr_err("%s:%d diag_cam disable_vreg failed\n", __func__, + __LINE__); + + pr_debug("Turned OFF camera clocks\n"); + return 0; +} + +int msm_diag_camera_get_vreginfo_list( + struct msm_ais_diag_regulator_info_list_t *p_vreglist) +{ + int rc = 0; + uint32_t i = 0; + uint32_t len = 0; + uint32_t len1 = 0; + struct regulator *vreg = NULL; + char *vreg_name_inuser = NULL; + + p_vreglist->regulator_num = new_diag_cam_dev->regulator_count; + + pr_debug("ais diag regulator_count %u\n", + new_diag_cam_dev->regulator_count); + + for (; i < p_vreglist->regulator_num ; ++i) { + vreg = new_diag_cam_dev->diag_cam_reg_ptr[i]; + p_vreglist->infolist[i].enable = + regulator_is_enabled(vreg); + len = strlen(new_diag_cam_dev->diag_cam_vreg[i].reg_name); + len1 = sizeof(p_vreglist->infolist[i].regulatorname); + len = (len >= len1) ? len1 : (len+1); + vreg_name_inuser = + p_vreglist->infolist[i].regulatorname; + if (copy_to_user((void __user *)vreg_name_inuser, + (void *)new_diag_cam_dev->diag_cam_vreg[i].reg_name, + len)) { + rc = -EFAULT; + pr_err("%s copy_to_user fail\n", __func__); + break; + } + } + + pr_debug("msm_diag_camera_get_vreginfo_list exit\n"); + return rc; +} + +static int msm_diag_cam_probe(struct platform_device *pdev) +{ + int rc = 0; + + CDBG("%s: pdev %pK device id = %d\n", __func__, pdev, pdev->id); + + new_diag_cam_dev = kzalloc(sizeof(struct diag_cam_device), + GFP_KERNEL); + if (!new_diag_cam_dev) + return -ENOMEM; + + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + + rc = msm_camera_get_clk_info(pdev, + &new_diag_cam_dev->diag_cam_clk_info, + &new_diag_cam_dev->diag_cam_clk, + &new_diag_cam_dev->num_clk); + if (rc < 0) { + pr_err("%s: msm_diag_cam_get_clk_info() failed", __func__); + kfree(new_diag_cam_dev); + return -EFAULT; + } + + new_diag_cam_dev->ref_count = 0; + new_diag_cam_dev->pdev = pdev; + + rc = msm_camera_get_dt_vreg_data( + new_diag_cam_dev->pdev->dev.of_node, + &(new_diag_cam_dev->diag_cam_vreg), + &(new_diag_cam_dev->regulator_count)); + if (rc < 0) { + pr_err("%s: msm_camera_get_dt_vreg_data fail\n", __func__); + rc = -EFAULT; + goto diag_cam_release_mem; + } + + if ((new_diag_cam_dev->regulator_count < 0) || + (new_diag_cam_dev->regulator_count > MAX_REGULATOR)) { + pr_err("%s: invalid reg count = %d, max is %d\n", __func__, + new_diag_cam_dev->regulator_count, MAX_REGULATOR); + rc = -EFAULT; + goto diag_cam_invalid_vreg_data; + } + + rc = msm_camera_config_vreg(&new_diag_cam_dev->pdev->dev, + new_diag_cam_dev->diag_cam_vreg, + new_diag_cam_dev->regulator_count, + NULL, + 0, + &new_diag_cam_dev->diag_cam_reg_ptr[0], 1); + if (rc < 0) + pr_err("%s:%d diag_cam config_vreg failed\n", __func__, + __LINE__); + + platform_set_drvdata(pdev, new_diag_cam_dev); + + return 0; + +diag_cam_invalid_vreg_data: + kfree(new_diag_cam_dev->diag_cam_vreg); +diag_cam_release_mem: + kfree(new_diag_cam_dev); + new_diag_cam_dev = NULL; + return rc; +} + +static int msm_diag_cam_exit(struct platform_device *pdev) +{ + return 0; +} + +static int __init msm_diag_cam_init_module(void) +{ + return platform_driver_register(&msm_diag_camera_driver); +} + +static void __exit msm_diag_cam_exit_module(void) +{ + kfree(new_diag_cam_dev); + platform_driver_unregister(&msm_diag_camera_driver); +} + +static const struct of_device_id msm_diag_camera_match_table[] = { + { .compatible = "qcom,diag-cam" }, + {}, +}; + +static struct platform_driver msm_diag_camera_driver = { + .probe = msm_diag_cam_probe, + .remove = msm_diag_cam_exit, + .driver = { + .name = MSM_DIAG_CAM_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_diag_camera_match_table, + }, +}; + +MODULE_DEVICE_TABLE(of, msm_diag_camera_match_table); + +module_init(msm_diag_cam_init_module); +module_exit(msm_diag_cam_exit_module); +MODULE_DESCRIPTION("MSM diag camera driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/msm_ais_diag/msm_diag_cam.h b/drivers/media/platform/msm/ais/msm_ais_diag/msm_diag_cam.h new file mode 100644 index 000000000000..572ba8dfba3a --- /dev/null +++ b/drivers/media/platform/msm/ais/msm_ais_diag/msm_diag_cam.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef MSM_DIAG_CAM_H +#define MSM_DIAG_CAM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_sd.h" +#include "cam_soc_api.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + + +enum msm_diag_cam_state_t { + AIS_DIAG_STATE_DISABLED, + AIS_DIAG_STATE_ENABLED, +}; + +struct diag_cam_device { + struct platform_device *pdev; + uint8_t ref_count; + enum msm_diag_cam_state_t diag_cam_state; + size_t num_clk; + size_t num_clk_cases; + struct clk **diag_cam_clk; + uint32_t **diag_cam_clk_rates; + struct msm_cam_clk_info *diag_cam_clk_info; + struct camera_vreg_t *diag_cam_vreg; + struct regulator *diag_cam_reg_ptr[MAX_REGULATOR]; + int32_t regulator_count; +}; + +int msm_ais_enable_allclocks(void); +int msm_ais_disable_allclocks(void); +int msm_diag_camera_get_vreginfo_list( + struct msm_ais_diag_regulator_info_list_t *p_vreglist); +#endif diff --git a/drivers/media/platform/msm/ais/msm_ais_mgr/Makefile b/drivers/media/platform/msm/ais/msm_ais_mgr/Makefile index b7a078738489..bb14aec1ee29 100644 --- a/drivers/media/platform/msm/ais/msm_ais_mgr/Makefile +++ b/drivers/media/platform/msm/ais/msm_ais_mgr/Makefile @@ -2,4 +2,5 @@ ccflags-y += -Idrivers/media/platform/msm/ais ccflags-y += -Idrivers/media/platform/msm/ais/common ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci +ccflags-y += -Idrivers/media/platform/msm/ais/msm_ais_diag obj-$(CONFIG_MSM_AIS) += msm_ais_mgr.o diff --git a/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mgr.c b/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mgr.c index 9391c1d0d4ab..4ae07932f5da 100644 --- a/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mgr.c +++ b/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mgr.c @@ -15,6 +15,8 @@ #include #include "msm_ais_mngr.h" #include "msm_early_cam.h" +#include "msm_camera_diag_util.h" +#include "msm_diag_cam.h" #undef CDBG #define CDBG(fmt, args...) pr_debug(fmt, ##args) @@ -42,7 +44,56 @@ static long msm_ais_hndl_ioctl(struct v4l2_subdev *sd, void *arg) case AIS_CLK_DISABLE: rc = msm_ais_disable_clocks(); break; + case AIS_CLK_ENABLE_ALLCLK: + rc = msm_ais_enable_allclocks(); + break; + case AIS_CLK_DISABLE_ALLCLK: + rc = msm_ais_disable_allclocks(); + break; + default: + pr_err("invalid cfg_type\n"); + rc = -EINVAL; + } + if (rc) + pr_err("msm_ais_hndl_ioctl failed %ld\n", rc); + + mutex_unlock(&clk_mngr_dev->cont_mutex); + return rc; +} + +static long msm_ais_hndl_ext_ioctl(struct v4l2_subdev *sd, void *arg) +{ + long rc = 0; + struct clk_mgr_cfg_data_ext *pcdata = + (struct clk_mgr_cfg_data_ext *)arg; + struct msm_ais_mngr_device *clk_mngr_dev = + (struct msm_ais_mngr_device *)v4l2_get_subdevdata(sd); + + if (WARN_ON(!clk_mngr_dev) || WARN_ON(!pcdata)) { + rc = -EINVAL; + return rc; + } + + mutex_lock(&clk_mngr_dev->cont_mutex); + CDBG(pr_fmt("cfg_type = %d\n"), pcdata->cfg_type); + switch (pcdata->cfg_type) { + case AIS_DIAG_GET_REGULATOR_INFO_LIST: + rc = msm_diag_camera_get_vreginfo_list( + &pcdata->data.vreg_infolist); + break; + case AIS_DIAG_GET_BUS_INFO_STATE: + rc = msm_camera_diag_get_ddrbw(&pcdata->data.bus_info); + break; + case AIS_DIAG_GET_CLK_INFO_LIST: + rc = msm_camera_diag_get_clk_list(&pcdata->data.clk_infolist); + break; + case AIS_DIAG_GET_GPIO_LIST: + rc = msm_camera_diag_get_gpio_list(&pcdata->data.gpio_list); + break; + case AIS_DIAG_SET_GPIO_LIST: + rc = msm_camera_diag_set_gpio_list(&pcdata->data.gpio_list); + break; default: pr_err("invalid cfg_type\n"); rc = -EINVAL; @@ -63,6 +114,11 @@ static long msm_ais_mngr_subdev_ioctl(struct v4l2_subdev *sd, if (rc) pr_err("msm_ais_mngr_subdev_ioctl failed\n"); break; + case VIDIOC_MSM_AIS_CLK_CFG_EXT: + rc = msm_ais_hndl_ext_ioctl(sd, arg); + if (rc) + pr_err("msm_ais_hndl_ext_ioctl failed\n"); + break; default: rc = -ENOIOCTLCMD; } @@ -136,6 +192,7 @@ static int32_t __init msm_ais_mngr_init(void) static void __exit msm_ais_mngr_exit(void) { + msm_sd_unregister(&msm_ais_mngr_dev->subdev); mutex_destroy(&msm_ais_mngr_dev->cont_mutex); kfree(msm_ais_mngr_dev); diff --git a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c b/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c index 6d26dff7525d..b820aa45136a 100644 --- a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c @@ -36,6 +36,7 @@ #include "include/msm_csid_3_6_0_hwreg.h" #include "include/msm_csid_3_5_1_hwreg.h" #include "cam_hw_ops.h" +#include "msm_camera_diag_util.h" #define V4L2_IDENT_CSID 50002 #define CSID_VERSION_V20 0x02000011 @@ -870,6 +871,20 @@ static int32_t msm_csid_cmd(struct csid_device *csid_dev, void *arg) case CSID_STOP: rc = msm_csid_stop(csid_dev, cdata->cfg.csid_cidmask); break; + case CSID_READ_REG_LIST_CMD: + { + struct msm_camera_reg_list_cmd reg_list_cmd; + + if (copy_from_user(®_list_cmd, + (void __user *)cdata->cfg.csid_reg_list_cmd, + sizeof(struct msm_camera_reg_list_cmd))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_camera_get_reg_list(csid_dev->base, ®_list_cmd); + break; + } default: pr_err("%s: %d failed\n", __func__, __LINE__); rc = -ENOIOCTLCMD; diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c index c3b087f61888..ebf817149184 100644 --- a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,6 +27,7 @@ #include "include/msm_csiphy_3_4_2_1_hwreg.h" #include "include/msm_csiphy_3_5_hwreg.h" #include "cam_hw_ops.h" +#include "msm_camera_diag_util.h" #define DBG_CSIPHY 0 #define SOF_DEBUG_ENABLE 1 @@ -1264,6 +1265,20 @@ static int32_t msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg) } break; + case CSIPHY_READ_REG_LIST_CMD: + { + struct msm_camera_reg_list_cmd reg_list_cmd; + + if (copy_from_user(®_list_cmd, + (void __user *)cdata->cfg.csiphy_reg_list_cmd, + sizeof(struct msm_camera_reg_list_cmd))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_camera_get_reg_list(csiphy_dev->base, ®_list_cmd); + break; + } default: pr_err("%s: %d failed\n", __func__, __LINE__); rc = -ENOIOCTLCMD; diff --git a/include/uapi/media/ais/msm_ais_isp.h b/include/uapi/media/ais/msm_ais_isp.h index 55bc5290ce28..2b4f0bfeb8c2 100644 --- a/include/uapi/media/ais/msm_ais_isp.h +++ b/include/uapi/media/ais/msm_ais_isp.h @@ -619,6 +619,33 @@ struct msm_vfe_axi_src_state { uint32_t src_frame_id; }; +enum msm_vfe_cmd_ext_type_t { + VFE_GET_BUFQ_STATE, +}; + +enum msm_isp_buffer_state { + MSM_ISP_BUFFER_STATE_UNUSED, /* not used */ + MSM_ISP_BUFFER_STATE_INITIALIZED, /* REQBUF done */ + MSM_ISP_BUFFER_STATE_PREPARED, /* BUF mapped */ + MSM_ISP_BUFFER_STATE_QUEUED, /* buf queued */ + MSM_ISP_BUFFER_STATE_DEQUEUED, /* in use in VFE */ + MSM_ISP_BUFFER_STATE_DIVERTED, /* Sent to other hardware*/ + MSM_ISP_BUFFER_STATE_DISPATCHED, /* Sent to HAL*/ +}; + +struct msm_vfe_bufq_state { + uint32_t handle; + uint32_t nbufs; + int32_t __user *buf_state; +}; + +struct msm_vfe_cmd_ext { + enum msm_vfe_cmd_ext_type_t type; + union { + struct msm_vfe_bufq_state bufq_state; + } data; +}; + enum msm_isp_event_mask_index { ISP_EVENT_MASK_INDEX_STATS_NOTIFY = 0, ISP_EVENT_MASK_INDEX_ERROR = 1, @@ -975,6 +1002,7 @@ enum msm_isp_ioctl_cmd_code { MSM_ISP_STOP, MSM_ISP_SET_CLK_STATUS, + MSM_ISP_CMD_EXT, }; @@ -1110,4 +1138,8 @@ enum msm_isp_ioctl_cmd_code { _IOWR('V', MSM_ISP_SET_CLK_STATUS, \ unsigned int) +#define VIDIOC_MSM_ISP_CMD_EXT \ + _IOWR('V', MSM_ISP_CMD_EXT, \ + struct msm_vfe_cmd_ext) + #endif /* __UAPI_MSM_AIS_ISP__ */ diff --git a/include/uapi/media/ais/msm_ais_ispif.h b/include/uapi/media/ais/msm_ais_ispif.h index b12175d787c2..a184e2983ab6 100644 --- a/include/uapi/media/ais/msm_ais_ispif.h +++ b/include/uapi/media/ais/msm_ais_ispif.h @@ -4,6 +4,7 @@ #include #include #include +#include #define CSID_VERSION_V20 0x02000011 #define CSID_VERSION_V22 0x02001000 @@ -141,10 +142,13 @@ enum ispif_cfg_type_t { ISPIF_STOP, ISPIF_ENABLE_REG_DUMP, ISPIF_SET_VFE_INFO, - ISPIF_CFG2 + ISPIF_CFG2, + ISPIF_READ_REG_LIST_CMD, + ISPIF_WRITE_REG_LIST_CMD, }; + struct ispif_cfg_data_ext { enum ispif_cfg_type_t cfg_type; void __user *data; @@ -158,10 +162,12 @@ struct ispif_cfg_data { uint32_t csid_version; /* ISPIF_INIT */ struct msm_ispif_vfe_info vfe_info; /* ISPIF_SET_VFE_INFO */ struct msm_ispif_param_data params; /* CFG, START, STOP */ + struct msm_camera_reg_list_cmd *reg_list; }; }; #define ISPIF_RDI_PACK_MODE_SUPPORT 1 +#define ISPIF_RW_REG_LIST_SUPPORT #define VIDIOC_MSM_ISPIF_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data) diff --git a/include/uapi/media/ais/msm_ais_mgr.h b/include/uapi/media/ais/msm_ais_mgr.h index 43ae16df65f9..bfac1ac8296a 100644 --- a/include/uapi/media/ais/msm_ais_mgr.h +++ b/include/uapi/media/ais/msm_ais_mgr.h @@ -3,16 +3,87 @@ #include +#define VREGNAME_SIZE 32 +#define CLKNAME_SIZE 32 + +enum cam_ahb_clk_vote { + /* need to update the voting requests + * according to dtsi entries. + */ + CAM_AHB_SUSPEND_VOTE = 0x0, + CAM_AHB_SVS_VOTE = 0x01, + CAM_AHB_NOMINAL_VOTE = 0x02, + CAM_AHB_TURBO_VOTE = 0x03, + CAM_AHB_DYNAMIC_VOTE = 0xFF, +}; + enum clk_mgr_cfg_type_t { AIS_CLK_ENABLE, AIS_CLK_DISABLE, + AIS_CLK_ENABLE_ALLCLK, + AIS_CLK_DISABLE_ALLCLK +}; + +enum ais_mgr_cfg_ext_type_t { + AIS_DIAG_GET_REGULATOR_INFO_LIST, + AIS_DIAG_GET_BUS_INFO_STATE, + AIS_DIAG_GET_CLK_INFO_LIST, + AIS_DIAG_GET_GPIO_LIST, + AIS_DIAG_SET_GPIO_LIST, }; #define AIS_CLK_ENABLE AIS_CLK_ENABLE #define AIS_CLK_DISABLE AIS_CLK_DISABLE + +struct msm_camera_reg_list_cmd { + void __user *value_list; + void __user *regaddr_list; + uint32_t reg_num; +}; + +struct msm_ais_diag_regulator_info_t { + int enable; + char regulatorname[VREGNAME_SIZE]; +}; + +struct msm_ais_diag_regulator_info_list_t { + struct msm_ais_diag_regulator_info_t *infolist; + uint32_t regulator_num; +}; + +struct msm_ais_diag_bus_info_t { + enum cam_ahb_clk_vote ahb_clk_vote_state; + uint32_t isp_bus_vector_idx; /* 0 - init 1- ping 2 - pong */ + uint64_t isp_ab; + uint64_t isp_ib; +}; + +struct msm_ais_diag_clk_info_t { + char clk_name[CLKNAME_SIZE]; + long clk_rate; + uint8_t enable; +}; + +struct msm_ais_diag_clk_list_t { + void __user *clk_info; + uint32_t clk_num; +}; + +struct msm_ais_diag_gpio_list_t { + uint32_t __user *gpio_idx_list; + int32_t __user *gpio_val_list; + uint32_t gpio_num; +}; + struct clk_mgr_cfg_data_ext { - enum clk_mgr_cfg_type_t cfg_type; + enum ais_mgr_cfg_ext_type_t cfg_type; + union { + struct msm_ais_diag_regulator_info_list_t vreg_infolist; + struct msm_ais_diag_bus_info_t bus_info; + struct msm_ais_diag_clk_list_t clk_infolist; + struct msm_ais_diag_gpio_list_t gpio_list; + } data; }; struct clk_mgr_cfg_data { diff --git a/include/uapi/media/ais/msm_ais_sensor.h b/include/uapi/media/ais/msm_ais_sensor.h index ca9bcf96bcb0..633f3f227174 100644 --- a/include/uapi/media/ais/msm_ais_sensor.h +++ b/include/uapi/media/ais/msm_ais_sensor.h @@ -3,7 +3,7 @@ #include #include - +#include #include #include @@ -152,6 +152,8 @@ enum csid_cfg_type_t { CSID_START, CSID_STOP, CSID_RELEASE, + CSID_READ_REG_LIST_CMD, + CSID_WRITE_REG_LIST_CMD, }; enum csiphy_cfg_type_t { @@ -160,6 +162,8 @@ enum csiphy_cfg_type_t { CSIPHY_START, CSIPHY_STOP, CSIPHY_RELEASE, + CSIPHY_READ_REG_LIST_CMD, + CSIPHY_WRITE_REG_LIST_CMD, }; enum camera_vreg_type { @@ -291,6 +295,7 @@ struct csid_cfg_data { struct msm_camera_csid_params *csid_params; struct msm_camera_csid_testmode_parms *csid_testmode_params; uint32_t csid_cidmask; + struct msm_camera_reg_list_cmd *csid_reg_list_cmd; } cfg; }; @@ -299,6 +304,7 @@ struct csiphy_cfg_data { union { struct msm_camera_csiphy_params *csiphy_params; struct msm_camera_csi_lane_params *csi_lane_params; + struct msm_camera_reg_list_cmd *csiphy_reg_list_cmd; } cfg; }; @@ -613,6 +619,8 @@ struct sensor_init_cfg_data { } cfg; }; +#define CSI_RW_REG_LIST_SUPPORT + #define VIDIOC_MSM_SENSOR_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data)