diff --git a/Makefile b/Makefile index 44714b7440f5..cb00746debf3 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,10 @@ ifeq ($(CONFIG_ARCH_BENGAL), y) include $(srctree)/techpack/camera/config/bengalcamera.conf endif +ifeq ($(CONFIG_ARCH_MONACO), y) +include $(srctree)/techpack/camera/config/monacocamera.conf +endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) include $(srctree)/techpack/camera/config/lahainacamera.conf endif @@ -22,6 +26,10 @@ ifeq ($(CONFIG_ARCH_HOLI), y) include $(srctree)/techpack/camera/config/holicamera.conf endif +ifeq ($(CONFIG_ARCH_BLAIR), y) +include $(srctree)/techpack/camera/config/blaircamera.conf +endif + ifeq ($(CONFIG_ARCH_SHIMA), y) include $(srctree)/techpack/camera/config/shimacamera.conf endif @@ -45,6 +53,11 @@ LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/bengalcameraconf.h endif +ifeq ($(CONFIG_ARCH_MONACO), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/monacocameraconf.h +endif + ifeq ($(CONFIG_ARCH_LAHAINA), y) LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/lahainacameraconf.h @@ -55,6 +68,11 @@ LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/holicameraconf.h endif +ifeq ($(CONFIG_ARCH_BLAIR), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/blaircameraconf.h +endif + ifeq ($(CONFIG_ARCH_SHIMA), y) LINUXINCLUDE += \ -include $(srctree)/techpack/camera/config/shimacameraconf.h diff --git a/config/blaircamera.conf b/config/blaircamera.conf new file mode 100644 index 000000000000..4a5de0e8362a --- /dev/null +++ b/config/blaircamera.conf @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2021, The Linux Foundation. All rights reserved. + +ifeq ($(CONFIG_QGKI),y) +export CONFIG_SPECTRA_CAMERA=m +$(info "SPECTRA_CAMERA IS STATIC") +else +$(info "SPECTRA_CAMERA IS MODULAR") +export CONFIG_SPECTRA_CAMERA=m +endif + +ifneq (,$(filter $(CONFIG_SPECTRA_CAMERA), y m)) +export CONFIG_SPECTRA_ISP=y +export CONFIG_SPECTRA_OPE=y +export CONFIG_SPECTRA_TFE=y +export CONFIG_SPECTRA_SENSOR=y +endif diff --git a/config/blaircameraconf.h b/config/blaircameraconf.h new file mode 100644 index 000000000000..816797dee642 --- /dev/null +++ b/config/blaircameraconf.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 +#define CONFIG_SPECTRA_ISP 1 +#define CONFIG_SPECTRA_OPE 1 +#define CONFIG_SPECTRA_TFE 1 +#define CONFIG_SPECTRA_SENSOR 1 diff --git a/config/monacocamera.conf b/config/monacocamera.conf new file mode 100644 index 000000000000..99b81918e8a3 --- /dev/null +++ b/config/monacocamera.conf @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2019,2021 The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA=y +export CONFIG_SPECTRA_TFE=y +export CONFIG_SPECTRA_ISP=y +export CONFIG_SPECTRA_SENSOR=y +export CONFIG_SPECTRA_OPE=y diff --git a/config/monacocameraconf.h b/config/monacocameraconf.h new file mode 100644 index 000000000000..17a038cc14d9 --- /dev/null +++ b/config/monacocameraconf.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 +#define CONFIG_SPECTRA_TFE 1 +#define CONFIG_SPECTRA_ISP 1 +#define CONFIG_SPECTRA_SENSOR 1 +#define CONFIG_SPECTRA_OPE 1 + diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 9637a8715af6..a9a635d606f9 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -583,6 +583,31 @@ int cam_context_handle_stop_dev(struct cam_context *ctx, return rc; } +int cam_context_handle_shutdown_dev(struct cam_context *ctx, + struct cam_control *cmd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid stop device command payload"); + return -EINVAL; + } + + if (ctx->state_machine[ctx->state].ioctl_ops.shutdown_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.shutdown_dev( + (struct v4l2_subdev *)cmd->handle, fh); + else + CAM_WARN(CAM_CORE, "No shutdown device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + + return rc; +} + int cam_context_handle_info_dump(void *context, enum cam_context_dump_id id) { diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 5be078536ff5..e55da3c3c4e7 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CONTEXT_H_ @@ -9,6 +9,7 @@ #include #include #include +#include #include "cam_req_mgr_interface.h" #include "cam_hw_mgr_intf.h" #include "cam_smmu_api.h" @@ -95,6 +96,7 @@ struct cam_ctx_request { * @acquire_hw: Function pointer for acquire hw * @release_hw: Function pointer for release hw * @dump_dev: Function pointer for dump dev + * @shutdown_dev: Function pointer for shutdown dev * */ struct cam_ctx_ioctl_ops { @@ -114,6 +116,8 @@ struct cam_ctx_ioctl_ops { int (*release_hw)(struct cam_context *ctx, void *args); int (*dump_dev)(struct cam_context *ctx, struct cam_dump_req_cmd *cmd); + int (*shutdown_dev)(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); }; /** @@ -479,6 +483,19 @@ int cam_context_handle_start_dev(struct cam_context *ctx, int cam_context_handle_stop_dev(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd); +/** + * cam_context_handle_shutdown_dev() + * + * @brief: Handle shutdown device command + * + * @ctx: Object pointer for cam_context + * @cmd: Shutdown device command payload + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_context_handle_shutdown_dev(struct cam_context *ctx, + struct cam_control *cmd, struct v4l2_subdev_fh *fh); + /** * cam_context_handle_dump_dev() * diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index c3770f2df745..d27bcdd6bf0d 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -297,6 +297,27 @@ static int __cam_node_handle_stop_dev(struct cam_node *node, return rc; } +int cam_node_handle_shutdown_dev(struct cam_node *node, + struct cam_control *cmd, struct v4l2_subdev_fh *fh) +{ + struct cam_context *ctx = NULL; + int32_t dev_index = -1; + int rc = 0, ret = 0; + + while ((dev_index = cam_get_dev_handle_info(cmd->handle, + &ctx, dev_index)) < CAM_REQ_MGR_MAX_HANDLES_V2) { + ret = cam_context_handle_shutdown_dev(ctx, cmd, fh); + if (ret) { + rc = ret; + CAM_ERR(CAM_CORE, "Shutdown failure for node %s", + node->name); + continue; + } + } + + return rc; +} + static int __cam_node_handle_config_dev(struct cam_node *node, struct cam_config_dev_cmd *config) { diff --git a/drivers/cam_core/cam_node.h b/drivers/cam_core/cam_node.h index 640798b387d6..81503f28974f 100644 --- a/drivers/cam_core/cam_node.h +++ b/drivers/cam_core/cam_node.h @@ -100,4 +100,30 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, */ void cam_node_put_ctxt_to_free_list(struct kref *ref); +/** + * cam_get_dev_handle_info() + * + * @brief: provides the active dev index. + * + * @handle: pointer to struct v4l2_dev + * @ctx: pointer to struct cam_context + * @dev_index: dev index + * + */ +int32_t cam_get_dev_handle_info(uint64_t handle, + struct cam_context **ctx, int32_t dev_index); + +/** + * cam_node_handle_shutdown_dev() + * + * @brief: Shutdowns all the active devices. + * + * @node: pointer to struct node + * @cmd: pointer to struct cmd + * @fh: pointer to struct v4l2_subdev_fh + * + */ +int cam_node_handle_shutdown_dev(struct cam_node *node, + struct cam_control *cmd, struct v4l2_subdev_fh *fh); + #endif /* _CAM_NODE_H_ */ diff --git a/drivers/cam_core/cam_subdev.c b/drivers/cam_core/cam_subdev.c index 52612951dca7..cbe1b4ca3336 100644 --- a/drivers/cam_core/cam_subdev.c +++ b/drivers/cam_core/cam_subdev.c @@ -45,6 +45,8 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, long rc; struct cam_node *node = (struct cam_node *) v4l2_get_subdevdata(sd); + struct v4l2_subdev_fh *fh = (struct v4l2_subdev_fh *)arg; + struct cam_control cntrl_cmd; if (!node || node->state == CAM_NODE_STATE_UNINIT) { rc = -EINVAL; @@ -56,6 +58,19 @@ static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, rc = cam_node_handle_ioctl(node, (struct cam_control *) arg); break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_WARN(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + cntrl_cmd.op_code = CAM_SD_SHUTDOWN; + cntrl_cmd.handle = (uint64_t)sd; + rc = cam_node_handle_shutdown_dev(node, &cntrl_cmd, fh); + if (rc) + CAM_ERR(CAM_CORE, "shutdown device failed(rc = %d)", + rc); + break; default: CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd, node->name); diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index f5bb5db85c29..3c8f5dc166e2 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -691,7 +691,7 @@ static int cam_cpas_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_cpas_subdev_close(struct v4l2_subdev *sd, +static int __cam_cpas_subdev_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); @@ -702,6 +702,11 @@ static int cam_cpas_subdev_close(struct v4l2_subdev *sd, } mutex_lock(&cpas_intf->intf_lock); + if (cpas_intf->open_cnt <= 0) { + CAM_WARN(CAM_CPAS, "device already closed, open_cnt: %d", cpas_intf->open_cnt); + mutex_unlock(&cpas_intf->intf_lock); + return 0; + } cpas_intf->open_cnt--; CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt); mutex_unlock(&cpas_intf->intf_lock); @@ -709,6 +714,19 @@ static int cam_cpas_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_cpas_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_CPAS); + + if (crm_active) { + CAM_DBG(CAM_CPAS, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return __cam_cpas_subdev_close(sd, fh); +} + static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -724,6 +742,9 @@ static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd, case VIDIOC_CAM_CONTROL: rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg); break; + case CAM_SD_SHUTDOWN: + rc = __cam_cpas_subdev_close(sd, NULL); + break; default: CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd); rc = -EINVAL; @@ -811,6 +832,7 @@ static int cam_cpas_subdev_register(struct platform_device *pdev) subdev->sd_flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; subdev->ent_function = CAM_CPAS_DEVICE_TYPE; + subdev->close_seq_prior = CAM_SD_CLOSE_LOW_PRIORITY; rc = cam_register_subdev(subdev); if (rc) { diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 6447b3b40dc3..01a376dd51c1 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -28,6 +28,7 @@ #include "cpastop_v540_100.h" #include "cpastop_v520_100.h" #include "cpastop_v545_100.h" +#include "cpastop_v545_110.h" #include "cpastop_v570_200.h" #include "cpastop_v680_100.h" #include "cpastop_v165_100.h" @@ -119,7 +120,7 @@ static const uint32_t cam_cpas_hw_version_map { CAM_CPAS_TITAN_545_V100, 0, - 0, + CAM_CPAS_TITAN_545_V110, 0, 0, 0, @@ -934,6 +935,10 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, camnoc_info = &cam545_cpas100_camnoc_info; qchannel_info = &cam545_cpas100_qchannel_info; break; + case CAM_CPAS_TITAN_545_V110: + camnoc_info = &cam545_cpas110_camnoc_info; + qchannel_info = &cam545_cpas110_qchannel_info; + break; case CAM_CPAS_TITAN_570_V200: camnoc_info = &cam570_cpas200_camnoc_info; qchannel_info = &cam570_cpas200_qchannel_info; diff --git a/drivers/cam_cpas/cpas_top/cpastop_v165_100.h b/drivers/cam_cpas/cpas_top/cpastop_v165_100.h index 8e41284604f6..9dc47566bb37 100644 --- a/drivers/cam_cpas/cpas_top/cpastop_v165_100.h +++ b/drivers/cam_cpas/cpas_top/cpastop_v165_100.h @@ -289,6 +289,27 @@ static struct cam_camnoc_specific */ .enable = false, }, + .qosgen_mainctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4808, /* IFE01234_RDI_QOSGEN_MAINCTL */ + .value = 0x2, + }, + .qosgen_shaping_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4820, /* IFE01234_RDI_QOSGEN_SHAPING_LOW */ + .value = 0x07070707, + }, + .qosgen_shaping_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4824, /* IFE01234_RDI_QOSGEN_SHAPING_HIGH */ + .value = 0x07070707, + }, }, { .port_type = CAM_CAMNOC_IFE01_NRDI_WRITE, @@ -343,6 +364,27 @@ static struct cam_camnoc_specific .offset = 0x3B88, /* IFE01_NRDI_ENCCTL_LOW */ .value = 1, }, + .qosgen_mainctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4708, /* IFE01_NRDI_QOSGEN_MAINCTL */ + .value = 0x2, + }, + .qosgen_shaping_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4720, /* IFE01_NRDI_QOSGEN_SHAPING_LOW */ + .value = 0x07070707, + }, + .qosgen_shaping_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4724, /* IFE01_NRDI_QOSGEN_SHAPING_HIGH */ + .value = 0x07070707, + }, }, { .port_type = CAM_CAMNOC_IFE2_NRDI_WRITE, @@ -397,6 +439,27 @@ static struct cam_camnoc_specific .offset = 0x5588, /* IFE2_NRDI_ENCCTL_LOW */ .value = 0, }, + .qosgen_mainctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5188, /* IFE2_NRDI_QOSGEN_MAINCTL */ + .value = 0x2, + }, + .qosgen_shaping_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x51A0, /* IFE2_NRDI_QOSGEN_SHAPING_LOW */ + .value = 0x07070707, + }, + .qosgen_shaping_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x51A4, /* IFE2_NRDI_QOSGEN_SHAPING_HIGH */ + .value = 0x07070707, + }, }, { .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, diff --git a/drivers/cam_cpas/cpas_top/cpastop_v545_110.h b/drivers/cam_cpas/cpas_top/cpastop_v545_110.h new file mode 100644 index 000000000000..d8833047c250 --- /dev/null +++ b/drivers/cam_cpas/cpas_top/cpastop_v545_110.h @@ -0,0 +1,322 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V545_110_H_ +#define _CPASTOP_V545_110_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v545_110_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xA40, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + (TEST_IRQ_ENABLE ? + 0x2 : /* SBM_FAULTINEN0_LOW_PORT6_MASK */ + 0x0) /* SBM_FAULTINEN0_LOW_PORT1_MASK */, + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xA48, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xA80, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x3 : 0x1, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v545_110_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xD08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xD10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xD18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT6_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xA88, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xA90, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + + +static struct cam_camnoc_specific + cam_cpas_v545_110_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE30, /* CDM_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE34, /* CDM_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE38, /* CDM_URGENCY_LOW */ + .value = 0x00000003, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE40, /* CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xE48, /* CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_TFE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_LOW */ + .offset = 0x30, + .value = 0x55554433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_HIGH */ + .offset = 0x34, + .value = 0x66666655, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x38, /* TFE_URGENCY_LOW */ + .value = 0x00001030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x40, /* TFE_DANGERLUT_LOW */ + .value = 0xffff0000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x48, /* TFE_SAFELUT_LOW */ + .value = 0x00000003, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_TFE_1, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_LOW */ + .offset = 0x4030, + .value = 0x55554433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_HIGH */ + .offset = 0x4034, + .value = 0x66666655, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4038, /* TFE_URGENCY_LOW */ + .value = 0x00001030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x4040, /* TFE_DANGERLUT_LOW */ + .value = 0xffff0000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x4048, /* TFE_SAFELUT_LOW */ + .value = 0x00000003, + }, + }, + { + .port_type = CAM_CAMNOC_TFE_2, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_LOW */ + .offset = 0x5030, + .value = 0x55554433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* TFE_PRIORITYLUT_HIGH */ + .offset = 0x5034, + .value = 0x66666655, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5038, /* TFE_URGENCY_LOW */ + .value = 0x00001030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5040, /* TFE_DANGERLUT_LOW */ + .value = 0xffff0000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5048, /* TFE_SAFELUT_LOW */ + .value = 0x00000003, + }, + }, + { + .port_type = CAM_CAMNOC_OPE, + .enable = true, + .priority_lut_low = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* OPE_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* OPE_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x438, /* OPE_URGENCY_LOW */ + .value = 0x00000033, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* OPE_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* OPE_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam545_cpas110_err_logger_offsets = { + .mainctrl = 0xD08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0xD10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0xD20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0xD24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0xD28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0xD2C, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0xD30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0xD34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0xD38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0xD3C, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_camnoc_info cam545_cpas110_camnoc_info = { + .specific = &cam_cpas_v545_110_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v545_110_camnoc_specific), + .irq_sbm = &cam_cpas_v545_110_irq_sbm, + .irq_err = &cam_cpas_v545_110_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v545_110_irq_err), + .err_logger = &cam545_cpas110_err_logger_offsets, + .errata_wa_list = NULL, +}; + +static struct cam_cpas_camnoc_qchannel cam545_cpas110_qchannel_info = { + .qchannel_ctrl = 0x14, + .qchannel_status = 0x18, +}; +#endif /* _CPASTOP_V545_110_H_ */ diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 2b82d1f283e4..87fe72a42a64 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_API_H_ @@ -139,6 +139,7 @@ enum cam_cpas_hw_version { CAM_CPAS_TITAN_540_V100 = 0x540100, CAM_CPAS_TITAN_520_V100 = 0x520100, CAM_CPAS_TITAN_545_V100 = 0x545100, + CAM_CPAS_TITAN_545_V110 = 0x545110, CAM_CPAS_TITAN_570_V200 = 0x570200, CAM_CPAS_TITAN_680_V100 = 0x680100, CAM_CPAS_TITAN_MAX diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index ca4d1d1e35d5..2b617b15f5a0 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/drivers/cam_cust/cam_custom_context.c @@ -1604,6 +1604,19 @@ static int __cam_custom_ctx_apply_default_req( return rc; } +static int __cam_custom_ctx_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = -EINVAL; + + if (!sd || !fh) { + CAM_ERR(CAM_CUSTOM, "Invalid input pointer"); + return rc; + } + + return cam_custom_subdev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { @@ -1618,6 +1631,7 @@ static struct cam_ctx_ops .ioctl_ops = { .acquire_dev = __cam_custom_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -1629,6 +1643,7 @@ static struct cam_ctx_ops .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev_in_acquired, .release_hw = __cam_custom_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .link = __cam_custom_ctx_link_in_acquired, @@ -1647,6 +1662,7 @@ static struct cam_ctx_ops .release_dev = __cam_custom_release_dev_in_acquired, .config_dev = __cam_custom_ctx_config_dev, .release_hw = __cam_custom_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_ready, @@ -1664,6 +1680,7 @@ static struct cam_ctx_ops .config_dev = __cam_custom_ctx_config_dev_in_flushed, .release_hw = __cam_custom_ctx_release_hw_in_activated_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_ready, @@ -1680,6 +1697,7 @@ static struct cam_ctx_ops .config_dev = __cam_custom_ctx_config_dev, .release_hw = __cam_custom_ctx_release_hw_in_activated_state, + .shutdown_dev = __cam_custom_ctx_shutdown_dev, }, .crm_ops = { .unlink = __cam_custom_ctx_unlink_in_activated, diff --git a/drivers/cam_cust/cam_custom_context.h b/drivers/cam_cust/cam_custom_context.h index ef7fe1f87434..74c45d541610 100644 --- a/drivers/cam_cust/cam_custom_context.h +++ b/drivers/cam_cust/cam_custom_context.h @@ -150,4 +150,16 @@ int cam_custom_dev_context_init(struct cam_custom_context *ctx, */ int cam_custom_dev_context_deinit(struct cam_custom_context *ctx); +/** + * cam_custom_subdev_close_internal() + * + * @brief: Close function for the Custom context + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_custom_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_CUSTOM_CONTEXT_H_ */ diff --git a/drivers/cam_cust/cam_custom_dev.c b/drivers/cam_cust/cam_custom_dev.c index 3c3bea4c22c0..36dde62fc51d 100644 --- a/drivers/cam_cust/cam_custom_dev.c +++ b/drivers/cam_cust/cam_custom_dev.c @@ -58,7 +58,7 @@ static int cam_custom_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_custom_subdev_close(struct v4l2_subdev *sd, +int cam_custom_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -86,6 +86,19 @@ end: return rc; } +static int cam_custom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_CUSTOM); + + if (crm_active) { + CAM_DBG(CAM_CUSTOM, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_custom_subdev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_custom_subdev_internal_ops = { .close = cam_custom_subdev_close, .open = cam_custom_subdev_open, @@ -102,6 +115,7 @@ static int cam_custom_component_bind(struct device *dev, struct platform_device *pdev = to_platform_device(dev); g_custom_dev.sd.internal_ops = &cam_custom_subdev_internal_ops; + g_custom_dev.sd.close_seq_prior = CAM_SD_CLOSE_HIGH_PRIORITY; rc = cam_subdev_probe(&g_custom_dev.sd, pdev, CAM_CUSTOM_DEV_NAME, CAM_CUSTOM_DEVICE_TYPE); diff --git a/drivers/cam_fd/cam_fd_context.c b/drivers/cam_fd/cam_fd_context.c index c79f2f90e007..0f3fa85f079e 100644 --- a/drivers/cam_fd/cam_fd_context.c +++ b/drivers/cam_fd/cam_fd_context.c @@ -169,6 +169,19 @@ static int __cam_fd_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_fd_shutdown_dev(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = -EINVAL; + + if (!sd || !fh) { + CAM_ERR(CAM_FD, "Invalid input pointer"); + return rc; + } + + return cam_fd_dev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_fd_ctx_state_machine[CAM_CTX_STATE_MAX] = { @@ -182,6 +195,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_fd_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_fd_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -192,18 +206,25 @@ static struct cam_ctx_ops .release_dev = __cam_fd_ctx_release_dev_in_acquired, .config_dev = __cam_fd_ctx_config_dev_in_acquired, .start_dev = __cam_fd_ctx_start_dev_in_acquired, + .shutdown_dev = __cam_fd_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, }, /* Ready */ { - .ioctl_ops = { }, + .ioctl_ops = { + .shutdown_dev = __cam_fd_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .shutdown_dev = __cam_fd_shutdown_dev, + }, + }, /* Activated */ { .ioctl_ops = { @@ -212,6 +233,7 @@ static struct cam_ctx_ops .config_dev = __cam_fd_ctx_config_dev_in_activated, .flush_dev = __cam_fd_ctx_flush_dev_in_activated, .dump_dev = __cam_fd_ctx_dump_dev_in_activated, + .shutdown_dev = __cam_fd_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_fd_ctx_handle_irq_in_activated, diff --git a/drivers/cam_fd/cam_fd_context.h b/drivers/cam_fd/cam_fd_context.h index a751a04d2d67..615e8d94cf6e 100644 --- a/drivers/cam_fd/cam_fd_context.h +++ b/drivers/cam_fd/cam_fd_context.h @@ -27,4 +27,15 @@ int cam_fd_context_init(struct cam_fd_context *fd_ctx, uint32_t ctx_id); int cam_fd_context_deinit(struct cam_fd_context *ctx); +/** + * cam_fd_dev_close_internal() + * + * @brief: Close function for the fd dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + */ +int cam_fd_dev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_FD_CONTEXT_H_ */ diff --git a/drivers/cam_fd/cam_fd_dev.c b/drivers/cam_fd/cam_fd_dev.c index bc1864edb24e..a58db056f6fb 100644 --- a/drivers/cam_fd/cam_fd_dev.c +++ b/drivers/cam_fd/cam_fd_dev.c @@ -57,7 +57,7 @@ static int cam_fd_dev_open(struct v4l2_subdev *sd, return 0; } -static int cam_fd_dev_close(struct v4l2_subdev *sd, +static int cam_fd_dev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_fd_dev *fd_dev = &g_fd_dev; @@ -69,6 +69,11 @@ static int cam_fd_dev_close(struct v4l2_subdev *sd, } mutex_lock(&fd_dev->lock); + if (fd_dev->open_cnt == 0) { + CAM_WARN(CAM_FD, "device already closed"); + mutex_unlock(&fd_dev->lock); + return 0; + } fd_dev->open_cnt--; CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); mutex_unlock(&fd_dev->lock); @@ -83,6 +88,19 @@ static int cam_fd_dev_close(struct v4l2_subdev *sd, return 0; } +static int cam_fd_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_FD); + + if (crm_active) { + CAM_DBG(CAM_FD, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_fd_dev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_fd_subdev_internal_ops = { .open = cam_fd_dev_open, .close = cam_fd_dev_close, @@ -98,6 +116,7 @@ static int cam_fd_dev_component_bind(struct device *dev, struct platform_device *pdev = to_platform_device(dev); g_fd_dev.sd.internal_ops = &cam_fd_subdev_internal_ops; + g_fd_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; /* Initialize the v4l2 subdevice first. (create cam_node) */ rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME, diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 57a80bcd7341..03ead2c3b693 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/drivers/cam_icp/cam_icp_context.c @@ -221,6 +221,12 @@ static int __cam_icp_handle_buf_done_in_ready(void *ctx, return cam_context_buf_done_from_hw(ctx, done, evt_id); } +static int __cam_icp_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_icp_subdev_close_internal(sd, fh); +} + static struct cam_ctx_ops cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = { /* Uninit */ @@ -233,6 +239,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_icp_acquire_dev_in_available, + .shutdown_dev = __cam_icp_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -245,6 +252,7 @@ static struct cam_ctx_ops .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, .dump_dev = __cam_icp_dump_dev_in_ready, + .shutdown_dev = __cam_icp_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, @@ -258,16 +266,23 @@ static struct cam_ctx_ops .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, .dump_dev = __cam_icp_dump_dev_in_ready, + .shutdown_dev = __cam_icp_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, .pagefault_ops = cam_icp_context_dump_active_request, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .shutdown_dev = __cam_icp_shutdown_dev, + }, + }, /* Activated */ { - .ioctl_ops = {}, + .ioctl_ops = { + .shutdown_dev = __cam_icp_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, .pagefault_ops = cam_icp_context_dump_active_request, diff --git a/drivers/cam_icp/cam_icp_context.h b/drivers/cam_icp/cam_icp_context.h index dc9018d1c229..9150bcf43f62 100644 --- a/drivers/cam_icp/cam_icp_context.h +++ b/drivers/cam_icp/cam_icp_context.h @@ -39,4 +39,12 @@ int cam_icp_context_init(struct cam_icp_context *ctx, */ int cam_icp_context_deinit(struct cam_icp_context *ctx); +/** + * cam_icp_subdev_close_internal() - Close function for the icp dev + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + */ +int cam_icp_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_ICP_CONTEXT_H_ */ diff --git a/drivers/cam_icp/cam_icp_subdev.c b/drivers/cam_icp/cam_icp_subdev.c index 6a12cdd3e2fc..1a3be9b64ad5 100644 --- a/drivers/cam_icp/cam_icp_subdev.c +++ b/drivers/cam_icp/cam_icp_subdev.c @@ -98,7 +98,7 @@ end: return rc; } -static int cam_icp_subdev_close(struct v4l2_subdev *sd, +int cam_icp_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -108,7 +108,6 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd, mutex_lock(&g_icp_dev.icp_lock); if (g_icp_dev.open_cnt <= 0) { CAM_DBG(CAM_ICP, "ICP subdev is already closed"); - rc = -EINVAL; goto end; } g_icp_dev.open_cnt--; @@ -133,7 +132,20 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd, end: mutex_unlock(&g_icp_dev.icp_lock); - return 0; + return rc; +} + +static int cam_icp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_ICP); + + if (crm_active) { + CAM_DBG(CAM_ICP, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_icp_subdev_close_internal(sd, fh); } const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = { @@ -157,6 +169,7 @@ static int cam_icp_component_bind(struct device *dev, g_icp_dev.sd.pdev = pdev; g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops; + g_icp_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME, CAM_ICP_DEVICE_TYPE); if (rc) { diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index e556ca6f1857..d6a1ecee86f9 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -1062,8 +1062,7 @@ static bool cam_icp_update_clk_free(struct cam_icp_hw_mgr *hw_mgr, static bool cam_icp_debug_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) { - if (icp_hw_mgr.icp_debug_clk < ICP_CLK_TURBO_HZ && - icp_hw_mgr.icp_debug_clk && + if (icp_hw_mgr.icp_debug_clk && icp_hw_mgr.icp_debug_clk != hw_mgr_clk_info->curr_clk) { hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_debug_clk; hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk; diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index f7a95795744b..00af70d8a093 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -864,6 +864,18 @@ static int __cam_isp_ctx_handle_buf_done_for_req_list( list_add_tail(&req->list, &ctx->free_req_list); req_isp->reapply = false; req_isp->cdm_reset_before_apply = false; + req_isp->num_acked = 0; + req_isp->num_deferred_acks = 0; + req_isp->bubble_detected = false; + /* + * Only update the process_bubble and bubble_frame_cnt + * when bubble is detected on this req, in case the other + * request is processing bubble. + */ + if (req_isp->bubble_detected) { + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->bubble_frame_cnt = 0; + } CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", @@ -1863,7 +1875,6 @@ notify_only: if ((!req_isp->bubble_detected) && (req->request_id > ctx_isp->reported_req_id)) { request_id = req->request_id; - ctx_isp->reported_req_id = request_id; __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_EPOCH, req); break; @@ -1873,6 +1884,9 @@ notify_only: if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_BUBBLE) request_id = 0; + if (request_id != 0) + ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); @@ -2099,6 +2113,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, ctx_isp->frame_id, ctx->ctx_id); } } + atomic_set(&ctx_isp->process_bubble, 1); } /* @@ -2334,6 +2349,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( ctx_isp->frame_id, ctx->ctx_id); } } + atomic_set(&ctx_isp->process_bubble, 1); } /* @@ -5837,6 +5853,12 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_isp_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_isp_subdev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_isp_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { @@ -5850,6 +5872,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_isp_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -5861,6 +5884,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_top_state, .config_dev = __cam_isp_ctx_config_dev_in_acquired, .release_hw = __cam_isp_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .link = __cam_isp_ctx_link_in_acquired, @@ -5880,6 +5904,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_top_state, .config_dev = __cam_isp_ctx_config_dev_in_top_state, .release_hw = __cam_isp_ctx_release_hw_in_top_state, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_ready, @@ -5897,6 +5922,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_activated, .config_dev = __cam_isp_ctx_config_dev_in_flushed, .release_hw = __cam_isp_ctx_release_hw_in_activated, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_ready, @@ -5914,6 +5940,7 @@ static struct cam_ctx_ops .release_dev = __cam_isp_ctx_release_dev_in_activated, .config_dev = __cam_isp_ctx_config_dev_in_top_state, .release_hw = __cam_isp_ctx_release_hw_in_activated, + .shutdown_dev = __cam_isp_shutdown_dev, }, .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_activated, diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index c0861f07964e..108dc096d897 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -364,5 +364,16 @@ int cam_isp_context_init(struct cam_isp_context *ctx, */ int cam_isp_context_deinit(struct cam_isp_context *ctx); +/** + * cam_isp_subdev_close_internal() + * + * @brief: Close function for the isp dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_isp_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); #endif /* __CAM_ISP_CONTEXT_H__ */ diff --git a/drivers/cam_isp/cam_isp_dev.c b/drivers/cam_isp/cam_isp_dev.c index 98de92cb3d58..9409c1015c6c 100644 --- a/drivers/cam_isp/cam_isp_dev.c +++ b/drivers/cam_isp/cam_isp_dev.c @@ -71,7 +71,7 @@ static int cam_isp_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_isp_subdev_close(struct v4l2_subdev *sd, +int cam_isp_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -99,6 +99,18 @@ end: return rc; } +static int cam_isp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_ISP); + + if (crm_active) { + CAM_DBG(CAM_ISP, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + return cam_isp_subdev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_isp_subdev_internal_ops = { .close = cam_isp_subdev_close, .open = cam_isp_subdev_open, @@ -120,6 +132,7 @@ static int cam_isp_dev_component_bind(struct device *dev, (const char **)&compat_str); g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops; + g_isp_dev.sd.close_seq_prior = CAM_SD_CLOSE_HIGH_PRIORITY; /* Initialize the v4l2 subdevice first. (create cam_node) */ if (strnstr(compat_str, "ife", strlen(compat_str))) { rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 4147efe58af0..09b0cdb0e881 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -141,6 +141,14 @@ static int cam_isp_update_dual_config( } hw_mgr_res = &res_list_isp_out[i]; + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, + "Invalid isp out resource i %d num_out_res %d", + i, dual_config->num_ports); + rc = -EINVAL; + goto end; + } + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { if (!hw_mgr_res->hw_res[j]) continue; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 1445bd098aa2..930e1eb2687b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1684,6 +1684,8 @@ static int cam_ife_csid_tpg_start(struct cam_ife_csid_hw *csid_hw, CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", 0x600, val); } + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return 0; } @@ -4241,6 +4243,8 @@ int cam_ife_csid_stop(void *hw_priv, res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; } + csid_hw->error_irq_count = 0; + CAM_DBG(CAM_ISP, "%s: Exit\n", __func__); return rc; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c index a22a68e1efe0..8dd9f0f0337e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include @@ -203,6 +203,152 @@ static int cam_tfe_csid_get_format_ipp( return rc; } +static void cam_tfe_csid_enable_path_for_init_frame_drop( + struct cam_tfe_csid_hw *csid_hw, + int res_id) +{ + struct cam_tfe_csid_path_cfg *path_data; + const struct cam_tfe_csid_pxl_reg_offset *pxl_reg = NULL; + const struct cam_tfe_csid_rdi_reg_offset *rdi_reg = NULL; + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *res; + uint32_t val; + + if (!csid_hw) { + CAM_WARN(CAM_ISP, "csid_hw cannot be NULL"); + return; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res_id == CAM_TFE_CSID_PATH_RES_IPP) { + res = &csid_hw->ipp_res; + pxl_reg = csid_reg->ipp_reg; + } else if (res_id >= CAM_TFE_CSID_PATH_RES_RDI_0 && + res_id <= CAM_TFE_CSID_PATH_RES_RDI_2) { + res = &csid_hw->rdi_res[res_id]; + rdi_reg = csid_reg->rdi_reg[res_id]; + } else { + CAM_ERR(CAM_ISP, "Invalid res_id"); + return; + } + + path_data = (struct cam_tfe_csid_path_cfg *)res->res_priv; + + if (!path_data || !path_data->init_frame_drop) + return; + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) + return; + + path_data->res_sof_cnt++; + if ((path_data->res_sof_cnt + 1) < + path_data->res_sof_cnt) { + CAM_WARN(CAM_ISP, "Res %d sof count overflow %d", + res_id, path_data->res_sof_cnt); + return; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id %d SOF cnt:%d init_frame_drop:%d", + csid_hw->hw_intf->hw_idx, res_id, path_data->res_sof_cnt, + path_data->init_frame_drop); + + if ((path_data->res_sof_cnt == + path_data->init_frame_drop) && + pxl_reg) { + CAM_DBG(CAM_ISP, "Enabling pixel IPP Path"); + if (path_data->sync_mode != + CAM_ISP_HW_SYNC_SLAVE) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val |= CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (!(csid_hw->csid_debug & + TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + val &= ~(TFE_CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + } + } else if ((path_data->res_sof_cnt == + path_data->init_frame_drop) && rdi_reg) { + CAM_DBG(CAM_ISP, "Enabling RDI %d Path", res_id); + cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_ctrl_addr); + if (!(csid_hw->csid_debug & + TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + val &= ~(TFE_CSID_PATH_INFO_INPUT_SOF); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_irq_mask_addr); + } + } +} + +static bool cam_tfe_csid_check_path_active(struct cam_tfe_csid_hw *csid_hw) +{ + const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t i; + uint32_t path_status = 1; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* check the IPP path status */ + if (csid_reg->cmn_reg->num_pix) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d IPP path status:%d", + csid_hw->hw_intf->hw_idx, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + + /* Check the RDI path status */ + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_status_addr); + CAM_DBG(CAM_ISP, "CSID:%d RDI:%d path status:%d", + csid_hw->hw_intf->hw_idx, i, path_status); + /* if status is 0 then it is active */ + if (!path_status) + goto end; + } + +end: + /* if status is 0 then path is active */ + return path_status ? false : true; +} + +static void cam_tfe_csid_reset_path_data( + struct cam_tfe_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + struct cam_tfe_csid_path_cfg *path_data = NULL; + + if (!csid_hw || !res) { + CAM_WARN(CAM_ISP, "csid_hw or res cannot be NULL"); + return; + } + path_data = res->res_priv; + + if (path_data) { + path_data->init_frame_drop = 0; + path_data->res_sof_cnt = 0; + } +} + static int cam_tfe_csid_cid_get(struct cam_tfe_csid_hw *csid_hw, int32_t vc, uint32_t dt, uint32_t *cid) { @@ -249,6 +395,7 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw) { struct cam_hw_soc_info *soc_info; const struct cam_tfe_csid_reg_offset *csid_reg; + struct cam_tfe_csid_path_cfg *path_data = NULL; int rc = 0; uint32_t val = 0, i; uint32_t status; @@ -348,6 +495,15 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw) csid_hw->error_irq_count = 0; csid_hw->prev_boot_timestamp = 0; + path_data = (struct cam_tfe_csid_path_cfg *)csid_hw->ipp_res.res_priv; + path_data->res_sof_cnt = 0; + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_data = (struct cam_tfe_csid_path_cfg *) + csid_hw->rdi_res[i].res_priv; + path_data->res_sof_cnt = 0; + } + return rc; } @@ -675,6 +831,7 @@ static int cam_tfe_csid_path_reserve(struct cam_tfe_csid_hw *csid_hw, path_data->height = reserve->in_port->height; path_data->start_line = reserve->in_port->line_start; path_data->end_line = reserve->in_port->line_end; + path_data->usage_type = reserve->in_port->usage_type; csid_hw->event_cb = reserve->event_cb; csid_hw->event_cb_priv = reserve->event_cb_prv; @@ -868,7 +1025,8 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw) { int rc = 0; const struct cam_tfe_csid_reg_offset *csid_reg; - struct cam_hw_soc_info *soc_info; + struct cam_hw_soc_info *soc_info; + struct cam_tfe_csid_path_cfg *path_data = NULL; uint32_t i, val, clk_lvl; unsigned long flags; @@ -949,6 +1107,16 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw) spin_unlock_irqrestore(&csid_hw->spin_lock, flags); cam_tasklet_start(csid_hw->tasklet); + path_data = (struct cam_tfe_csid_path_cfg *)csid_hw->ipp_res.res_priv; + path_data->res_sof_cnt = 0; + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + path_data = (struct cam_tfe_csid_path_cfg *) + csid_hw->rdi_res[i].res_priv; + path_data->res_sof_cnt = 0; + } + + return rc; disable_soc: @@ -1512,11 +1680,14 @@ static int cam_tfe_csid_enable_rdi_path( { const struct cam_tfe_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; + struct cam_tfe_csid_path_cfg *path_data; uint32_t id, val; + bool path_active = false; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; + path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv; if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW || res->res_id > CAM_TFE_CSID_PATH_RES_RDI_2 || @@ -1528,17 +1699,38 @@ static int cam_tfe_csid_enable_rdi_path( return -EINVAL; } - /* resume at frame boundary */ - cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY, - soc_info->reg_map[0].mem_base + - csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + /*Drop one frame extra on RDI for dual TFE use case */ + if (path_data->usage_type == CAM_ISP_TFE_IN_RES_USAGE_DUAL) + path_data->init_frame_drop = 1; + + /*resume at frame boundary */ + if (!path_data->init_frame_drop) { + CAM_DBG(CAM_ISP, "Start RDI:%d path", id); + /* resume at frame boundary */ + cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + } else { + path_active = cam_tfe_csid_check_path_active(csid_hw); + if (path_active) + cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + CAM_DBG(CAM_ISP, + "CSID:%d %s RDI:%d path frame drop %d", + csid_hw->hw_intf->hw_idx, + path_active ? "Starting" : "Not Starting", id, + path_data->init_frame_drop); + } /* Enable the required RDI interrupts */ val = TFE_CSID_PATH_INFO_RST_DONE | TFE_CSID_PATH_ERROR_FIFO_OVERFLOW | TFE_CSID_PATH_RDI_ERROR_CCIF_VIOLATION | TFE_CSID_PATH_RDI_OVERFLOW_IRQ; - if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ) + if ((csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ) || + (path_data->init_frame_drop && !path_active)) val |= TFE_CSID_PATH_INFO_INPUT_SOF; if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ) val |= TFE_CSID_PATH_INFO_INPUT_EOF; @@ -1560,10 +1752,12 @@ static int cam_tfe_csid_disable_rdi_path( uint32_t id, val = 0; const struct cam_tfe_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; + struct cam_tfe_csid_path_cfg *path_data; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; + path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv; if ((res->res_id > CAM_TFE_CSID_PATH_RES_RDI_2) || (!csid_reg->rdi_reg[res->res_id])) { @@ -1599,6 +1793,9 @@ static int cam_tfe_csid_disable_rdi_path( CAM_DBG(CAM_ISP, "CSID:%d res_id:%d", csid_hw->hw_intf->hw_idx, res->res_id); + path_data->init_frame_drop = 0; + path_data->res_sof_cnt = 0; + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); @@ -1964,6 +2161,8 @@ static int cam_tfe_csid_release(void *hw_priv, res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + cam_tfe_csid_reset_path_data(csid_hw, res); + end: mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; @@ -3276,6 +3475,9 @@ handle_fatal_error: complete(&csid_hw->csid_rdin_complete[i]); } + if (irq_status[i] & TFE_CSID_PATH_INFO_INPUT_SOF) + cam_tfe_csid_enable_path_for_init_frame_drop(csid_hw, i); + if ((irq_status[i] & TFE_CSID_PATH_INFO_INPUT_SOF) && (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) { if (!csid_hw->sof_irq_triggered) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h index 55d71df6fada..b13d4b0473f8 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TFE_CSID_HW_H_ @@ -332,7 +332,12 @@ struct cam_tfe_csid_cid_data { * @sensor_fps Sensor fps * @sensor_hbi Sensor horizontal blanking interval * @sensor_vbi Sensor vertical blanking interval - * + * @usage_type: dual or single tfe information + * @init_frame_drop init frame drop value. In dual ife case rdi need to drop one + * more frame than pix. + * @res_sof_cnt path resource sof count value. it used for initial + * frame drop + */ struct cam_tfe_csid_path_cfg { uint32_t vc; @@ -355,6 +360,9 @@ struct cam_tfe_csid_path_cfg { uint32_t sensor_fps; uint32_t sensor_hbi; uint32_t sensor_vbi; + uint32_t usage_type; + uint32_t init_frame_drop; + uint32_t res_sof_cnt; }; /** diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 3796f94bfe4d..44de3efdb383 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -2954,9 +2954,8 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_client = NULL; uint32_t *reg_val_pair; - uint32_t i, j, k, size = 0; + uint32_t i, j, size = 0; uint32_t frame_inc = 0, val; - uint32_t loop_size = 0; bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; @@ -3086,41 +3085,31 @@ static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, wm_data->index, reg_val_pair[j-1]); } - if ((!bus_priv->common_data.is_lite && wm_data->index > 22) || - bus_priv->common_data.is_lite) - loop_size = wm_data->irq_subsample_period + 1; - else - loop_size = 1; - /* WM Image address */ - for (k = 0; k < loop_size; k++) { - if (wm_data->en_ubwc) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - update_buf->wm_update->image_buf[i] + - io_cfg->planes[i].meta_size + - k * frame_inc); - update_buf->wm_update->image_buf_offset[i] = - io_cfg->planes[i].meta_size; - } else if (wm_data->en_cfg & (0x3 << 16)) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - (update_buf->wm_update->image_buf[i] + - wm_data->offset + k * frame_inc)); - update_buf->wm_update->image_buf_offset[i] = - wm_data->offset; - } else { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - (update_buf->wm_update->image_buf[i] + - k * frame_inc)); - update_buf->wm_update->image_buf_offset[i] = 0; - } - - CAM_DBG(CAM_ISP, "WM:%d image address 0x%X", - wm_data->index, reg_val_pair[j-1]); + if (wm_data->en_ubwc) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size); + update_buf->wm_update->image_buf_offset[i] = + io_cfg->planes[i].meta_size; + } else if (wm_data->en_cfg & (0x3 << 16)) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + wm_data->offset)); + update_buf->wm_update->image_buf_offset[i] = + wm_data->offset; + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i]); + update_buf->wm_update->image_buf_offset[i] = 0; } + CAM_DBG(CAM_ISP, "WM:%d image address 0x%X", + wm_data->index, reg_val_pair[j-1]); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->frame_incr, frame_inc); CAM_DBG(CAM_ISP, "WM:%d frame_inc %d", diff --git a/drivers/cam_jpeg/cam_jpeg_context.c b/drivers/cam_jpeg/cam_jpeg_context.c index 93d4ade12c42..20dd4a02127b 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.c +++ b/drivers/cam_jpeg/cam_jpeg_context.c @@ -135,6 +135,12 @@ static int __cam_jpeg_ctx_stop_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_jpeg_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_jpeg_subdev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_jpeg_ctx_state_machine[CAM_CTX_STATE_MAX] = { @@ -148,6 +154,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_jpeg_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_jpeg_shutdown_dev, }, .crm_ops = { }, .irq_ops = NULL, @@ -160,11 +167,30 @@ static struct cam_ctx_ops .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, .dump_dev = __cam_jpeg_ctx_dump_dev_in_acquired, + .shutdown_dev = __cam_jpeg_shutdown_dev, }, .crm_ops = { }, .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, .pagefault_ops = cam_jpeg_context_dump_active_request, }, + /* Ready */ + { + .ioctl_ops = { + .shutdown_dev = __cam_jpeg_shutdown_dev, + }, + }, + /* Flushed */ + { + .ioctl_ops = { + .shutdown_dev = __cam_jpeg_shutdown_dev, + }, + }, + /* Activated */ + { + .ioctl_ops = { + .shutdown_dev = __cam_jpeg_shutdown_dev, + }, + }, }; int cam_jpeg_context_init(struct cam_jpeg_context *ctx, diff --git a/drivers/cam_jpeg/cam_jpeg_context.h b/drivers/cam_jpeg/cam_jpeg_context.h index 85394047d97f..f8a8b06d09f0 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.h +++ b/drivers/cam_jpeg/cam_jpeg_context.h @@ -64,4 +64,16 @@ int cam_jpeg_context_init(struct cam_jpeg_context *ctx, */ int cam_jpeg_context_deinit(struct cam_jpeg_context *ctx); +/** + * cam_jpeg_subdev_close_internal() + * + * @brief: Close function for the jpeg dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_jpeg_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* __CAM_JPEG_CONTEXT_H__ */ diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c index 966bbb1fab06..a47476a06144 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/cam_jpeg/cam_jpeg_dev.c @@ -56,13 +56,12 @@ static int cam_jpeg_subdev_open(struct v4l2_subdev *sd, return 0; } -static int cam_jpeg_subdev_close(struct v4l2_subdev *sd, +int cam_jpeg_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; struct cam_node *node = v4l2_get_subdevdata(sd); - mutex_lock(&g_jpeg_dev.jpeg_mutex); if (g_jpeg_dev.open_cnt <= 0) { CAM_DBG(CAM_JPEG, "JPEG subdev is already closed"); @@ -86,6 +85,18 @@ end: return rc; } +static int cam_jpeg_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_JPEG); + + if (crm_active) { + CAM_DBG(CAM_JPEG, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + return cam_jpeg_subdev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_jpeg_subdev_internal_ops = { .close = cam_jpeg_subdev_close, .open = cam_jpeg_subdev_open, @@ -102,6 +113,7 @@ static int cam_jpeg_dev_component_bind(struct device *dev, struct platform_device *pdev = to_platform_device(dev); g_jpeg_dev.sd.internal_ops = &cam_jpeg_subdev_internal_ops; + g_jpeg_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_subdev_probe(&g_jpeg_dev.sd, pdev, CAM_JPEG_DEV_NAME, CAM_JPEG_DEVICE_TYPE); if (rc) { diff --git a/drivers/cam_lrme/cam_lrme_context.c b/drivers/cam_lrme/cam_lrme_context.c index 537432f982bf..7025b384b1d2 100644 --- a/drivers/cam_lrme/cam_lrme_context.c +++ b/drivers/cam_lrme/cam_lrme_context.c @@ -172,6 +172,12 @@ static int __cam_lrme_ctx_handle_irq_in_activated(void *context, return rc; } +static int __cam_lrme_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_lrme_dev_close_internal(sd, fh); +} + /* top state machine */ static struct cam_ctx_ops cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = { @@ -185,6 +191,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_lrme_ctx_acquire_dev_in_available, + .shutdown_dev = __cam_lrme_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -195,18 +202,25 @@ static struct cam_ctx_ops .config_dev = __cam_lrme_ctx_config_dev_in_activated, .release_dev = __cam_lrme_ctx_release_dev_in_acquired, .start_dev = __cam_lrme_ctx_start_dev_in_acquired, + .shutdown_dev = __cam_lrme_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, }, /* Ready */ { - .ioctl_ops = {}, + .ioctl_ops = { + .shutdown_dev = __cam_lrme_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, }, /* Flushed */ - {}, + { + .ioctl_ops = { + .shutdown_dev = __cam_lrme_shutdown_dev, + }, + }, /* Activate */ { .ioctl_ops = { @@ -215,6 +229,7 @@ static struct cam_ctx_ops .stop_dev = __cam_lrme_ctx_stop_dev_in_activated, .flush_dev = __cam_lrme_ctx_flush_dev_in_activated, .dump_dev = __cam_lrme_ctx_dump_dev_in_activated, + .shutdown_dev = __cam_lrme_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_lrme_ctx_handle_irq_in_activated, diff --git a/drivers/cam_lrme/cam_lrme_context.h b/drivers/cam_lrme/cam_lrme_context.h index bc459cce2f95..34ed1693f944 100644 --- a/drivers/cam_lrme/cam_lrme_context.h +++ b/drivers/cam_lrme/cam_lrme_context.h @@ -30,4 +30,16 @@ int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx, uint32_t index); int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx); +/** + * cam_lrme_dev_close_internal() + * + * @brief: Close function for the jpeg dev + * + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + * + */ +int cam_lrme_dev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_LRME_CONTEXT_H_ */ diff --git a/drivers/cam_lrme/cam_lrme_dev.c b/drivers/cam_lrme/cam_lrme_dev.c index 3735ff9370a2..5055444c3d8a 100644 --- a/drivers/cam_lrme/cam_lrme_dev.c +++ b/drivers/cam_lrme/cam_lrme_dev.c @@ -72,7 +72,7 @@ static int cam_lrme_dev_open(struct v4l2_subdev *sd, return 0; } -static int cam_lrme_dev_close(struct v4l2_subdev *sd, +int cam_lrme_dev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -106,6 +106,18 @@ end: return rc; } +static int cam_lrme_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_LRME); + + if (crm_active) { + CAM_DBG(CAM_LRME, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + return cam_lrme_dev_close_internal(sd, fh); +} + static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = { .open = cam_lrme_dev_open, .close = cam_lrme_dev_close, @@ -126,6 +138,7 @@ static int cam_lrme_component_bind(struct device *dev, return -ENOMEM; } g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops; + g_lrme_dev->sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; mutex_init(&g_lrme_dev->lock); diff --git a/drivers/cam_ope/cam_ope_context.c b/drivers/cam_ope/cam_ope_context.c index d1f39e8fce17..c8be0da353d4 100644 --- a/drivers/cam_ope/cam_ope_context.c +++ b/drivers/cam_ope/cam_ope_context.c @@ -195,6 +195,12 @@ static int __cam_ope_handle_buf_done_in_ready(void *ctx, return cam_context_buf_done_from_hw(ctx, done, evt_id); } +static int __cam_ope_shutdown_dev( + struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return cam_ope_subdev_close_internal(sd, fh); +} + static struct cam_ctx_ops cam_ope_ctx_state_machine[CAM_CTX_STATE_MAX] = { /* Uninit */ @@ -207,6 +213,7 @@ static struct cam_ctx_ops { .ioctl_ops = { .acquire_dev = __cam_ope_acquire_dev_in_available, + .shutdown_dev = __cam_ope_shutdown_dev, }, .crm_ops = {}, .irq_ops = NULL, @@ -219,6 +226,7 @@ static struct cam_ctx_ops .config_dev = __cam_ope_config_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready, .dump_dev = __cam_ope_dump_dev_in_ready, + .shutdown_dev = __cam_ope_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_ope_handle_buf_done_in_ready, @@ -232,14 +240,23 @@ static struct cam_ctx_ops .config_dev = __cam_ope_config_dev_in_ready, .flush_dev = __cam_ope_flush_dev_in_ready, .dump_dev = __cam_ope_dump_dev_in_ready, + .shutdown_dev = __cam_ope_shutdown_dev, }, .crm_ops = {}, .irq_ops = __cam_ope_handle_buf_done_in_ready, .pagefault_ops = cam_ope_context_dump_active_request, }, + /* Flushed */ + { + .ioctl_ops = { + .shutdown_dev = __cam_ope_shutdown_dev, + }, + }, /* Activated */ { - .ioctl_ops = {}, + .ioctl_ops = { + .shutdown_dev = __cam_ope_shutdown_dev, + }, .crm_ops = {}, .irq_ops = NULL, .pagefault_ops = cam_ope_context_dump_active_request, diff --git a/drivers/cam_ope/cam_ope_context.h b/drivers/cam_ope/cam_ope_context.h index e79e0f33225d..5e6d28c3ff59 100644 --- a/drivers/cam_ope/cam_ope_context.h +++ b/drivers/cam_ope/cam_ope_context.h @@ -41,4 +41,12 @@ int cam_ope_context_init(struct cam_ope_context *ctx, */ int cam_ope_context_deinit(struct cam_ope_context *ctx); +/** + * cam_ope_subdev_close_internal() - Close function for the icp dev + * @sd: Pointer to struct v4l2_subdev + * @fh: Pointer to struct v4l2_subdev_fh + */ +int cam_ope_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh); + #endif /* _CAM_OPE_CONTEXT_H_ */ diff --git a/drivers/cam_ope/cam_ope_subdev.c b/drivers/cam_ope/cam_ope_subdev.c index edfdd1e75e77..a04abe3bcf8c 100644 --- a/drivers/cam_ope/cam_ope_subdev.c +++ b/drivers/cam_ope/cam_ope_subdev.c @@ -95,7 +95,7 @@ end: return rc; } -static int cam_ope_subdev_close(struct v4l2_subdev *sd, +int cam_ope_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rc = 0; @@ -134,6 +134,19 @@ end: return rc; } +static int cam_ope_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_OPE); + + if (crm_active) { + CAM_DBG(CAM_OPE, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_ope_subdev_close_internal(sd, fh); +} + const struct v4l2_subdev_internal_ops cam_ope_subdev_internal_ops = { .open = cam_ope_subdev_open, .close = cam_ope_subdev_close, @@ -156,6 +169,7 @@ static int cam_ope_subdev_component_bind(struct device *dev, g_ope_dev.sd.pdev = pdev; g_ope_dev.sd.internal_ops = &cam_ope_subdev_internal_ops; + g_ope_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_subdev_probe(&g_ope_dev.sd, pdev, OPE_DEV_NAME, CAM_OPE_DEVICE_TYPE); if (rc) { diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 0bd68d76fa68..c7d6e8252b02 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -1339,7 +1339,8 @@ static int __cam_req_mgr_check_sync_for_mslave( static int __cam_req_mgr_check_sync_req_is_ready( struct cam_req_mgr_core_link *link, struct cam_req_mgr_core_link *sync_link, - struct cam_req_mgr_slot *slot) + struct cam_req_mgr_slot *slot, + uint32_t trigger) { struct cam_req_mgr_slot *sync_rd_slot = NULL; int64_t req_id = 0, sync_req_id = 0; @@ -1513,7 +1514,8 @@ static int __cam_req_mgr_check_sync_req_is_ready( */ master_slave_diff = sync_frame_duration; do_div(master_slave_diff, 5); - if ((sync_link->sof_timestamp > 0) && + if ((trigger == CAM_TRIGGER_POINT_SOF) && + (sync_link->sof_timestamp > 0) && (sof_timestamp_delta < master_slave_diff) && (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { @@ -1574,7 +1576,8 @@ static int __cam_req_mgr_check_multi_sync_link_ready( } if (link->max_delay == link->sync_link[i]->max_delay) { rc = __cam_req_mgr_check_sync_req_is_ready( - link, link->sync_link[i], slot); + link, link->sync_link[i], + slot, trigger); if (rc < 0) { CAM_DBG(CAM_CRM, "link %x not ready", link->link_hdl); diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index 6ae85e826c5e..350c9ea171bf 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "cam_req_mgr_dev.h" #include "cam_req_mgr_util.h" @@ -32,6 +33,7 @@ static struct cam_req_mgr_device g_dev; struct kmem_cache *g_cam_req_mgr_timer_cachep; +static struct list_head cam_req_mgr_ordered_sd_list; static struct device_attribute camera_debug_sysfs_attr = __ATTR(debug_node, 0600, NULL, cam_debug_sysfs_node_store); @@ -122,6 +124,7 @@ static int cam_req_mgr_open(struct file *filep) spin_unlock_bh(&g_dev.cam_eventq_lock); g_dev.open_cnt++; + g_dev.read_active_dev_id_hdls = 0; rc = cam_mem_mgr_init(); if (rc) { g_dev.open_cnt--; @@ -158,6 +161,7 @@ static unsigned int cam_req_mgr_poll(struct file *f, static int cam_req_mgr_close(struct file *filep) { struct v4l2_subdev *sd; + struct cam_subdev *csd; struct v4l2_fh *vfh = filep->private_data; struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); @@ -172,18 +176,23 @@ static int cam_req_mgr_close(struct file *filep) } cam_req_mgr_handle_core_shutdown(); + g_dev.shutdown_state = true; - list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + list_for_each_entry(csd, &cam_req_mgr_ordered_sd_list, list) { + sd = &csd->sd; if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) continue; - if (sd->internal_ops && sd->internal_ops->close) { + if (sd->internal_ops) { CAM_DBG(CAM_CRM, "Invoke subdev close for device %s", sd->name); - sd->internal_ops->close(sd, subdev_fh); + v4l2_subdev_call(sd, core, ioctl, + CAM_SD_SHUTDOWN, subdev_fh); } } g_dev.open_cnt--; + g_dev.shutdown_state = false; + g_dev.read_active_dev_id_hdls = 0; v4l2_fh_release(filep); spin_lock_bh(&g_dev.cam_eventq_lock); @@ -659,6 +668,51 @@ void cam_subdev_notify_message(u32 subdev_type, } EXPORT_SYMBOL(cam_subdev_notify_message); + +static int cam_req_mgr_ordered_list_cmp(void *priv, + struct list_head *head_1, struct list_head *head_2) +{ + struct cam_subdev *entry_1 = + list_entry(head_1, struct cam_subdev, list); + struct cam_subdev *entry_2 = + list_entry(head_2, struct cam_subdev, list); + int ret = -1; + + if (entry_1->close_seq_prior > entry_2->close_seq_prior) + return 1; + else if (entry_1->close_seq_prior < entry_2->close_seq_prior) + return ret; + else + return 0; +} + +bool cam_req_mgr_is_open(uint64_t dev_id) +{ + bool crm_status; + bool dev_id_status; + + mutex_lock(&g_dev.cam_lock); + crm_status = g_dev.open_cnt ? true : false; + + if (!g_dev.read_active_dev_id_hdls) { + g_dev.active_dev_id_hdls = cam_get_dev_handle_status(); + g_dev.read_active_dev_id_hdls++; + } + + dev_id_status = (g_dev.active_dev_id_hdls & dev_id) ? true : false; + crm_status &= dev_id_status; + mutex_unlock(&g_dev.cam_lock); + + return crm_status; +} +EXPORT_SYMBOL(cam_req_mgr_is_open); + +bool cam_req_mgr_is_shutdown(void) +{ + return g_dev.shutdown_state; +} +EXPORT_SYMBOL(cam_req_mgr_is_shutdown); + int cam_register_subdev(struct cam_subdev *csd) { struct v4l2_subdev *sd; @@ -687,6 +741,10 @@ int cam_register_subdev(struct cam_subdev *csd) sd->entity.pads = NULL; sd->entity.function = csd->ent_function; + list_add(&csd->list, &cam_req_mgr_ordered_sd_list); + list_sort(NULL, &cam_req_mgr_ordered_sd_list, + cam_req_mgr_ordered_list_cmp); + rc = v4l2_device_register_subdev(g_dev.v4l2_dev, sd); if (rc) { CAM_ERR(CAM_CRM, "register subdev failed"); @@ -747,6 +805,7 @@ static int cam_req_mgr_component_master_bind(struct device *dev) goto video_setup_fail; g_dev.open_cnt = 0; + g_dev.shutdown_state = false; mutex_init(&g_dev.cam_lock); spin_lock_init(&g_dev.cam_eventq_lock); mutex_init(&g_dev.dev_lock); @@ -764,6 +823,7 @@ static int cam_req_mgr_component_master_bind(struct device *dev) } g_dev.state = true; + INIT_LIST_HEAD(&cam_req_mgr_ordered_sd_list); if (g_cam_req_mgr_timer_cachep == NULL) { g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer", diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.h b/drivers/cam_req_mgr/cam_req_mgr_dev.h index d374f6cce319..0a55789b7c7d 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.h +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.h @@ -19,6 +19,9 @@ * @cam_lock: per file handle lock * @cam_eventq: event queue * @cam_eventq_lock: lock for event queue + * @shutdown_state: shutdown state + * @active_dev_id_hdls: active dev id handles + * @read_active_dev_id_hdls: read active_dev_id_hdls status */ struct cam_req_mgr_device { struct video_device *video; @@ -30,6 +33,9 @@ struct cam_req_mgr_device { struct mutex cam_lock; struct v4l2_fh *cam_eventq; spinlock_t cam_eventq_lock; + bool shutdown_state; + uint64_t active_dev_id_hdls; + int read_active_dev_id_hdls; }; #define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \ diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.c b/drivers/cam_req_mgr/cam_req_mgr_util.c index 02e4e53ef5d7..00b919fcec30 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.c +++ b/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -14,6 +14,7 @@ #include #include "cam_req_mgr_util.h" #include "cam_debug_util.h" +#include "cam_context.h" static struct cam_req_mgr_util_hdl_tbl *hdl_tbl; static DEFINE_SPINLOCK(hdl_tbl_lock); @@ -209,6 +210,36 @@ int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) return handle; } +int32_t cam_get_dev_handle_info(uint64_t handle, + struct cam_context **ctx, int32_t dev_index) +{ + int32_t idx; + struct v4l2_subdev *sd = (struct v4l2_subdev *)handle; + + for (idx = dev_index + 1; idx < CAM_REQ_MGR_MAX_HANDLES_V2; idx++) { + if (hdl_tbl->hdl[idx].state == HDL_ACTIVE) { + *ctx = (struct cam_context *)cam_get_device_priv( + hdl_tbl->hdl[idx].hdl_value); + if ((*ctx) && !strcmp(sd->name, (*ctx)->dev_name)) + return idx; + } + } + *ctx = NULL; + return CAM_REQ_MGR_MAX_HANDLES_V2; +} + +uint64_t cam_get_dev_handle_status(void) +{ + int32_t idx; + uint64_t active_dev_hdls = 0; + + for (idx = 0; idx < CAM_REQ_MGR_MAX_HANDLES_V2; idx++) + if (hdl_tbl->hdl[idx].state == HDL_ACTIVE) + active_dev_hdls |= hdl_tbl->hdl[idx].dev_id; + + return active_dev_hdls; +} + void *cam_get_device_priv(int32_t dev_hdl) { int idx; diff --git a/drivers/cam_req_mgr/cam_req_mgr_util.h b/drivers/cam_req_mgr/cam_req_mgr_util.h index 0d0fec1f8e01..fb70401306d9 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_util.h +++ b/drivers/cam_req_mgr/cam_req_mgr_util.h @@ -166,4 +166,11 @@ int32_t cam_req_mgr_util_deinit(void); */ int32_t cam_req_mgr_util_free_hdls(void); +/** + * cam_get_dev_handle_status() - get dev handles status + * + * Returns dev handle status + */ +uint64_t cam_get_dev_handle_status(void); + #endif /* _CAM_REQ_MGR_UTIL_API_H_ */ diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h index a6f6d7062c0f..e37d7177c8a3 100644 --- a/drivers/cam_req_mgr/cam_subdev.h +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -21,6 +21,13 @@ enum cam_subdev_message_type_t { CAM_SUBDEV_MESSAGE_CLOCK_UPDATE }; +/* Enum for close sequence priority */ +enum cam_subdev_close_seq_priority { + CAM_SD_CLOSE_HIGH_PRIORITY, + CAM_SD_CLOSE_MEDIUM_PRIORITY, + CAM_SD_CLOSE_LOW_PRIORITY +}; + /** * struct cam_subdev - describes a camera sub-device * @@ -39,6 +46,8 @@ enum cam_subdev_message_type_t { * @ent_function: Media entity function type. Can be: * %CAM_IFE_DEVICE_TYPE - identifies as IFE device. * %CAM_ICP_DEVICE_TYPE - identifies as ICP device. + * @list: list pointer + * @close_seq_prior: cam_subdev_close_seq_priority type * * Each instance of a subdev driver should create this struct, either * stand-alone or embedded in a larger struct. This structure should be @@ -58,6 +67,8 @@ struct cam_subdev { struct v4l2_subdev *sd, enum cam_subdev_message_type_t msg_type, uint32_t data); + struct list_head list; + enum cam_subdev_close_seq_priority close_seq_prior; }; /** @@ -119,4 +130,20 @@ int cam_register_subdev(struct cam_subdev *sd); */ int cam_unregister_subdev(struct cam_subdev *sd); +/** + * cam_req_mgr_is_open() + * + * @brief: This common utility function returns the crm active status + * + * @dev_id: device id type + */ +bool cam_req_mgr_is_open(uint64_t dev_id); + +/** + * cam_req_mgr_is_shutdown() + * + * @brief: This common utility function returns the shutdown state + */ +bool cam_req_mgr_is_shutdown(void); + #endif /* _CAM_SUBDEV_H_ */ diff --git a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 96435bcd5fe6..17b310eee33a 100644 --- a/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -10,6 +10,38 @@ #include "cam_trace.h" #include "camera_main.h" +static int cam_actuator_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_actuator_ctrl_t *a_ctrl = + v4l2_get_subdevdata(sd); + + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "a_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return 0; +} + +static int cam_actuator_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_ACTUATOR); + + if (crm_active) { + CAM_DBG(CAM_ACTUATOR, + "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_actuator_subdev_close_internal(sd, fh); +} + static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -24,6 +56,14 @@ static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd, CAM_ERR(CAM_ACTUATOR, "Failed for driver_cmd: %d", rc); break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_actuator_subdev_close_internal(sd, NULL); + break; default: CAM_ERR(CAM_ACTUATOR, "Invalid ioctl cmd: %u", cmd); rc = -ENOIOCTLCMD; @@ -77,24 +117,6 @@ static long cam_actuator_init_subdev_do_ioctl(struct v4l2_subdev *sd, } #endif -static int cam_actuator_subdev_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct cam_actuator_ctrl_t *a_ctrl = - v4l2_get_subdevdata(sd); - - if (!a_ctrl) { - CAM_ERR(CAM_ACTUATOR, "a_ctrl ptr is NULL"); - return -EINVAL; - } - - mutex_lock(&(a_ctrl->actuator_mutex)); - cam_actuator_shutdown(a_ctrl); - mutex_unlock(&(a_ctrl->actuator_mutex)); - - return 0; -} - static struct v4l2_subdev_core_ops cam_actuator_subdev_core_ops = { .ioctl = cam_actuator_subdev_ioctl, #ifdef CONFIG_COMPAT @@ -127,10 +149,13 @@ static int cam_actuator_init_subdev(struct cam_actuator_ctrl_t *a_ctrl) a_ctrl->v4l2_dev_str.ent_function = CAM_ACTUATOR_DEVICE_TYPE; a_ctrl->v4l2_dev_str.token = a_ctrl; + a_ctrl->v4l2_dev_str.close_seq_prior = + CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(a_ctrl->v4l2_dev_str)); if (rc) - CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev rc: %d", rc); + CAM_ERR(CAM_ACTUATOR, + "Fail with cam_register_subdev rc: %d", rc); return rc; } diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index 59dad9ee4e72..e4e185bb28c1 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -985,6 +985,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, } mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + cci_dev->is_burst_read[master] = true; reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); soc_info = &cci_dev->soc_info; @@ -1256,6 +1257,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, } mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + cci_dev->is_burst_read[master] = false; reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); soc_info = &cci_dev->soc_info; @@ -1622,7 +1624,7 @@ static int32_t cam_cci_read_bytes_v_1_2(struct v4l2_subdev *sd, else read_cfg->num_byte = read_bytes; - cci_dev->is_burst_read = false; + cci_dev->is_burst_read[master] = false; rc = cam_cci_read(sd, c_ctrl); if (rc) { CAM_ERR(CAM_CCI, "failed to read rc:%d", rc); @@ -1639,7 +1641,6 @@ static int32_t cam_cci_read_bytes_v_1_2(struct v4l2_subdev *sd, } while (read_bytes); ERROR: - cci_dev->is_burst_read = false; return rc; } @@ -1704,10 +1705,8 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, read_cfg->num_byte = read_bytes; if (read_cfg->num_byte >= CCI_READ_MAX) { - cci_dev->is_burst_read = true; rc = cam_cci_burst_read(sd, c_ctrl); } else { - cci_dev->is_burst_read = false; rc = cam_cci_read(sd, c_ctrl); } if (rc) { @@ -1726,7 +1725,6 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, } while (read_bytes); ERROR: - cci_dev->is_burst_read = false; return rc; } diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 8b5ab58539f1..e496ca83cf65 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_cci_dev.h" @@ -112,7 +112,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) (!rd_done_th_assert)) { cci_dev->cci_master_info[MASTER_0].status = 0; rd_done_th_assert = true; - if (cci_dev->is_burst_read) + if (cci_dev->is_burst_read[MASTER_0]) complete( &cci_dev->cci_master_info[MASTER_0].th_complete); complete(&cci_dev->cci_master_info[MASTER_0].rd_done); @@ -168,7 +168,7 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) (!rd_done_th_assert)) { cci_dev->cci_master_info[MASTER_1].status = 0; rd_done_th_assert = true; - if (cci_dev->is_burst_read) + if (cci_dev->is_burst_read[MASTER_1]) complete( &cci_dev->cci_master_info[MASTER_1].th_complete); complete(&cci_dev->cci_master_info[MASTER_1].rd_done); diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h index 46cf0315dcab..83359150fc95 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_DEV_H_ @@ -50,8 +50,8 @@ #define CCI_READ_MAX 256 #define CCI_READ_MAX_V_1_2 0xE #define CCI_I2C_READ_MAX_RETRIES 3 -#define CCI_I2C_MAX_READ 10240 -#define CCI_I2C_MAX_WRITE 10240 +#define CCI_I2C_MAX_READ 20480 +#define CCI_I2C_MAX_WRITE 20480 #define CCI_I2C_MAX_BYTE_COUNT 65535 #define CAMX_CCI_DEV_NAME "cam-cci-driver" @@ -224,7 +224,7 @@ struct cci_device { uint32_t cpas_handle; uint32_t irq_status1; spinlock_t lock_status; - bool is_burst_read; + bool is_burst_read[MASTER_MAX]; uint32_t irqs_disabled; struct mutex init_mutex; uint64_t dump_en; diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index 39433a3f43e1..268e6c119824 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_cci_dev.h" @@ -76,6 +76,7 @@ static int cam_cci_init_master(struct cci_device *cci_dev, cci_dev->cci_master_info[master].status = 0; cci_dev->cci_master_info[master].is_initilized = true; + cci_dev->is_burst_read[master] = false; } return 0; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index fbe53591fc6e..204f1df7c653 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -77,29 +77,7 @@ static void cam_csiphy_debug_unregister(void) root_dentry = NULL; } -static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); - int rc = 0; - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_csiphy_core_cfg(csiphy_dev, arg); - if (rc) - CAM_ERR(CAM_CSIPHY, - "Failed in configuring the device: %d", rc); - break; - default: - CAM_ERR(CAM_CSIPHY, "Wrong ioctl : %d", cmd); - rc = -ENOIOCTLCMD; - break; - } - - return rc; -} - -static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, +static int cam_csiphy_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct csiphy_device *csiphy_dev = @@ -117,6 +95,49 @@ static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_CSIPHY); + + if (crm_active) { + CAM_DBG(CAM_CSIPHY, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_csiphy_subdev_close_internal(sd, fh); +} + +static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_csiphy_core_cfg(csiphy_dev, arg); + if (rc) + CAM_ERR(CAM_CSIPHY, + "Failed in configuring the device: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_csiphy_subdev_close_internal(sd, NULL); + break; + default: + CAM_ERR(CAM_CSIPHY, "Wrong ioctl : %d", cmd); + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + #ifdef CONFIG_COMPAT static long cam_csiphy_subdev_compat_ioctl(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg) @@ -236,6 +257,8 @@ static int cam_csiphy_component_bind(struct device *dev, cam_csiphy_subdev_handle_message; new_csiphy_dev->v4l2_dev_str.token = new_csiphy_dev; + new_csiphy_dev->v4l2_dev_str.close_seq_prior = + CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(new_csiphy_dev->v4l2_dev_str)); if (rc < 0) { diff --git a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index 2c0f791b6f7e..00d695326bcf 100644 --- a/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -10,28 +10,7 @@ #include "cam_debug_util.h" #include "camera_main.h" -static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct cam_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_eeprom_driver_cmd(e_ctrl, arg); - if (rc) - CAM_ERR(CAM_EEPROM, - "Failed in Driver cmd: %d", rc); - break; - default: - rc = -ENOIOCTLCMD; - break; - } - - return rc; -} - -static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, +static int cam_eeprom_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_eeprom_ctrl_t *e_ctrl = @@ -49,6 +28,48 @@ static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_EEPROM); + + if (crm_active) { + CAM_DBG(CAM_EEPROM, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_eeprom_subdev_close_internal(sd, fh); +} + +static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_eeprom_driver_cmd(e_ctrl, arg); + if (rc) + CAM_ERR(CAM_EEPROM, + "Failed in Driver cmd: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_eeprom_subdev_close_internal(sd, NULL); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl, struct cam_eeprom_i2c_info_t *i2c_info) { @@ -147,6 +168,7 @@ static int cam_eeprom_init_subdev(struct cam_eeprom_ctrl_t *e_ctrl) (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); e_ctrl->v4l2_dev_str.ent_function = CAM_EEPROM_DEVICE_TYPE; e_ctrl->v4l2_dev_str.token = e_ctrl; + e_ctrl->v4l2_dev_str.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(e_ctrl->v4l2_dev_str)); if (rc) diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index 8cda6c3831c8..8fe5b78243f3 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -10,6 +10,7 @@ #include "cam_res_mgr_api.h" #include "cam_common_util.h" #include "cam_packet_util.h" +#include static uint default_on_timer = 2; module_param(default_on_timer, uint, 0644); @@ -1558,8 +1559,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) add_req.trigger_eof = true; /* Active time for the preflash */ flash_data->flash_active_time_ms = - (flash_operation_info->time_on_duration_ns) - / 1000000; + do_div(flash_operation_info->time_on_duration_ns, 1000000); CAM_DBG(CAM_FLASH, "PRECISE FLASH: active_time: %llu", flash_data->flash_active_time_ms); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index 5a4655834eaa..a7f3370a7f8c 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -133,7 +133,8 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, struct cam_flash_query_cap_info flash_cap = {0}; CAM_DBG(CAM_FLASH, "CAM_QUERY_CAP"); - flash_cap.slot_info = fctrl->soc_info.index; + flash_cap.slot_info = fctrl->soc_info.index; + flash_cap.flash_type = soc_private->flash_type; for (i = 0; i < fctrl->flash_num_sources; i++) { flash_cap.max_current_flash[i] = soc_private->flash_max_current[i]; @@ -236,6 +237,37 @@ static const struct of_device_id cam_flash_dt_match[] = { {} }; +static int cam_flash_subdev_close_internal(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_flash_ctrl *fctrl = + v4l2_get_subdevdata(sd); + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + + return 0; +} + +static int cam_flash_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_FLASH); + + if (crm_active) { + CAM_DBG(CAM_FLASH, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_flash_subdev_close_internal(sd, fh); +} + static long cam_flash_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -257,6 +289,14 @@ static long cam_flash_subdev_ioctl(struct v4l2_subdev *sd, "Failed in driver cmd: %d", rc); break; } + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_flash_subdev_close_internal(sd, NULL); + break; default: CAM_ERR(CAM_FLASH, "Invalid ioctl cmd type"); rc = -ENOIOCTLCMD; @@ -328,24 +368,6 @@ static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client) return rc; } -static int cam_flash_subdev_close(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct cam_flash_ctrl *fctrl = - v4l2_get_subdevdata(sd); - - if (!fctrl) { - CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); - return -EINVAL; - } - - mutex_lock(&fctrl->flash_mutex); - cam_flash_shutdown(fctrl); - mutex_unlock(&fctrl->flash_mutex); - - return 0; -} - static struct v4l2_subdev_core_ops cam_flash_subdev_core_ops = { .ioctl = cam_flash_subdev_ioctl, #ifdef CONFIG_COMPAT @@ -375,6 +397,7 @@ static int cam_flash_init_subdev(struct cam_flash_ctrl *fctrl) V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; fctrl->v4l2_dev_str.ent_function = CAM_FLASH_DEVICE_TYPE; fctrl->v4l2_dev_str.token = fctrl; + fctrl->v4l2_dev_str.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(fctrl->v4l2_dev_str)); if (rc) @@ -390,6 +413,7 @@ static int cam_flash_component_bind(struct device *dev, struct cam_flash_ctrl *fctrl = NULL; struct device_node *of_parent = NULL; struct platform_device *pdev = to_platform_device(dev); + struct cam_hw_soc_info *soc_info = NULL; CAM_DBG(CAM_FLASH, "Binding flash component"); if (!pdev->dev.of_node) { @@ -445,6 +469,19 @@ static int cam_flash_component_bind(struct device *dev, fctrl->io_master_info.cci_client->cci_device = fctrl->cci_num; CAM_DBG(CAM_FLASH, "cci-index %d", fctrl->cci_num, rc); + soc_info = &fctrl->soc_info; + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &fctrl->power_info.gpio_num_info); + if ((rc < 0) || (!fctrl->power_info.gpio_num_info)) { + CAM_ERR(CAM_FLASH, "No/Error Flash GPIOs"); + return -EINVAL; + } + rc = cam_sensor_util_regulator_powerup(soc_info); + if (rc < 0) { + CAM_ERR(CAM_FLASH, "regulator power up for flash failed %d", rc); + return rc; + } + fctrl->i2c_data.per_frame = kzalloc(sizeof(struct i2c_settings_array) * MAX_PER_FRAME_ARRAY, GFP_KERNEL); diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index b8416cd15d8b..cc1c9738d2b6 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_FLASH_DEV_H_ @@ -30,6 +30,7 @@ #include "cam_subdev.h" #include "cam_mem_mgr.h" #include "cam_sensor_cmn_header.h" +#include "cam_sensor_util.h" #include "cam_soc_util.h" #include "cam_debug_util.h" #include "cam_sensor_io.h" @@ -137,6 +138,7 @@ struct cam_flash_frame_setting { * @torch_op_current : Torch operational current * @torch_max_current : Max supported current for LED in torch mode * @is_wled_flash : Detection between WLED/LED flash + * @flash_type : Flash type */ struct cam_flash_private_soc { @@ -149,6 +151,7 @@ struct cam_flash_private_soc { uint32_t torch_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; bool is_wled_flash; + uint32_t flash_type; }; struct cam_flash_func_tbl { diff --git a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c index 17b7c7e0aec8..9af39e9560fb 100644 --- a/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c +++ b/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -73,6 +73,12 @@ static int32_t cam_get_source_node_info( soc_private->is_wled_flash = of_property_read_bool(of_node, "wled-flash-support"); + rc = of_property_read_u32(of_node, "flash-type", &soc_private->flash_type); + if (rc) { + CAM_ERR(CAM_FLASH, + "flash-type read failed rc=%d", rc); + } + switch_src_node = of_parse_phandle(of_node, "switch-source", 0); if (!switch_src_node) { CAM_WARN(CAM_FLASH, "switch_src_node NULL"); diff --git a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index b47d90225ca0..a7616d4d19b1 100644 --- a/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -10,29 +10,7 @@ #include "cam_debug_util.h" #include "camera_main.h" -static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_ois_driver_cmd(o_ctrl, arg); - if (rc) - CAM_ERR(CAM_OIS, - "Failed with driver cmd: %d", rc); - break; - default: - CAM_ERR(CAM_OIS, "Wrong IOCTL cmd: %u", cmd); - rc = -ENOIOCTLCMD; - break; - } - - return rc; -} - -static int cam_ois_subdev_close(struct v4l2_subdev *sd, +static int cam_ois_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_ois_ctrl_t *o_ctrl = @@ -50,6 +28,48 @@ static int cam_ois_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_ois_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_OIS); + + if (crm_active) { + CAM_DBG(CAM_OIS, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_ois_subdev_close_internal(sd, fh); +} + +static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ois_driver_cmd(o_ctrl, arg); + if (rc) + CAM_ERR(CAM_OIS, + "Failed with driver cmd: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + rc = cam_ois_subdev_close_internal(sd, NULL); + break; + default: + CAM_ERR(CAM_OIS, "Wrong IOCTL cmd: %u", cmd); + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + static int32_t cam_ois_update_i2c_info(struct cam_ois_ctrl_t *o_ctrl, struct cam_ois_i2c_info_t *i2c_info) { @@ -144,6 +164,7 @@ static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); o_ctrl->v4l2_dev_str.ent_function = CAM_OIS_DEVICE_TYPE; o_ctrl->v4l2_dev_str.token = o_ctrl; + o_ctrl->v4l2_dev_str.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(o_ctrl->v4l2_dev_str)); if (rc) diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c index 92a5d940f339..d4982ab2311e 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -9,29 +9,7 @@ #include "cam_sensor_core.h" #include "camera_main.h" -static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - int rc = 0; - struct cam_sensor_ctrl_t *s_ctrl = - v4l2_get_subdevdata(sd); - - switch (cmd) { - case VIDIOC_CAM_CONTROL: - rc = cam_sensor_driver_cmd(s_ctrl, arg); - if (rc) - CAM_ERR(CAM_SENSOR, - "Failed in Driver cmd: %d", rc); - break; - default: - CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); - rc = -ENOIOCTLCMD; - break; - } - return rc; -} - -static int cam_sensor_subdev_close(struct v4l2_subdev *sd, +static int cam_sensor_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct cam_sensor_ctrl_t *s_ctrl = @@ -49,6 +27,49 @@ static int cam_sensor_subdev_close(struct v4l2_subdev *sd, return 0; } +static int cam_sensor_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + bool crm_active = cam_req_mgr_is_open(CAM_SENSOR); + + if (crm_active) { + CAM_DBG(CAM_SENSOR, "CRM is ACTIVE, close should be from CRM"); + return 0; + } + + return cam_sensor_subdev_close_internal(sd, fh); +} + +static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_sensor_driver_cmd(s_ctrl, arg); + if (rc) + CAM_ERR(CAM_SENSOR, + "Failed in Driver cmd: %d", rc); + break; + case CAM_SD_SHUTDOWN: + if (!cam_req_mgr_is_shutdown()) { + CAM_ERR(CAM_CORE, "SD shouldn't come from user space"); + return 0; + } + + rc = cam_sensor_subdev_close_internal(sd, NULL); + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); + rc = -ENOIOCTLCMD; + break; + } + return rc; +} + #ifdef CONFIG_COMPAT static long cam_sensor_init_subdev_do_ioctl(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg) @@ -122,6 +143,8 @@ static int cam_sensor_init_subdev_params(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->v4l2_dev_str.ent_function = CAM_SENSOR_DEVICE_TYPE; s_ctrl->v4l2_dev_str.token = s_ctrl; + s_ctrl->v4l2_dev_str.close_seq_prior = + CAM_SD_CLOSE_MEDIUM_PRIORITY; rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str)); if (rc) diff --git a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h index e37314a46571..6cece10403c9 100644 --- a/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h +++ b/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SENSOR_I2C_H_ @@ -18,7 +18,7 @@ #define I2C_COMPARE_MATCH 0 #define I2C_COMPARE_MISMATCH 1 -#define I2C_REG_DATA_MAX (10*1024) +#define I2C_REG_DATA_MAX (20*1024) /** * @client: CCI client structure diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 25ab72ae6069..58a248f4c882 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SENSOR_CMN_HEADER_ @@ -345,6 +345,12 @@ enum msm_sensor_camera_id_t { CAMERA_7, CAMERA_8, CAMERA_9, + CAMERA_10, + CAMERA_11, + CAMERA_12, + CAMERA_13, + CAMERA_14, + CAMERA_15, MAX_CAMERAS, }; diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 4147c1dc7409..771ca38fa6d8 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -2407,6 +2407,10 @@ int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl, case SENSOR_CUSTOM_GPIO1: case SENSOR_CUSTOM_GPIO2: + if (!gpio_num_info) { + CAM_ERR(CAM_SENSOR, "failed: No gpio"); + continue; + } if (!gpio_num_info->valid[pd->seq_type]) continue; diff --git a/drivers/cam_utils/cam_soc_icc.c b/drivers/cam_utils/cam_soc_icc.c index a30e0f153b1b..757254777740 100644 --- a/drivers/cam_utils/cam_soc_icc.c +++ b/drivers/cam_utils/cam_soc_icc.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #include #include "cam_soc_bus.h" - +#include /** * struct cam_soc_bus_client_data : Bus client data * @@ -37,8 +37,8 @@ int cam_soc_bus_client_update_request(void *client, unsigned int idx) CAM_DBG(CAM_PERF, "Bus client=[%s] index[%d] ab[%llu] ib[%llu]", bus_client->common_data->name, idx, ab, ib); - rc = icc_set_bw(bus_client_data->icc_data, Bps_to_icc(ab), - Bps_to_icc(ib)); + rc = icc_set_bw(bus_client_data->icc_data, do_div(ab, 1000), + do_div(ib, 1000)); if (rc) { CAM_ERR(CAM_UTIL, "Update request failed, client[%s], idx: %d", @@ -60,8 +60,8 @@ int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib) CAM_DBG(CAM_PERF, "Bus client=[%s] :ab[%llu] ib[%llu]", bus_client->common_data->name, ab, ib); - rc = icc_set_bw(bus_client_data->icc_data, Bps_to_icc(ab), - Bps_to_icc(ib)); + rc = icc_set_bw(bus_client_data->icc_data, do_div(ab, 1000), + do_div(ib, 1000)); if (rc) { CAM_ERR(CAM_UTIL, "Update request failed, client[%s]", bus_client->common_data->name); diff --git a/include/uapi/camera/media/cam_sensor.h b/include/uapi/camera/media/cam_sensor.h index cff997346943..f935a7a702b3 100644 --- a/include/uapi/camera/media/cam_sensor.h +++ b/include/uapi/camera/media/cam_sensor.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef __UAPI_CAM_SENSOR_H__ @@ -476,6 +476,7 @@ struct cam_flash_query_curr { * @max_current_flash : max supported current for flash * @max_duration_flash : max flash turn on duration * @max_current_torch : max supported current for torch + * @flash_type : Indicates about the flash type -I2C,GPIO,PMIC * */ struct cam_flash_query_cap_info { @@ -483,6 +484,7 @@ struct cam_flash_query_cap_info { __u32 max_current_flash[CAM_FLASH_MAX_LED_TRIGGERS]; __u32 max_duration_flash[CAM_FLASH_MAX_LED_TRIGGERS]; __u32 max_current_torch[CAM_FLASH_MAX_LED_TRIGGERS]; + __u32 flash_type; } __attribute__ ((packed)); #endif