Merge "msm: camera: core: remove extra stop during release" into dev/msm-4.9-camx
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt b/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt
new file mode 100644
index 0000000..9a37922
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-lrme.txt
@@ -0,0 +1,149 @@
+* Qualcomm Technologies, Inc. MSM Camera LRME
+
+The MSM camera Low Resolution Motion Estimation device provides dependency
+definitions for enabling Camera LRME HW. MSM camera LRME is implemented in
+multiple device nodes. The root LRME device node has properties defined to
+hint the driver about the LRME HW nodes available during the probe sequence.
+Each node has multiple properties defined for interrupts, clocks and
+regulators.
+
+=======================
+Required Node Structure
+=======================
+LRME root interface node takes care of the handling LRME high level
+driver handling and controls underlying LRME hardware present.
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,cam-lrme"
+
+- compat-hw-name
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,lrme"
+
+- num-lrme
+ Usage: required
+ Value type: <u32>
+ Definition: Number of supported LRME HW blocks
+
+Example:
+ qcom,cam-lrme {
+ compatible = "qcom,cam-lrme";
+ compat-hw-name = "qcom,lrme";
+ num-lrme = <1>;
+ };
+
+=======================
+Required Node Structure
+=======================
+LRME Node provides interface for Low Resolution Motion Estimation hardware
+driver about the device register map, interrupt map, clocks, regulators.
+
+- cell-index
+ Usage: required
+ Value type: <u32>
+ Definition: Node instance number
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,lrme"
+
+- reg-names
+ Usage: optional
+ Value type: <string>
+ Definition: Name of the register resources
+
+- reg
+ Usage: optional
+ Value type: <u32>
+ Definition: Register values
+
+- reg-cam-base
+ Usage: optional
+ Value type: <u32>
+ Definition: Offset of the register space compared to
+ to Camera base register space
+
+- interrupt-names
+ Usage: optional
+ Value type: <string>
+ Definition: Name of the interrupt
+
+- interrupts
+ Usage: optional
+ Value type: <u32>
+ Definition: Interrupt line associated with LRME HW
+
+- regulator-names
+ Usage: required
+ Value type: <string>
+ Definition: Name of the regulator resources for LRME HW
+
+- camss-supply
+ Usage: required
+ Value type: <phandle>
+ Definition: Regulator reference corresponding to the names listed
+ in "regulator-names"
+
+- clock-names
+ Usage: required
+ Value type: <string>
+ Definition: List of clock names required for LRME HW
+
+- clocks
+ Usage: required
+ Value type: <phandle>
+ Definition: List of clocks required for LRME HW
+
+- clock-rates
+ Usage: required
+ Value type: <u32>
+ Definition: List of clocks rates
+
+- clock-cntl-level
+ Usage: required
+ Value type: <string>
+ Definition: List of strings corresponds clock-rates levels
+ Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo
+
+- src-clock-name
+ Usage: required
+ Value type: <string>
+ Definition: Source clock name
+
+Examples:
+ cam_lrme: qcom,lrme@ac6b000 {
+ cell-index = <0>;
+ compatible = "qcom,lrme";
+ reg-names = "lrme";
+ reg = <0xac6b000 0xa00>;
+ reg-cam-base = <0x6b000>;
+ interrupt-names = "lrme";
+ interrupts = <0 476 0>;
+ regulator-names = "camss";
+ camss-supply = <&titan_top_gdsc>;
+ clock-names = "camera_ahb",
+ "camera_axi",
+ "soc_ahb_clk",
+ "cpas_ahb_clk",
+ "camnoc_axi_clk",
+ "lrme_clk_src",
+ "lrme_clk";
+ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+ <&clock_gcc GCC_CAMERA_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&clock_camcc CAM_CC_LRME_CLK_SRC>,
+ <&clock_camcc CAM_CC_LRME_CLK>;
+ clock-rates = <0 0 0 0 0 0 0>,
+ <0 0 0 0 0 19200000 19200000>,
+ <0 0 0 0 0 19200000 19200000>,
+ <0 0 0 0 0 19200000 19200000>;
+ clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo";
+ src-clock-name = "lrme_core_clk_src";
+ };
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 17bcf0955..35a7774 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -434,13 +434,14 @@
"csid0", "csid1", "csid2",
"ife0", "ife1", "ife2", "ipe0",
"ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0",
- "icp0", "jpeg-dma0", "jpeg-enc0", "fd0";
+ "icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas";
client-axi-port-names =
"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
"cam_hf_1", "cam_hf_2", "cam_hf_2",
"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
- "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1";
+ "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
+ "cam_sf_1";
client-bus-camnoc-based;
qcom,axi-port-list {
qcom,axi-port1 {
@@ -529,7 +530,8 @@
cdm-client-names = "vfe",
"jpegdma",
"jpegenc",
- "fd";
+ "fd",
+ "lrmecdm";
status = "ok";
};
@@ -775,7 +777,7 @@
clock-rates =
<0 0 0 0 0 0 384000000 0 0 0 404000000 0>,
<0 0 0 0 0 0 538000000 0 0 0 600000000 0>;
- clock-cntl-level = "svs";
+ clock-cntl-level = "svs", "turbo";
src-clock-name = "ife_csid_clk_src";
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index d867129..d2ee9eb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -157,6 +157,33 @@
compatible = "qcom,msm-cam-smmu";
status = "ok";
+ msm_cam_smmu_lrme {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1038 0x0>,
+ <&apps_smmu 0x1058 0x0>,
+ <&apps_smmu 0x1039 0x0>,
+ <&apps_smmu 0x1059 0x0>;
+ label = "lrme";
+ lrme_iova_mem_map: iova-mem-map {
+ iova-mem-region-shared {
+ /* Shared region is 100MB long */
+ iova-region-name = "shared";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0x6400000>;
+ iova-region-id = <0x1>;
+ status = "ok";
+ };
+ /* IO region is approximately 3.3 GB */
+ iova-mem-region-io {
+ iova-region-name = "io";
+ iova-region-start = <0xd800000>;
+ iova-region-len = <0xd2800000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+
msm_cam_smmu_ife {
compatible = "qcom,msm-cam-smmu-cb";
iommus = <&apps_smmu 0x808 0x0>,
@@ -329,13 +356,14 @@
"csid0", "csid1", "csid2",
"ife0", "ife1", "ife2", "ipe0",
"ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0",
- "icp0", "jpeg-dma0", "jpeg-enc0", "fd0";
+ "icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas0";
client-axi-port-names =
"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_hf_2",
"cam_sf_1", "cam_hf_1", "cam_hf_2", "cam_hf_2",
"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
- "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1";
+ "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
+ "cam_sf_1";
client-bus-camnoc-based;
qcom,axi-port-list {
qcom,axi-port1 {
@@ -415,4 +443,44 @@
};
};
};
+
+ qcom,cam-lrme {
+ compatible = "qcom,cam-lrme";
+ arch-compat = "lrme";
+ status = "ok";
+ };
+
+ cam_lrme: qcom,lrme@ac6b000 {
+ cell-index = <0>;
+ compatible = "qcom,lrme";
+ reg-names = "lrme";
+ reg = <0xac6b000 0xa00>;
+ reg-cam-base = <0x6b000>;
+ interrupt-names = "lrme";
+ interrupts = <0 476 0>;
+ regulator-names = "camss";
+ camss-supply = <&titan_top_gdsc>;
+ clock-names = "camera_ahb",
+ "camera_axi",
+ "soc_ahb_clk",
+ "cpas_ahb_clk",
+ "camnoc_axi_clk",
+ "lrme_clk_src",
+ "lrme_clk";
+ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+ <&clock_gcc GCC_CAMERA_AXI_CLK>,
+ <&clock_camcc CAM_CC_SOC_AHB_CLK>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+ <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+ <&clock_camcc CAM_CC_LRME_CLK_SRC>,
+ <&clock_camcc CAM_CC_LRME_CLK>;
+ clock-rates = <0 0 0 0 0 200000000 200000000>,
+ <0 0 0 0 0 269000000 269000000>,
+ <0 0 0 0 0 320000000 320000000>,
+ <0 0 0 0 0 400000000 400000000>;
+
+ clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo";
+ src-clock-name = "lrme_clk_src";
+ status = "ok";
+ };
};
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index 48fa1c0..9e0aee9 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -10,3 +10,4 @@
obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
index d039d75..7447e1d 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -134,8 +134,8 @@
rc = ctx->state_machine[ctx->state].crm_ops.unlink(
ctx, unlink);
} else {
- CAM_ERR(CAM_CORE, "No crm unlink in dev %d, state %d",
- ctx->dev_hdl, ctx->state);
+ CAM_ERR(CAM_CORE, "No crm unlink in dev %d, name %s, state %d",
+ ctx->dev_hdl, ctx->dev_name, ctx->state);
rc = -EPROTO;
}
mutex_unlock(&ctx->ctx_mutex);
@@ -196,6 +196,30 @@
return rc;
}
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+ struct cam_req_mgr_link_evt_data *process_evt)
+{
+ int rc;
+
+ if (!ctx->state_machine) {
+ CAM_ERR(CAM_CORE, "Context is not ready");
+ return -EINVAL;
+ }
+
+ mutex_lock(&ctx->ctx_mutex);
+ if (ctx->state_machine[ctx->state].crm_ops.process_evt) {
+ rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx,
+ process_evt);
+ } else {
+ CAM_ERR(CAM_CORE, "No crm process evt in dev %d, state %d",
+ ctx->dev_hdl, ctx->state);
+ rc = -EPROTO;
+ }
+ mutex_unlock(&ctx->ctx_mutex);
+
+ return rc;
+}
+
int cam_context_handle_acquire_dev(struct cam_context *ctx,
struct cam_acquire_dev_cmd *cmd)
{
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
index 6d1589e..d536663 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -56,6 +56,7 @@
* @num_in_acked: Number of in fence acked
* @num_out_acked: Number of out fence acked
* @flushed: Request is flushed
+ * @error_flag: Flag an error
* @ctx: The context to which this request belongs
*
*/
@@ -73,6 +74,7 @@
uint32_t num_in_acked;
uint32_t num_out_acked;
int flushed;
+ bool error_flag;
struct cam_context *ctx;
};
@@ -120,6 +122,8 @@
struct cam_req_mgr_apply_request *apply);
int (*flush_req)(struct cam_context *ctx,
struct cam_req_mgr_flush_request *flush);
+ int (*process_evt)(struct cam_context *ctx,
+ struct cam_req_mgr_link_evt_data *evt_data);
};
@@ -270,6 +274,18 @@
struct cam_req_mgr_flush_request *apply);
/**
+ * cam_context_handle_crm_process_evt()
+ *
+ * @brief: Handle process event command
+ *
+ * @ctx: Object pointer for cam_context
+ * @process_evt: process event command payload
+ *
+ */
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+ struct cam_req_mgr_link_evt_data *process_evt);
+
+/**
* cam_context_handle_acquire_dev()
*
* @brief: Handle acquire device command
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index 32f6572..0a1c2cf 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -178,6 +178,7 @@
req->ctx = NULL;
req->flushed = 0;
spin_lock(&ctx->lock);
+ list_del_init(&req->list);
list_add_tail(&req->list, &ctx->free_req_list);
spin_unlock(&ctx->lock);
}
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index 1f0213e..3b0adc4 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -309,6 +309,26 @@
return cam_context_handle_crm_flush_req(ctx, flush);
}
+static int __cam_node_crm_process_evt(
+ struct cam_req_mgr_link_evt_data *evt_data)
+{
+ struct cam_context *ctx = NULL;
+
+ if (!evt_data) {
+ CAM_ERR(CAM_CORE, "Invalid process event request payload");
+ return -EINVAL;
+ }
+
+ ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl);
+ if (!ctx) {
+ CAM_ERR(CAM_CORE, "Can not get context for handle %d",
+ evt_data->dev_hdl);
+ return -EINVAL;
+ }
+
+ return cam_context_handle_crm_process_evt(ctx, evt_data);
+}
+
int cam_node_deinit(struct cam_node *node)
{
if (node)
@@ -361,6 +381,7 @@
node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info;
node->crm_node_intf.link_setup = __cam_node_crm_link_setup;
node->crm_node_intf.flush_req = __cam_node_crm_flush_req;
+ node->crm_node_intf.process_evt = __cam_node_crm_process_evt;
mutex_init(&node->list_mutex);
INIT_LIST_HEAD(&node->free_ctx_list);
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index e51d350..a8855ae 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -109,7 +109,19 @@
new_write_idx << BYTE_WORD_SHIFT);
}
+ /*
+ * To make sure command data in a command queue before
+ * updating write index
+ */
+ wmb();
+
q->qhdr_write_idx = new_write_idx;
+
+ /*
+ * Before raising interrupt make sure command data is ready for
+ * firmware to process
+ */
+ wmb();
cam_io_w((uint32_t)INTR_ENABLE,
g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT);
err:
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 93926a78..340a1e2 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -1644,6 +1644,7 @@
for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+ hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap = NULL;
cam_icp_hw_mgr_clk_info_update(hw_mgr, &hw_mgr->ctx_data[ctx_id]);
hw_mgr->ctx_data[ctx_id].clk_info.curr_fc = 0;
hw_mgr->ctx_data[ctx_id].clk_info.base_clk = 0;
@@ -2068,6 +2069,7 @@
ctx_data = config_args->ctxt_to_hw_map;
mutex_lock(&ctx_data->ctx_mutex);
if (!ctx_data->in_use) {
+ mutex_unlock(&ctx_data->ctx_mutex);
CAM_ERR(CAM_ICP, "ctx is not in use");
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index ae6b149..5c95dad 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -216,19 +216,7 @@
continue;
}
- if (!bubble_state) {
- CAM_DBG(CAM_ISP,
- "Sync with success: req %lld res 0x%x fd 0x%x",
- req->request_id,
- req_isp->fence_map_out[j].resource_handle,
- req_isp->fence_map_out[j].sync_id);
-
- rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
- CAM_SYNC_STATE_SIGNALED_SUCCESS);
- if (rc)
- CAM_DBG(CAM_ISP, "Sync failed with rc = %d",
- rc);
- } else if (!req_isp->bubble_report) {
+ if (req->error_flag || !req_isp->bubble_report) {
CAM_DBG(CAM_ISP,
"Sync with failure: req %lld res 0x%x fd 0x%x",
req->request_id,
@@ -240,6 +228,18 @@
if (rc)
CAM_ERR(CAM_ISP, "Sync failed with rc = %d",
rc);
+ } else if (!bubble_state) {
+ CAM_DBG(CAM_ISP,
+ "Sync with success: req %lld res 0x%x fd 0x%x",
+ req->request_id,
+ req_isp->fence_map_out[j].resource_handle,
+ req_isp->fence_map_out[j].sync_id);
+
+ rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+ CAM_SYNC_STATE_SIGNALED_SUCCESS);
+ if (rc)
+ CAM_DBG(CAM_ISP, "Sync failed with rc = %d",
+ rc);
} else {
/*
* Ignore the buffer done if bubble detect is on
@@ -304,7 +304,7 @@
ctx_isp->sof_timestamp_val);
CAM_DBG(CAM_ISP, " sof status:%d", sof_event_status);
- if (cam_req_mgr_notify_frame_message(&req_msg,
+ if (cam_req_mgr_notify_message(&req_msg,
V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT))
CAM_ERR(CAM_ISP,
"Error in notifying the sof time for req id:%lld",
@@ -2091,6 +2091,34 @@
return rc;
}
+static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
+ struct cam_req_mgr_link_evt_data *link_evt_data)
+{
+ int rc = 0;
+ struct cam_ctx_request *req_current;
+ struct cam_ctx_request *req_prev;
+ bool req_id_found = false;
+
+ list_for_each_entry_safe(req_current, req_prev,
+ &ctx->pending_req_list, list) {
+ if (link_evt_data->req_id == req_current->request_id) {
+ req_current->error_flag = true;
+ req_id_found = true;
+ CAM_DBG(CAM_ISP,
+ "flagging req_id=%lld as error on link_hdl: %d for dev_hdl: %d",
+ link_evt_data->req_id, link_evt_data->link_hdl,
+ link_evt_data->dev_hdl);
+ }
+ }
+
+ if (!req_id_found) {
+ CAM_ERR(CAM_ISP,
+ "req_id=%lld not found in the pending list ",
+ link_evt_data->req_id);
+ rc = -EINVAL;
+ }
+ return rc;
+}
static int __cam_isp_ctx_unlink_in_activated(struct cam_context *ctx,
struct cam_req_mgr_core_dev_link_setup *unlink)
{
@@ -2223,6 +2251,7 @@
.unlink = __cam_isp_ctx_unlink_in_activated,
.apply_req = __cam_isp_ctx_apply_req,
.flush_req = __cam_isp_ctx_flush_req_in_top_state,
+ .process_evt = __cam_isp_ctx_process_evt,
},
.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
},
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index d5a5347..8880cb5 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -41,10 +41,12 @@
(CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1)
#define CAM_ISP_GENERIC_BLOB_TYPE_MAX \
- (CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG + 1)
+ (CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG + 1)
static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = {
CAM_ISP_HW_CMD_GET_HFR_UPDATE,
+ CAM_ISP_HW_CMD_CLOCK_UPDATE,
+ CAM_ISP_HW_CMD_BW_UPDATE,
};
static struct cam_ife_hw_mgr g_ife_hw_mgr;
@@ -866,7 +868,7 @@
struct cam_ife_hw_mgr *ife_hw_mgr;
struct cam_ife_hw_mgr_res *csid_res;
struct cam_ife_hw_mgr_res *cid_res;
- struct cam_hw_intf *hw_intf;
+ struct cam_hw_intf *hw_intf;
struct cam_csid_hw_reserve_resource_args csid_acquire;
ife_hw_mgr = ife_ctx->hw_mgr;
@@ -2109,6 +2111,168 @@
return rc;
}
+static int cam_isp_blob_clock_update(
+ uint32_t blob_type,
+ struct cam_isp_generic_blob_info *blob_info,
+ struct cam_isp_clock_config *clock_config,
+ struct cam_hw_prepare_update_args *prepare)
+{
+ struct cam_ife_hw_mgr_ctx *ctx = NULL;
+ struct cam_ife_hw_mgr_res *hw_mgr_res;
+ struct cam_hw_intf *hw_intf;
+ struct cam_vfe_clock_update_args clock_upd_args;
+ uint64_t clk_rate = 0;
+ int rc = -EINVAL;
+ uint32_t i;
+ uint32_t j;
+
+ ctx = prepare->ctxt_to_hw_map;
+
+ CAM_DBG(CAM_ISP,
+ "usage=%u left_clk= %lu right_clk=%lu",
+ clock_config->usage_type,
+ clock_config->left_pix_hz,
+ clock_config->right_pix_hz);
+
+ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ clk_rate = 0;
+ if (!hw_mgr_res->hw_res[i])
+ continue;
+
+ if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+ if (i == CAM_ISP_HW_SPLIT_LEFT)
+ clk_rate =
+ clock_config->left_pix_hz;
+ else
+ clk_rate =
+ clock_config->right_pix_hz;
+ else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
+ && (hw_mgr_res->res_id <=
+ CAM_ISP_HW_VFE_IN_RDI3))
+ for (j = 0; j < clock_config->num_rdi; j++)
+ clk_rate = max(clock_config->rdi_hz[j],
+ clk_rate);
+ else
+ if (hw_mgr_res->hw_res[i]) {
+ CAM_ERR(CAM_ISP, "Invalid res_id %u",
+ hw_mgr_res->res_id);
+ rc = -EINVAL;
+ return rc;
+ }
+
+ hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+ if (hw_intf && hw_intf->hw_ops.process_cmd) {
+ clock_upd_args.node_res =
+ hw_mgr_res->hw_res[i];
+ CAM_DBG(CAM_ISP,
+ "res_id=%u i= %d clk=%llu\n",
+ hw_mgr_res->res_id, i, clk_rate);
+
+ clock_upd_args.clk_rate = clk_rate;
+
+ rc = hw_intf->hw_ops.process_cmd(
+ hw_intf->hw_priv,
+ CAM_ISP_HW_CMD_CLOCK_UPDATE,
+ &clock_upd_args,
+ sizeof(
+ struct cam_vfe_clock_update_args));
+ if (rc)
+ CAM_ERR(CAM_ISP, "Clock Update failed");
+ } else
+ CAM_WARN(CAM_ISP, "NULL hw_intf!");
+ }
+ }
+
+ return rc;
+}
+
+static int cam_isp_blob_bw_update(
+ uint32_t blob_type,
+ struct cam_isp_generic_blob_info *blob_info,
+ struct cam_isp_bw_config *bw_config,
+ struct cam_hw_prepare_update_args *prepare)
+{
+ struct cam_ife_hw_mgr_ctx *ctx = NULL;
+ struct cam_ife_hw_mgr_res *hw_mgr_res;
+ struct cam_hw_intf *hw_intf;
+ struct cam_vfe_bw_update_args bw_upd_args;
+ uint64_t cam_bw_bps = 0;
+ uint64_t ext_bw_bps = 0;
+ int rc = -EINVAL;
+ uint32_t i;
+
+ ctx = prepare->ctxt_to_hw_map;
+
+ CAM_DBG(CAM_ISP,
+ "usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n"
+ "right cam_bw_bps=%llu ext_bw_bps=%llu",
+ bw_config->usage_type,
+ bw_config->left_pix_vote.cam_bw_bps,
+ bw_config->left_pix_vote.ext_bw_bps,
+ bw_config->right_pix_vote.cam_bw_bps,
+ bw_config->right_pix_vote.ext_bw_bps);
+
+ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!hw_mgr_res->hw_res[i])
+ continue;
+
+ if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+ if (i == CAM_ISP_HW_SPLIT_LEFT) {
+ cam_bw_bps =
+ bw_config->left_pix_vote.cam_bw_bps;
+ ext_bw_bps =
+ bw_config->left_pix_vote.ext_bw_bps;
+ } else {
+ cam_bw_bps =
+ bw_config->right_pix_vote.cam_bw_bps;
+ ext_bw_bps =
+ bw_config->right_pix_vote.ext_bw_bps;
+ }
+ else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
+ && (hw_mgr_res->res_id <=
+ CAM_ISP_HW_VFE_IN_RDI3)) {
+ uint32_t idx = hw_mgr_res->res_id -
+ CAM_ISP_HW_VFE_IN_RDI0;
+ if (idx >= bw_config->num_rdi)
+ continue;
+
+ cam_bw_bps =
+ bw_config->rdi_vote[idx].cam_bw_bps;
+ ext_bw_bps =
+ bw_config->rdi_vote[idx].ext_bw_bps;
+ } else
+ if (hw_mgr_res->hw_res[i]) {
+ CAM_ERR(CAM_ISP, "Invalid res_id %u",
+ hw_mgr_res->res_id);
+ rc = -EINVAL;
+ return rc;
+ }
+
+ hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+ if (hw_intf && hw_intf->hw_ops.process_cmd) {
+ bw_upd_args.node_res =
+ hw_mgr_res->hw_res[i];
+
+ bw_upd_args.camnoc_bw_bytes = cam_bw_bps;
+ bw_upd_args.external_bw_bytes = ext_bw_bps;
+
+ rc = hw_intf->hw_ops.process_cmd(
+ hw_intf->hw_priv,
+ CAM_ISP_HW_CMD_BW_UPDATE,
+ &bw_upd_args,
+ sizeof(struct cam_vfe_bw_update_args));
+ if (rc)
+ CAM_ERR(CAM_ISP, "BW Update failed");
+ } else
+ CAM_WARN(CAM_ISP, "NULL hw_intf!");
+ }
+ }
+
+ return rc;
+}
+
static int cam_isp_packet_generic_blob_handler(void *user_data,
uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
{
@@ -2146,6 +2310,26 @@
CAM_ERR(CAM_ISP, "HFR Update Failed");
}
break;
+ case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: {
+ struct cam_isp_clock_config *clock_config =
+ (struct cam_isp_clock_config *)blob_data;
+
+ rc = cam_isp_blob_clock_update(blob_type, blob_info,
+ clock_config, prepare);
+ if (rc)
+ CAM_ERR(CAM_ISP, "Clock Update Failed");
+ }
+ break;
+ case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
+ struct cam_isp_bw_config *bw_config =
+ (struct cam_isp_bw_config *)blob_data;
+
+ rc = cam_isp_blob_bw_update(blob_type, blob_info,
+ bw_config, prepare);
+ if (rc)
+ CAM_ERR(CAM_ISP, "Bandwidth Update Failed");
+ }
+ break;
default:
CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
break;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index 876a540..3606af9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -97,6 +97,8 @@
struct cam_ife_hw_mgr_res *hw_mgr_res;
struct cam_isp_resource_node *res;
struct cam_isp_hw_dual_isp_update_args dual_isp_update_args;
+ uint32_t outport_id;
+ uint32_t ports_plane_idx;
size_t len = 0;
uint32_t *cpu_addr;
uint32_t i, j;
@@ -113,6 +115,14 @@
dual_config = (struct cam_isp_dual_config *)cpu_addr;
for (i = 0; i < dual_config->num_ports; i++) {
+
+ if (i >= CAM_ISP_IFE_OUT_RES_MAX) {
+ CAM_ERR(CAM_UTIL,
+ "failed update for i:%d > size_isp_out:%d",
+ i, size_isp_out);
+ return -EINVAL;
+ }
+
hw_mgr_res = &res_list_isp_out[i];
for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) {
if (!hw_mgr_res->hw_res[j])
@@ -122,6 +132,20 @@
continue;
res = hw_mgr_res->hw_res[j];
+
+ if (res->res_id < CAM_ISP_IFE_OUT_RES_BASE ||
+ res->res_id >= CAM_ISP_IFE_OUT_RES_MAX)
+ continue;
+
+ outport_id = res->res_id & 0xFF;
+
+ ports_plane_idx = (j * (dual_config->num_ports *
+ CAM_PACKET_MAX_PLANES)) +
+ (outport_id * CAM_PACKET_MAX_PLANES);
+
+ if (dual_config->stripes[ports_plane_idx].port_id == 0)
+ continue;
+
dual_isp_update_args.split_id = j;
dual_isp_update_args.res = res;
dual_isp_update_args.dual_cfg = dual_config;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index deef41f..07217f5 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -392,6 +392,7 @@
* for RDI, set mode to none
* @master_idx: For Slave reservation, Give master IFE instance Index.
* Slave will synchronize with master Start and stop operations
+ * @clk_rate Clock rate
*
*/
struct cam_ife_csid_path_cfg {
@@ -409,6 +410,7 @@
uint32_t height;
enum cam_isp_hw_sync_mode sync_mode;
uint32_t master_idx;
+ uint64_t clk_rate;
};
/**
@@ -432,6 +434,7 @@
* @csid_rdin_reset_complete: rdi n completion
* @csid_debug: csid debug information to enable the SOT, EOT,
* SOF, EOF, measure etc in the csid hw
+ * @clk_rate Clock rate
*
*/
struct cam_ife_csid_hw {
@@ -452,6 +455,7 @@
struct completion csid_ipp_complete;
struct completion csid_rdin_complete[CAM_IFE_CSID_RDI_MAX];
uint64_t csid_debug;
+ uint64_t clk_rate;
};
int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf,
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
index c81e6db..b634e38b 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
@@ -90,6 +90,8 @@
CAM_ISP_HW_CMD_GET_HFR_UPDATE,
CAM_ISP_HW_CMD_GET_SECURE_MODE,
CAM_ISP_HW_CMD_STRIPE_UPDATE,
+ CAM_ISP_HW_CMD_CLOCK_UPDATE,
+ CAM_ISP_HW_CMD_BW_UPDATE,
CAM_ISP_HW_CMD_MAX,
};
@@ -192,6 +194,8 @@
void *data;
struct cam_isp_hw_get_wm_update *wm_update;
struct cam_isp_port_hfr_config *hfr_update;
+ struct cam_isp_clock_config *clock_update;
+ struct cam_isp_bw_config *bw_update;
};
};
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
index b7ec511..b771ec6 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
@@ -161,6 +161,31 @@
};
/*
+ * struct cam_vfe_clock_update_args:
+ *
+ * @node_res: Resource to get the time stamp
+ * @clk_rate: Clock rate requested
+ */
+struct cam_vfe_clock_update_args {
+ struct cam_isp_resource_node *node_res;
+ uint64_t clk_rate;
+};
+
+/*
+ * struct cam_vfe_bw_update_args:
+ *
+ * @node_res: Resource to get the time stamp
+ * @camnoc_bw_bytes: Bandwidth vote request for CAMNOC
+ * @external_bw_bytes: Bandwidth vote request from CAMNOC
+ * out to the rest of the path-to-DDR
+ */
+struct cam_vfe_bw_update_args {
+ struct cam_isp_resource_node *node_res;
+ uint64_t camnoc_bw_bytes;
+ uint64_t external_bw_bytes;
+};
+
+/*
* struct cam_vfe_top_irq_evt_payload:
*
* @Brief: This structure is used to save payload for IRQ
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index d1e1605..d534607 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -264,7 +264,9 @@
goto deinint_vfe_res;
}
- return 0;
+ vfe_hw->hw_state = CAM_HW_STATE_POWER_UP;
+ return rc;
+
deinint_vfe_res:
if (isp_res && isp_res->deinit)
isp_res->deinit(isp_res, NULL, 0);
@@ -650,10 +652,11 @@
switch (cmd_type) {
case CAM_ISP_HW_CMD_GET_CHANGE_BASE:
case CAM_ISP_HW_CMD_GET_REG_UPDATE:
+ case CAM_ISP_HW_CMD_CLOCK_UPDATE:
+ case CAM_ISP_HW_CMD_BW_UPDATE:
rc = core_info->vfe_top->hw_ops.process_cmd(
core_info->vfe_top->top_priv, cmd_type, cmd_args,
arg_size);
-
break;
case CAM_ISP_HW_CMD_GET_BUF_UPDATE:
case CAM_ISP_HW_CMD_GET_HFR_UPDATE:
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
index ac8b497..9a2c12c 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile
@@ -1,11 +1,13 @@
ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils/
ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm/
ccflags-y += -Idrivers/media/platform/msm/camera/cam_core/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include
ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw
obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o cam_vfe_rdi.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index 7baac45..1b8cdf3 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -17,6 +17,8 @@
#include "cam_vfe_top.h"
#include "cam_vfe_top_ver2.h"
#include "cam_debug_util.h"
+#include "cam_cpas_api.h"
+#include "cam_vfe_soc.h"
#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00003F9F
#define CAM_VFE_HW_RESET_HW_VAL 0x00003F87
@@ -29,8 +31,11 @@
struct cam_vfe_top_ver2_priv {
struct cam_vfe_top_ver2_common_data common_data;
- struct cam_vfe_camif *camif;
struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX];
+ unsigned long hw_clk_rate;
+ struct cam_axi_vote hw_axi_vote;
+ struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX];
+ unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX];
};
static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv,
@@ -80,6 +85,174 @@
return 0;
}
+static int cam_vfe_top_set_hw_clk_rate(
+ struct cam_vfe_top_ver2_priv *top_priv)
+{
+ struct cam_hw_soc_info *soc_info = NULL;
+ int i, rc = 0;
+ unsigned long max_clk_rate = 0;
+
+ soc_info = top_priv->common_data.soc_info;
+
+ for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+ if (top_priv->req_clk_rate[i] > max_clk_rate)
+ max_clk_rate = top_priv->req_clk_rate[i];
+ }
+ if (max_clk_rate == top_priv->hw_clk_rate)
+ return 0;
+
+ CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%lld",
+ soc_info->clk_name[soc_info->src_clk_idx],
+ soc_info->src_clk_idx, max_clk_rate);
+
+ rc = cam_soc_util_set_clk_rate(
+ soc_info->clk[soc_info->src_clk_idx],
+ soc_info->clk_name[soc_info->src_clk_idx],
+ max_clk_rate);
+
+ if (!rc)
+ top_priv->hw_clk_rate = max_clk_rate;
+ else
+ CAM_ERR(CAM_ISP, "Set Clock rate failed, rc=%d", rc);
+
+ return rc;
+}
+
+static int cam_vfe_top_set_axi_bw_vote(
+ struct cam_vfe_top_ver2_priv *top_priv)
+{
+ struct cam_axi_vote sum = {0, 0};
+ int i, rc = 0;
+ struct cam_hw_soc_info *soc_info =
+ top_priv->common_data.soc_info;
+ struct cam_vfe_soc_private *soc_private =
+ soc_info->soc_private;
+
+ if (!soc_private) {
+ CAM_ERR(CAM_ISP, "Error soc_private NULL");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+ sum.uncompressed_bw +=
+ top_priv->req_axi_vote[i].uncompressed_bw;
+ sum.compressed_bw +=
+ top_priv->req_axi_vote[i].compressed_bw;
+ }
+
+ CAM_DBG(CAM_ISP, "BW Vote: u=%lld c=%lld",
+ sum.uncompressed_bw,
+ sum.compressed_bw);
+
+ if ((top_priv->hw_axi_vote.uncompressed_bw ==
+ sum.uncompressed_bw) &&
+ (top_priv->hw_axi_vote.compressed_bw ==
+ sum.compressed_bw))
+ return 0;
+
+ rc = cam_cpas_update_axi_vote(
+ soc_private->cpas_handle,
+ &sum);
+ if (!rc) {
+ top_priv->hw_axi_vote.uncompressed_bw = sum.uncompressed_bw;
+ top_priv->hw_axi_vote.compressed_bw = sum.compressed_bw;
+ } else
+ CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
+
+ return rc;
+}
+
+static int cam_vfe_top_clock_update(
+ struct cam_vfe_top_ver2_priv *top_priv,
+ void *cmd_args, uint32_t arg_size)
+{
+ struct cam_vfe_clock_update_args *clk_update = NULL;
+ struct cam_isp_resource_node *res = NULL;
+ struct cam_hw_info *hw_info = NULL;
+ int i, rc = 0;
+
+ clk_update =
+ (struct cam_vfe_clock_update_args *)cmd_args;
+ res = clk_update->node_res;
+
+ if (!res || !res->hw_intf->hw_priv) {
+ CAM_ERR(CAM_ISP, "Invalid input res %pK", res);
+ return -EINVAL;
+ }
+
+ hw_info = res->hw_intf->hw_priv;
+
+ if (res->res_type != CAM_ISP_RESOURCE_VFE_IN ||
+ res->res_id >= CAM_ISP_HW_VFE_IN_MAX) {
+ CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d",
+ res->hw_intf->hw_idx, res->res_type,
+ res->res_id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+ if (top_priv->mux_rsrc[i].res_id == res->res_id) {
+ top_priv->req_clk_rate[i] = clk_update->clk_rate;
+ break;
+ }
+ }
+
+ if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+ CAM_DBG(CAM_ISP, "VFE:%d Not ready to set clocks yet :%d",
+ res->hw_intf->hw_idx,
+ hw_info->hw_state);
+ } else
+ rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+
+ return rc;
+}
+
+static int cam_vfe_top_bw_update(
+ struct cam_vfe_top_ver2_priv *top_priv,
+ void *cmd_args, uint32_t arg_size)
+{
+ struct cam_vfe_bw_update_args *bw_update = NULL;
+ struct cam_isp_resource_node *res = NULL;
+ struct cam_hw_info *hw_info = NULL;
+ int rc = 0;
+ int i;
+
+ bw_update = (struct cam_vfe_bw_update_args *)cmd_args;
+ res = bw_update->node_res;
+
+ if (!res || !res->hw_intf->hw_priv)
+ return -EINVAL;
+
+ hw_info = res->hw_intf->hw_priv;
+
+ if (res->res_type != CAM_ISP_RESOURCE_VFE_IN ||
+ res->res_id >= CAM_ISP_HW_VFE_IN_MAX) {
+ CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d",
+ res->hw_intf->hw_idx, res->res_type,
+ res->res_id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+ if (top_priv->mux_rsrc[i].res_id == res->res_id) {
+ top_priv->req_axi_vote[i].uncompressed_bw =
+ bw_update->camnoc_bw_bytes;
+ top_priv->req_axi_vote[i].compressed_bw =
+ bw_update->external_bw_bytes;
+ break;
+ }
+ }
+
+ if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+ CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+ res->hw_intf->hw_idx,
+ hw_info->hw_state);
+ } else
+ rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+
+ return rc;
+}
+
static int cam_vfe_top_mux_get_reg_update(
struct cam_vfe_top_ver2_priv *top_priv,
void *cmd_args, uint32_t arg_size)
@@ -230,9 +403,21 @@
return -EINVAL;
}
- top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
+ top_priv = (struct cam_vfe_top_ver2_priv *)device_priv;
mux_res = (struct cam_isp_resource_node *)start_args;
+ rc = cam_vfe_top_set_hw_clk_rate(top_priv);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
+ return rc;
+ }
+
+ rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "set_hw_clk_rate failed, rc=%d", rc);
+ return rc;
+ }
+
if (mux_res->start) {
rc = mux_res->start(mux_res);
} else {
@@ -248,7 +433,7 @@
{
struct cam_vfe_top_ver2_priv *top_priv;
struct cam_isp_resource_node *mux_res;
- int rc = 0;
+ int i, rc = 0;
if (!device_priv || !stop_args) {
CAM_ERR(CAM_ISP, "Error! Invalid input arguments");
@@ -267,8 +452,16 @@
rc = -EINVAL;
}
- return rc;
+ if (!rc) {
+ for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+ if (top_priv->mux_rsrc[i].res_id == mux_res->res_id)
+ top_priv->req_clk_rate[i] = 0;
+ top_priv->req_axi_vote[i].compressed_bw = 0;
+ top_priv->req_axi_vote[i].uncompressed_bw = 0;
+ }
+ }
+ return rc;
}
int cam_vfe_top_read(void *device_priv,
@@ -303,6 +496,14 @@
rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args,
arg_size);
break;
+ case CAM_ISP_HW_CMD_CLOCK_UPDATE:
+ rc = cam_vfe_top_clock_update(top_priv, cmd_args,
+ arg_size);
+ break;
+ case CAM_ISP_HW_CMD_BW_UPDATE:
+ rc = cam_vfe_top_bw_update(top_priv, cmd_args,
+ arg_size);
+ break;
default:
rc = -EINVAL;
CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
@@ -338,12 +539,19 @@
goto free_vfe_top;
}
vfe_top->top_priv = top_priv;
+ top_priv->hw_clk_rate = 0;
+ top_priv->hw_axi_vote.compressed_bw = 0;
+ top_priv->hw_axi_vote.uncompressed_bw = 0;
for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN;
top_priv->mux_rsrc[i].hw_intf = hw_intf;
top_priv->mux_rsrc[i].res_state =
CAM_ISP_RESOURCE_STATE_AVAILABLE;
+ top_priv->req_clk_rate[i] = 0;
+ top_priv->req_axi_vote[i].compressed_bw = 0;
+ top_priv->req_axi_vote[i].uncompressed_bw = 0;
+
if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) {
top_priv->mux_rsrc[i].res_id =
CAM_ISP_HW_VFE_IN_CAMIF;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
index dbb211f..81e3b48 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h
@@ -29,21 +29,6 @@
struct cam_hw_ops hw_ops;
};
-struct cam_vfe_camif {
- void *camif_priv;
- int (*start_resource)(void *priv,
- struct cam_isp_resource_node *camif_res);
- int (*stop_resource)(void *priv,
- struct cam_isp_resource_node *camif_res);
- int (*acquire_resource)(void *priv,
- struct cam_isp_resource_node *camif_res,
- void *acquire_param);
- int (*release_resource)(void *priv,
- struct cam_isp_resource_node *camif_res);
- int (*process_cmd)(void *priv, uint32_t cmd_type, void *cmd_args,
- uint32_t arg_size);
-};
-
int cam_vfe_top_init(uint32_t top_version,
struct cam_hw_soc_info *soc_info,
struct cam_hw_intf *hw_intf,
diff --git a/drivers/media/platform/msm/camera/cam_lrme/Makefile b/drivers/media/platform/msm/camera/cam_lrme/Makefile
new file mode 100644
index 0000000..fba4529
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw_mgr/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_dev.o cam_lrme_context.o
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
new file mode 100644
index 0000000..0aa5ade
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c
@@ -0,0 +1,241 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_debug_util.h"
+#include "cam_lrme_context.h"
+
+static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx,
+ struct cam_acquire_dev_cmd *cmd)
+{
+ int rc = 0;
+ uint64_t ctxt_to_hw_map = (uint64_t)ctx->ctxt_to_hw_map;
+ struct cam_lrme_context *lrme_ctx = ctx->ctx_priv;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ rc = cam_context_acquire_dev_to_hw(ctx, cmd);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to acquire");
+ return rc;
+ }
+
+ ctxt_to_hw_map |= (lrme_ctx->index << CAM_LRME_CTX_INDEX_SHIFT);
+ ctx->ctxt_to_hw_map = (void *)ctxt_to_hw_map;
+
+ ctx->state = CAM_CTX_ACQUIRED;
+
+ return rc;
+}
+
+static int __cam_lrme_ctx_release_dev_in_acquired(struct cam_context *ctx,
+ struct cam_release_dev_cmd *cmd)
+{
+ int rc = 0;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ rc = cam_context_release_dev_to_hw(ctx, cmd);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to release");
+ return rc;
+ }
+
+ ctx->state = CAM_CTX_AVAILABLE;
+
+ return rc;
+}
+
+static int __cam_lrme_ctx_start_dev_in_acquired(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd)
+{
+ int rc = 0;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ rc = cam_context_start_dev_to_hw(ctx, cmd);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to start");
+ return rc;
+ }
+
+ ctx->state = CAM_CTX_ACTIVATED;
+
+ return rc;
+}
+
+static int __cam_lrme_ctx_config_dev_in_activated(struct cam_context *ctx,
+ struct cam_config_dev_cmd *cmd)
+{
+ int rc;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ rc = cam_context_prepare_dev_to_hw(ctx, cmd);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to config");
+ return rc;
+ }
+
+ return rc;
+}
+
+static int __cam_lrme_ctx_stop_dev_in_activated(struct cam_context *ctx,
+ struct cam_start_stop_dev_cmd *cmd)
+{
+ int rc = 0;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ rc = cam_context_stop_dev_to_hw(ctx);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to stop dev");
+ return rc;
+ }
+
+ ctx->state = CAM_CTX_ACQUIRED;
+
+ return rc;
+}
+
+static int __cam_lrme_ctx_release_dev_in_activated(struct cam_context *ctx,
+ struct cam_release_dev_cmd *cmd)
+{
+ int rc = 0;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ rc = __cam_lrme_ctx_stop_dev_in_activated(ctx, NULL);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to stop");
+ return rc;
+ }
+
+ rc = cam_context_release_dev_to_hw(ctx, cmd);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to release");
+ return rc;
+ }
+
+ ctx->state = CAM_CTX_AVAILABLE;
+
+ return rc;
+}
+
+static int __cam_lrme_ctx_handle_irq_in_activated(void *context,
+ uint32_t evt_id, void *evt_data)
+{
+ int rc;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ rc = cam_context_buf_done_from_hw(context, evt_data, evt_id);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed in buf done, rc=%d", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+/* top state machine */
+static struct cam_ctx_ops
+ cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = {
+ /* Uninit */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+ /* Available */
+ {
+ .ioctl_ops = {
+ .acquire_dev = __cam_lrme_ctx_acquire_dev_in_available,
+ },
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+ /* Acquired */
+ {
+ .ioctl_ops = {
+ .release_dev = __cam_lrme_ctx_release_dev_in_acquired,
+ .start_dev = __cam_lrme_ctx_start_dev_in_acquired,
+ },
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+ /* Ready */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+ /* Activate */
+ {
+ .ioctl_ops = {
+ .config_dev = __cam_lrme_ctx_config_dev_in_activated,
+ .release_dev = __cam_lrme_ctx_release_dev_in_activated,
+ .stop_dev = __cam_lrme_ctx_stop_dev_in_activated,
+ },
+ .crm_ops = {},
+ .irq_ops = __cam_lrme_ctx_handle_irq_in_activated,
+ },
+};
+
+int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
+ struct cam_context *base_ctx,
+ struct cam_hw_mgr_intf *hw_intf,
+ uint64_t index)
+{
+ int rc = 0;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ if (!base_ctx || !lrme_ctx) {
+ CAM_ERR(CAM_LRME, "Invalid input");
+ return -EINVAL;
+ }
+
+ memset(lrme_ctx, 0, sizeof(*lrme_ctx));
+
+ rc = cam_context_init(base_ctx, "lrme", NULL, hw_intf,
+ lrme_ctx->req_base, CAM_CTX_REQ_MAX);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to init context");
+ return rc;
+ }
+ lrme_ctx->base = base_ctx;
+ lrme_ctx->index = index;
+ base_ctx->ctx_priv = lrme_ctx;
+ base_ctx->state_machine = cam_lrme_ctx_state_machine;
+
+ return rc;
+}
+
+int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx)
+{
+ int rc = 0;
+
+ CAM_DBG(CAM_LRME, "Enter");
+
+ if (!lrme_ctx) {
+ CAM_ERR(CAM_LRME, "No ctx to deinit");
+ return -EINVAL;
+ }
+
+ rc = cam_context_deinit(lrme_ctx->base);
+
+ memset(lrme_ctx, 0, sizeof(*lrme_ctx));
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
new file mode 100644
index 0000000..882f7ac
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_LRME_CONTEXT_H_
+#define _CAM_LRME_CONTEXT_H_
+
+#include "cam_context.h"
+#include "cam_context_utils.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_interface.h"
+#include "cam_sync_api.h"
+
+#define CAM_LRME_CTX_INDEX_SHIFT 32
+
+/**
+ * struct cam_lrme_context
+ *
+ * @base : Base context pointer for this LRME context
+ * @req_base : List of base request for this LRME context
+ */
+struct cam_lrme_context {
+ struct cam_context *base;
+ struct cam_ctx_request req_base[CAM_CTX_REQ_MAX];
+ uint64_t index;
+};
+
+int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx,
+ struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf,
+ uint64_t index);
+int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx);
+
+#endif /* _CAM_LRME_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c
new file mode 100644
index 0000000..5be16ef
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c
@@ -0,0 +1,233 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_subdev.h"
+#include "cam_node.h"
+#include "cam_lrme_context.h"
+#include "cam_lrme_hw_mgr.h"
+#include "cam_lrme_hw_mgr_intf.h"
+
+#define CAM_LRME_DEV_NAME "cam-lrme"
+
+/**
+ * struct cam_lrme_dev
+ *
+ * @sd : Subdev information
+ * @ctx : List of base contexts
+ * @lrme_ctx : List of LRME contexts
+ * @lock : Mutex for LRME subdev
+ * @open_cnt : Open count of LRME subdev
+ */
+struct cam_lrme_dev {
+ struct cam_subdev sd;
+ struct cam_context ctx[CAM_CTX_MAX];
+ struct cam_lrme_context lrme_ctx[CAM_CTX_MAX];
+ struct mutex lock;
+ uint32_t open_cnt;
+};
+
+static struct cam_lrme_dev *g_lrme_dev;
+
+static int cam_lrme_dev_buf_done_cb(void *ctxt_to_hw_map, uint32_t evt_id,
+ void *evt_data)
+{
+ uint64_t index;
+ struct cam_context *ctx;
+ int rc;
+
+ index = CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map);
+ CAM_DBG(CAM_LRME, "ctx index %llu, evt_id %u\n", index, evt_id);
+ ctx = &g_lrme_dev->ctx[index];
+ rc = ctx->irq_cb_intf(ctx, evt_id, evt_data);
+ if (rc)
+ CAM_ERR(CAM_LRME, "irq callback failed");
+
+ return rc;
+}
+
+static int cam_lrme_dev_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct cam_lrme_dev *lrme_dev = g_lrme_dev;
+
+ if (!lrme_dev) {
+ CAM_ERR(CAM_LRME,
+ "LRME Dev not initialized, dev=%pK", lrme_dev);
+ return -ENODEV;
+ }
+
+ mutex_lock(&lrme_dev->lock);
+ lrme_dev->open_cnt++;
+ mutex_unlock(&lrme_dev->lock);
+
+ return 0;
+}
+
+static int cam_lrme_dev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct cam_lrme_dev *lrme_dev = g_lrme_dev;
+ struct cam_node *node = v4l2_get_subdevdata(sd);
+
+ if (!lrme_dev) {
+ CAM_ERR(CAM_LRME, "Invalid args");
+ return -ENODEV;
+ }
+
+ mutex_lock(&lrme_dev->lock);
+ lrme_dev->open_cnt--;
+ mutex_unlock(&lrme_dev->lock);
+
+ if (!node) {
+ CAM_ERR(CAM_LRME, "Node is NULL");
+ return -EINVAL;
+ }
+
+ if (lrme_dev->open_cnt == 0)
+ cam_node_shutdown(node);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = {
+ .open = cam_lrme_dev_open,
+ .close = cam_lrme_dev_close,
+};
+
+static int cam_lrme_dev_probe(struct platform_device *pdev)
+{
+ int rc;
+ int i;
+ struct cam_hw_mgr_intf hw_mgr_intf;
+ struct cam_node *node;
+
+ g_lrme_dev = kzalloc(sizeof(struct cam_lrme_dev), GFP_KERNEL);
+ if (!g_lrme_dev) {
+ CAM_ERR(CAM_LRME, "No memory");
+ return -ENOMEM;
+ }
+ g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops;
+
+ mutex_init(&g_lrme_dev->lock);
+
+ rc = cam_subdev_probe(&g_lrme_dev->sd, pdev, CAM_LRME_DEV_NAME,
+ CAM_LRME_DEVICE_TYPE);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "LRME cam_subdev_probe failed");
+ goto free_mem;
+ }
+ node = (struct cam_node *)g_lrme_dev->sd.token;
+
+ rc = cam_lrme_hw_mgr_init(&hw_mgr_intf, cam_lrme_dev_buf_done_cb);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Can not initialized LRME HW manager");
+ goto unregister;
+ }
+
+ for (i = 0; i < CAM_CTX_MAX; i++) {
+ rc = cam_lrme_context_init(&g_lrme_dev->lrme_ctx[i],
+ &g_lrme_dev->ctx[i],
+ &node->hw_mgr_intf, i);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "LRME context init failed");
+ goto deinit_ctx;
+ }
+ }
+
+ rc = cam_node_init(node, &hw_mgr_intf, g_lrme_dev->ctx, CAM_CTX_MAX,
+ CAM_LRME_DEV_NAME);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "LRME node init failed");
+ goto deinit_ctx;
+ }
+
+ CAM_DBG(CAM_LRME, "%s probe complete", g_lrme_dev->sd.name);
+
+ return 0;
+
+deinit_ctx:
+ for (--i; i >= 0; i--) {
+ if (cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]))
+ CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i);
+ }
+unregister:
+ if (cam_subdev_remove(&g_lrme_dev->sd))
+ CAM_ERR(CAM_LRME, "Failed in subdev remove");
+free_mem:
+ kfree(g_lrme_dev);
+
+ return rc;
+}
+
+static int cam_lrme_dev_remove(struct platform_device *pdev)
+{
+ int i;
+ int rc = 0;
+
+ for (i = 0; i < CAM_CTX_MAX; i++) {
+ rc = cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]);
+ if (rc)
+ CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i);
+ }
+
+ rc = cam_lrme_hw_mgr_deinit();
+ if (rc)
+ CAM_ERR(CAM_LRME, "Failed in hw mgr deinit, rc=%d", rc);
+
+ rc = cam_subdev_remove(&g_lrme_dev->sd);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Unregister failed");
+
+ mutex_destroy(&g_lrme_dev->lock);
+ kfree(g_lrme_dev);
+ g_lrme_dev = NULL;
+
+ return rc;
+}
+
+static const struct of_device_id cam_lrme_dt_match[] = {
+ {
+ .compatible = "qcom,cam-lrme"
+ },
+ {}
+};
+
+static struct platform_driver cam_lrme_driver = {
+ .probe = cam_lrme_dev_probe,
+ .remove = cam_lrme_dev_remove,
+ .driver = {
+ .name = "cam_lrme",
+ .owner = THIS_MODULE,
+ .of_match_table = cam_lrme_dt_match,
+ },
+};
+
+static int __init cam_lrme_dev_init_module(void)
+{
+ return platform_driver_register(&cam_lrme_driver);
+}
+
+static void __exit cam_lrme_dev_exit_module(void)
+{
+ platform_driver_unregister(&cam_lrme_driver);
+}
+
+module_init(cam_lrme_dev_init_module);
+module_exit(cam_lrme_dev_exit_module);
+MODULE_DESCRIPTION("MSM LRME driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/Makefile b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/Makefile
new file mode 100644
index 0000000..e4c8e0d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_mgr.o
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
new file mode 100644
index 0000000..448086d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
@@ -0,0 +1,1034 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_cpas.h>
+#include <media/cam_req_mgr.h>
+
+#include "cam_io_util.h"
+#include "cam_soc_util.h"
+#include "cam_mem_mgr_api.h"
+#include "cam_smmu_api.h"
+#include "cam_packet_util.h"
+#include "cam_lrme_context.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_lrme_hw_mgr_intf.h"
+#include "cam_lrme_hw_mgr.h"
+
+static struct cam_lrme_hw_mgr g_lrme_hw_mgr;
+
+static int cam_lrme_mgr_util_reserve_device(struct cam_lrme_hw_mgr *hw_mgr,
+ struct cam_lrme_acquire_args *lrme_acquire_args)
+{
+ int i, index = 0;
+ uint32_t min_ctx = UINT_MAX;
+ struct cam_lrme_device *hw_device = NULL;
+
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
+ if (!hw_mgr->device_count) {
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ CAM_ERR(CAM_LRME, "No device is registered");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < hw_mgr->device_count && i < CAM_LRME_HW_MAX; i++) {
+ hw_device = &hw_mgr->hw_device[i];
+ if (!hw_device->num_context) {
+ index = i;
+ break;
+ }
+ if (hw_device->num_context < min_ctx) {
+ min_ctx = hw_device->num_context;
+ index = i;
+ }
+ }
+
+ hw_device = &hw_mgr->hw_device[index];
+ hw_device->num_context++;
+
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+ CAM_DBG(CAM_LRME, "reserve device index %d", index);
+
+ return index;
+}
+
+static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr,
+ uint32_t device_index, struct cam_lrme_device **hw_device)
+{
+ if (!hw_mgr) {
+ CAM_ERR(CAM_LRME, "invalid params hw_mgr %pK", hw_mgr);
+ return -EINVAL;
+ }
+
+ if (device_index >= CAM_LRME_HW_MAX) {
+ CAM_ERR(CAM_LRME, "Wrong device index %d", device_index);
+ return -EINVAL;
+ }
+
+ *hw_device = &hw_mgr->hw_device[device_index];
+
+ return 0;
+}
+
+static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet)
+{
+ struct cam_cmd_buf_desc *cmd_desc = NULL;
+ int i, rc;
+
+ if (!packet) {
+ CAM_ERR(CAM_LRME, "Invalid args");
+ return -EINVAL;
+ }
+
+ CAM_DBG(CAM_LRME, "Packet request=%d, op_code=0x%x, size=%d, flags=%d",
+ packet->header.request_id, packet->header.op_code,
+ packet->header.size, packet->header.flags);
+ CAM_DBG(CAM_LRME,
+ "Packet cmdbuf(offset=%d, num=%d) io(offset=%d, num=%d)",
+ packet->cmd_buf_offset, packet->num_cmd_buf,
+ packet->io_configs_offset, packet->num_io_configs);
+ CAM_DBG(CAM_LRME,
+ "Packet Patch(offset=%d, num=%d) kmd(offset=%d, num=%d)",
+ packet->patch_offset, packet->num_patches,
+ packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index);
+
+ if (cam_packet_util_validate_packet(packet)) {
+ CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d",
+ packet->kmd_cmd_buf_index,
+ packet->num_cmd_buf, packet->cmd_buf_offset,
+ packet->io_configs_offset, packet->header.size);
+ return -EINVAL;
+ }
+
+ if (!packet->num_io_configs) {
+ CAM_ERR(CAM_LRME, "no io configs");
+ return -EINVAL;
+ }
+
+ cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)&packet->payload +
+ packet->cmd_buf_offset);
+
+ for (i = 0; i < packet->num_cmd_buf; i++) {
+ if (!cmd_desc[i].length)
+ continue;
+
+ CAM_DBG(CAM_LRME,
+ "CmdBuf[%d] hdl=%d, offset=%d, size=%d, len=%d, type=%d, meta_data=%d",
+ i,
+ cmd_desc[i].mem_handle, cmd_desc[i].offset,
+ cmd_desc[i].size, cmd_desc[i].length, cmd_desc[i].type,
+ cmd_desc[i].meta_data);
+
+ rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Invalid cmd buffer %d", i);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl,
+ struct cam_hw_prepare_update_args *prepare,
+ struct cam_lrme_hw_io_buffer *input_buf,
+ struct cam_lrme_hw_io_buffer *output_buf, uint32_t io_buf_size)
+{
+ int rc = -EINVAL;
+ uint32_t num_in_buf, num_out_buf, i, j, plane;
+ struct cam_buf_io_cfg *io_cfg;
+ uint64_t io_addr[CAM_PACKET_MAX_PLANES];
+ size_t size;
+
+ num_in_buf = 0;
+ num_out_buf = 0;
+ io_cfg = (struct cam_buf_io_cfg *)((uint8_t *)
+ &prepare->packet->payload +
+ prepare->packet->io_configs_offset);
+
+ for (i = 0; i < prepare->packet->num_io_configs; i++) {
+ CAM_DBG(CAM_LRME,
+ "IOConfig[%d] : handle[%d] Dir[%d] Res[%d] Fence[%d], Format[%d]",
+ i, io_cfg[i].mem_handle[0], io_cfg[i].direction,
+ io_cfg[i].resource_type,
+ io_cfg[i].fence, io_cfg[i].format);
+
+ if ((num_in_buf > io_buf_size) ||
+ (num_out_buf > io_buf_size)) {
+ CAM_ERR(CAM_LRME, "Invalid number of buffers %d %d %d",
+ num_in_buf, num_out_buf, io_buf_size);
+ return -EINVAL;
+ }
+
+ memset(io_addr, 0, sizeof(io_addr));
+ for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) {
+ if (!io_cfg[i].mem_handle[plane])
+ break;
+
+ rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[plane],
+ iommu_hdl, &io_addr[plane], &size);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Cannot get io buf for %d %d",
+ plane, rc);
+ return -ENOMEM;
+ }
+
+ io_addr[plane] += io_cfg[i].offsets[plane];
+
+ if (io_addr[plane] >> 32) {
+ CAM_ERR(CAM_LRME, "Invalid io addr for %d %d",
+ plane, rc);
+ return -ENOMEM;
+ }
+
+ CAM_DBG(CAM_LRME, "IO Address[%d][%d] : %llu",
+ io_cfg[i].direction, plane, io_addr[plane]);
+ }
+
+ switch (io_cfg[i].direction) {
+ case CAM_BUF_INPUT: {
+ prepare->in_map_entries[num_in_buf].resource_handle =
+ io_cfg[i].resource_type;
+ prepare->in_map_entries[num_in_buf].sync_id =
+ io_cfg[i].fence;
+
+ input_buf[num_in_buf].valid = true;
+ for (j = 0; j < plane; j++)
+ input_buf[num_in_buf].io_addr[j] = io_addr[j];
+ input_buf[num_in_buf].num_plane = plane;
+ input_buf[num_in_buf].io_cfg = &io_cfg[i];
+
+ num_in_buf++;
+ break;
+ }
+ case CAM_BUF_OUTPUT: {
+ prepare->out_map_entries[num_out_buf].resource_handle =
+ io_cfg[i].resource_type;
+ prepare->out_map_entries[num_out_buf].sync_id =
+ io_cfg[i].fence;
+
+ output_buf[num_out_buf].valid = true;
+ for (j = 0; j < plane; j++)
+ output_buf[num_out_buf].io_addr[j] = io_addr[j];
+ output_buf[num_out_buf].num_plane = plane;
+ output_buf[num_out_buf].io_cfg = &io_cfg[i];
+
+ num_out_buf++;
+ break;
+ }
+ default:
+ CAM_ERR(CAM_LRME, "Unsupported io direction %d",
+ io_cfg[i].direction);
+ return -EINVAL;
+ }
+ }
+ prepare->num_in_map_entries = num_in_buf;
+ prepare->num_out_map_entries = num_out_buf;
+
+ return 0;
+}
+
+static int cam_lrme_mgr_util_prepare_hw_update_entries(
+ struct cam_lrme_hw_mgr *hw_mgr,
+ struct cam_hw_prepare_update_args *prepare,
+ struct cam_lrme_hw_cmd_config_args *config_args,
+ struct cam_kmd_buf_info *kmd_buf_info)
+{
+ int i, rc = 0;
+ struct cam_lrme_device *hw_device = NULL;
+ uint32_t *kmd_buf_addr;
+ uint32_t num_entry;
+ uint32_t kmd_buf_max_size;
+ uint32_t kmd_buf_used_bytes = 0;
+ struct cam_hw_update_entry *hw_entry;
+ struct cam_cmd_buf_desc *cmd_desc = NULL;
+
+ hw_device = config_args->hw_device;
+ if (!hw_device) {
+ CAM_ERR(CAM_LRME, "Invalid hw_device");
+ return -EINVAL;
+ }
+
+ kmd_buf_addr = (uint32_t *)((uint8_t *)kmd_buf_info->cpu_addr +
+ kmd_buf_info->used_bytes);
+ kmd_buf_max_size = kmd_buf_info->size - kmd_buf_info->used_bytes;
+
+ config_args->cmd_buf_addr = kmd_buf_addr;
+ config_args->size = kmd_buf_max_size;
+ config_args->config_buf_size = 0;
+
+ if (hw_device->hw_intf.hw_ops.process_cmd) {
+ rc = hw_device->hw_intf.hw_ops.process_cmd(
+ hw_device->hw_intf.hw_priv,
+ CAM_LRME_HW_CMD_PREPARE_HW_UPDATE,
+ config_args,
+ sizeof(struct cam_lrme_hw_cmd_config_args));
+ if (rc) {
+ CAM_ERR(CAM_LRME,
+ "Failed in CMD_PREPARE_HW_UPDATE %d", rc);
+ return rc;
+ }
+ } else {
+ CAM_ERR(CAM_LRME, "Can't find handle function");
+ return -EINVAL;
+ }
+
+ kmd_buf_used_bytes += config_args->config_buf_size;
+
+ if (!kmd_buf_used_bytes || (kmd_buf_used_bytes > kmd_buf_max_size)) {
+ CAM_ERR(CAM_LRME, "Invalid kmd used bytes %d (%d)",
+ kmd_buf_used_bytes, kmd_buf_max_size);
+ return -ENOMEM;
+ }
+
+ hw_entry = prepare->hw_update_entries;
+ num_entry = 0;
+
+ if (config_args->config_buf_size) {
+ if ((num_entry + 1) >= prepare->max_hw_update_entries) {
+ CAM_ERR(CAM_LRME, "Insufficient HW entries :%d %d",
+ num_entry, prepare->max_hw_update_entries);
+ return -EINVAL;
+ }
+
+ hw_entry[num_entry].handle = kmd_buf_info->handle;
+ hw_entry[num_entry].len = config_args->config_buf_size;
+ hw_entry[num_entry].offset = kmd_buf_info->offset;
+
+ kmd_buf_info->used_bytes += config_args->config_buf_size;
+ kmd_buf_info->offset += config_args->config_buf_size;
+ num_entry++;
+ }
+
+ cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)
+ &prepare->packet->payload + prepare->packet->cmd_buf_offset);
+
+ for (i = 0; i < prepare->packet->num_cmd_buf; i++) {
+ if (!cmd_desc[i].length)
+ continue;
+
+ if ((num_entry + 1) >= prepare->max_hw_update_entries) {
+ CAM_ERR(CAM_LRME, "Exceed max num of entry");
+ return -EINVAL;
+ }
+
+ hw_entry[num_entry].handle = cmd_desc[i].mem_handle;
+ hw_entry[num_entry].len = cmd_desc[i].length;
+ hw_entry[num_entry].offset = cmd_desc[i].offset;
+ num_entry++;
+ }
+ prepare->num_hw_update_entries = num_entry;
+
+ CAM_DBG(CAM_LRME, "FinalConfig : hw_entries=%d, Sync(in=%d, out=%d)",
+ prepare->num_hw_update_entries, prepare->num_in_map_entries,
+ prepare->num_out_map_entries);
+
+ return rc;
+}
+
+static void cam_lrme_mgr_util_put_frame_req(
+ struct list_head *src_list,
+ struct list_head *list,
+ spinlock_t *lock)
+{
+ spin_lock(lock);
+ list_add_tail(list, src_list);
+ spin_unlock(lock);
+}
+
+static int cam_lrme_mgr_util_get_frame_req(
+ struct list_head *src_list,
+ struct cam_lrme_frame_request **frame_req,
+ spinlock_t *lock)
+{
+ int rc = 0;
+ struct cam_lrme_frame_request *req_ptr = NULL;
+
+ spin_lock(lock);
+ if (!list_empty(src_list)) {
+ req_ptr = list_first_entry(src_list,
+ struct cam_lrme_frame_request, frame_list);
+ list_del_init(&req_ptr->frame_list);
+ } else {
+ rc = -ENOENT;
+ }
+ *frame_req = req_ptr;
+ spin_unlock(lock);
+
+ return rc;
+}
+
+
+static int cam_lrme_mgr_util_submit_req(void *priv, void *data)
+{
+ struct cam_lrme_device *hw_device;
+ struct cam_lrme_hw_mgr *hw_mgr;
+ struct cam_lrme_frame_request *frame_req = NULL;
+ struct cam_lrme_hw_submit_args submit_args;
+ struct cam_lrme_mgr_work_data *work_data;
+ int rc;
+ int req_prio = 0;
+
+ if (!priv) {
+ CAM_ERR(CAM_LRME, "worker doesn't have private data");
+ return -EINVAL;
+ }
+
+ hw_mgr = (struct cam_lrme_hw_mgr *)priv;
+ work_data = (struct cam_lrme_mgr_work_data *)data;
+ hw_device = work_data->hw_device;
+
+ rc = cam_lrme_mgr_util_get_frame_req(&hw_device->
+ frame_pending_list_high, &frame_req, &hw_device->high_req_lock);
+
+ if (!frame_req) {
+ rc = cam_lrme_mgr_util_get_frame_req(&hw_device->
+ frame_pending_list_normal, &frame_req,
+ &hw_device->normal_req_lock);
+ if (frame_req)
+ req_prio = 1;
+ }
+
+ if (!frame_req) {
+ CAM_DBG(CAM_LRME, "No pending request");
+ return 0;
+ }
+
+ if (hw_device->hw_intf.hw_ops.process_cmd) {
+ submit_args.hw_update_entries = frame_req->hw_update_entries;
+ submit_args.num_hw_update_entries =
+ frame_req->num_hw_update_entries;
+ submit_args.frame_req = frame_req;
+
+ rc = hw_device->hw_intf.hw_ops.process_cmd(
+ hw_device->hw_intf.hw_priv,
+ CAM_LRME_HW_CMD_SUBMIT,
+ &submit_args, sizeof(struct cam_lrme_hw_submit_args));
+
+ if (rc == -EBUSY)
+ CAM_DBG(CAM_LRME, "device busy");
+ else if (rc)
+ CAM_ERR(CAM_LRME, "submit request failed rc %d", rc);
+ if (rc) {
+ req_prio == 0 ? spin_lock(&hw_device->high_req_lock) :
+ spin_lock(&hw_device->normal_req_lock);
+ list_add(&frame_req->frame_list,
+ (req_prio == 0 ?
+ &hw_device->frame_pending_list_high :
+ &hw_device->frame_pending_list_normal));
+ req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) :
+ spin_unlock(&hw_device->normal_req_lock);
+ }
+ if (rc == -EBUSY)
+ rc = 0;
+ } else {
+ req_prio == 0 ? spin_lock(&hw_device->high_req_lock) :
+ spin_lock(&hw_device->normal_req_lock);
+ list_add(&frame_req->frame_list,
+ (req_prio == 0 ?
+ &hw_device->frame_pending_list_high :
+ &hw_device->frame_pending_list_normal));
+ req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) :
+ spin_unlock(&hw_device->normal_req_lock);
+ rc = -EINVAL;
+ }
+
+ CAM_DBG(CAM_LRME, "End of submit, rc %d", rc);
+
+ return rc;
+}
+
+static int cam_lrme_mgr_util_schedule_frame_req(
+ struct cam_lrme_hw_mgr *hw_mgr, struct cam_lrme_device *hw_device)
+{
+ int rc = 0;
+ struct crm_workq_task *task;
+ struct cam_lrme_mgr_work_data *work_data;
+
+ task = cam_req_mgr_workq_get_task(hw_device->work);
+ if (!task) {
+ CAM_ERR(CAM_LRME, "Can not get task for worker");
+ return -ENOMEM;
+ }
+
+ work_data = (struct cam_lrme_mgr_work_data *)task->payload;
+ work_data->hw_device = hw_device;
+
+ task->process_cb = cam_lrme_mgr_util_submit_req;
+ CAM_DBG(CAM_LRME, "enqueue submit task");
+ rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0);
+
+ return rc;
+}
+
+static int cam_lrme_mgr_util_release(struct cam_lrme_hw_mgr *hw_mgr,
+ uint32_t device_index)
+{
+ int rc = 0;
+ struct cam_lrme_device *hw_device;
+
+ rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Error in getting device %d", rc);
+ return rc;
+ }
+
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
+ hw_device->num_context--;
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+ return rc;
+}
+
+static int cam_lrme_mgr_cb(void *data,
+ struct cam_lrme_hw_cb_args *cb_args)
+{
+ struct cam_lrme_hw_mgr *hw_mgr = &g_lrme_hw_mgr;
+ int rc = 0;
+ bool frame_abort = true;
+ struct cam_lrme_frame_request *frame_req;
+ struct cam_lrme_device *hw_device;
+
+ if (!data || !cb_args) {
+ CAM_ERR(CAM_LRME, "Invalid input args");
+ return -EINVAL;
+ }
+
+ hw_device = (struct cam_lrme_device *)data;
+ frame_req = cb_args->frame_req;
+
+ if (cb_args->cb_type & CAM_LRME_CB_PUT_FRAME) {
+ memset(frame_req, 0x0, sizeof(*frame_req));
+ INIT_LIST_HEAD(&frame_req->frame_list);
+ cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
+ &frame_req->frame_list,
+ &hw_mgr->free_req_lock);
+ cb_args->cb_type &= ~CAM_LRME_CB_PUT_FRAME;
+ frame_req = NULL;
+ }
+
+ if (cb_args->cb_type & CAM_LRME_CB_COMP_REG_UPDATE) {
+ cb_args->cb_type &= ~CAM_LRME_CB_COMP_REG_UPDATE;
+ CAM_DBG(CAM_LRME, "Reg update");
+ }
+
+ if (!frame_req)
+ return rc;
+
+ if (cb_args->cb_type & CAM_LRME_CB_BUF_DONE) {
+ cb_args->cb_type &= ~CAM_LRME_CB_BUF_DONE;
+ frame_abort = false;
+ } else if (cb_args->cb_type & CAM_LRME_CB_ERROR) {
+ cb_args->cb_type &= ~CAM_LRME_CB_ERROR;
+ frame_abort = true;
+ } else {
+ CAM_ERR(CAM_LRME, "Wrong cb type %d, req %lld",
+ cb_args->cb_type, frame_req->req_id);
+ return -EINVAL;
+ }
+
+ if (hw_mgr->event_cb) {
+ struct cam_hw_done_event_data buf_data;
+
+ buf_data.request_id = frame_req->req_id;
+ CAM_DBG(CAM_LRME, "frame req %llu, frame_abort %d",
+ frame_req->req_id, frame_abort);
+ rc = hw_mgr->event_cb(frame_req->ctxt_to_hw_map,
+ frame_abort, &buf_data);
+ } else {
+ CAM_ERR(CAM_LRME, "No cb function");
+ }
+ memset(frame_req, 0x0, sizeof(*frame_req));
+ INIT_LIST_HEAD(&frame_req->frame_list);
+ cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
+ &frame_req->frame_list,
+ &hw_mgr->free_req_lock);
+
+ rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device);
+
+ return rc;
+}
+
+static int cam_lrme_mgr_get_caps(void *hw_mgr_priv, void *hw_get_caps_args)
+{
+ int rc = 0;
+ struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_query_cap_cmd *args = hw_get_caps_args;
+
+ if (sizeof(struct cam_lrme_query_cap_cmd) != args->size) {
+ CAM_ERR(CAM_LRME,
+ "sizeof(struct cam_query_cap_cmd) = %lu, args->size = %d",
+ sizeof(struct cam_query_cap_cmd), args->size);
+ return -EFAULT;
+ }
+
+ if (copy_to_user((void __user *)args->caps_handle, &(hw_mgr->lrme_caps),
+ sizeof(struct cam_lrme_query_cap_cmd))) {
+ CAM_ERR(CAM_LRME, "copy to user failed");
+ return -EFAULT;
+ }
+
+ return rc;
+}
+
+static int cam_lrme_mgr_hw_acquire(void *hw_mgr_priv, void *hw_acquire_args)
+{
+ struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_hw_acquire_args *args =
+ (struct cam_hw_acquire_args *)hw_acquire_args;
+ struct cam_lrme_acquire_args lrme_acquire_args;
+ uint64_t device_index;
+
+ if (!hw_mgr_priv || !args) {
+ CAM_ERR(CAM_LRME,
+ "Invalid input params hw_mgr_priv %pK, acquire_args %pK",
+ hw_mgr_priv, args);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&lrme_acquire_args,
+ (void __user *)args->acquire_info,
+ sizeof(struct cam_lrme_acquire_args))) {
+ CAM_ERR(CAM_LRME, "Failed to copy acquire args from user");
+ return -EFAULT;
+ }
+
+ device_index = cam_lrme_mgr_util_reserve_device(hw_mgr,
+ &lrme_acquire_args);
+ CAM_DBG(CAM_LRME, "Get device id %llu", device_index);
+
+ if (device_index >= hw_mgr->device_count) {
+ CAM_ERR(CAM_LRME, "Get wrong device id %llu", device_index);
+ return -EINVAL;
+ }
+
+ /* device_index is the right 4 bit in ctxt_to_hw_map */
+ args->ctxt_to_hw_map = (void *)device_index;
+
+ return 0;
+}
+
+static int cam_lrme_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args)
+{
+ int rc = 0;
+ struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_hw_release_args *args =
+ (struct cam_hw_release_args *)hw_release_args;
+ uint64_t device_index;
+
+ if (!hw_mgr_priv || !hw_release_args) {
+ CAM_ERR(CAM_LRME, "Invalid arguments %pK, %pK",
+ hw_mgr_priv, hw_release_args);
+ return -EINVAL;
+ }
+
+ device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+ if (device_index >= hw_mgr->device_count) {
+ CAM_ERR(CAM_LRME, "Invalid device index %llu", device_index);
+ return -EPERM;
+ }
+
+ rc = cam_lrme_mgr_util_release(hw_mgr, device_index);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Failed in release device, rc=%d", rc);
+
+ return rc;
+}
+
+static int cam_lrme_mgr_hw_start(void *hw_mgr_priv, void *hw_start_args)
+{
+ int rc = 0;
+ struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_hw_start_args *args =
+ (struct cam_hw_start_args *)hw_start_args;
+ struct cam_lrme_device *hw_device;
+ uint32_t device_index;
+
+ if (!hw_mgr || !args) {
+ CAM_ERR(CAM_LRME, "Invald input params");
+ return -EINVAL;
+ }
+
+ device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+ if (device_index >= hw_mgr->device_count) {
+ CAM_ERR(CAM_LRME, "Invalid device index %d", device_index);
+ return -EPERM;
+ }
+
+ CAM_DBG(CAM_LRME, "Start device index %d", device_index);
+
+ rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to get hw device");
+ return rc;
+ }
+
+ if (hw_device->hw_intf.hw_ops.start) {
+ rc = hw_device->hw_intf.hw_ops.start(
+ hw_device->hw_intf.hw_priv, NULL, 0);
+ } else {
+ CAM_ERR(CAM_LRME, "Invald start function");
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int cam_lrme_mgr_hw_stop(void *hw_mgr_priv, void *stop_args)
+{
+ int rc = 0;
+ struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_hw_stop_args *args =
+ (struct cam_hw_stop_args *)stop_args;
+ struct cam_lrme_device *hw_device;
+ uint32_t device_index;
+
+ if (!hw_mgr_priv || !stop_args) {
+ CAM_ERR(CAM_LRME, "Invalid arguments");
+ return -EINVAL;
+ }
+
+ device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+ if (device_index >= hw_mgr->device_count) {
+ CAM_ERR(CAM_LRME, "Invalid device index %d", device_index);
+ return -EPERM;
+ }
+
+ CAM_DBG(CAM_LRME, "Stop device index %d", device_index);
+
+ rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to get hw device");
+ return rc;
+ }
+
+ if (hw_device->hw_intf.hw_ops.stop) {
+ rc = hw_device->hw_intf.hw_ops.stop(
+ hw_device->hw_intf.hw_priv, NULL, 0);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed in HW stop %d", rc);
+ goto end;
+ }
+ }
+
+end:
+ return rc;
+}
+
+static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv,
+ void *hw_prepare_update_args)
+{
+ int rc = 0, i;
+ struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_hw_prepare_update_args *args =
+ (struct cam_hw_prepare_update_args *)hw_prepare_update_args;
+ struct cam_lrme_device *hw_device;
+ struct cam_kmd_buf_info kmd_buf;
+ struct cam_lrme_hw_cmd_config_args config_args;
+ struct cam_lrme_frame_request *frame_req = NULL;
+ uint32_t device_index;
+
+ if (!hw_mgr_priv || !hw_prepare_update_args) {
+ CAM_ERR(CAM_LRME, "Invalid args %pK %pK",
+ hw_mgr_priv, hw_prepare_update_args);
+ return -EINVAL;
+ }
+
+ device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map);
+ if (device_index >= hw_mgr->device_count) {
+ CAM_ERR(CAM_LRME, "Invalid device index %d", device_index);
+ return -EPERM;
+ }
+
+ rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Error in getting device %d", rc);
+ goto error;
+ }
+
+ rc = cam_lrme_mgr_util_packet_validate(args->packet);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Error in packet validation %d", rc);
+ goto error;
+ }
+
+ rc = cam_packet_util_get_kmd_buffer(args->packet, &kmd_buf);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Error in get kmd buf buffer %d", rc);
+ goto error;
+ }
+
+ CAM_DBG(CAM_LRME,
+ "KMD Buf : hdl=%d, cpu_addr=%pK, offset=%d, size=%d, used=%d",
+ kmd_buf.handle, kmd_buf.cpu_addr, kmd_buf.offset,
+ kmd_buf.size, kmd_buf.used_bytes);
+
+ rc = cam_packet_util_process_patches(args->packet,
+ hw_mgr->device_iommu.non_secure, hw_mgr->device_iommu.secure);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Patch packet failed, rc=%d", rc);
+ return rc;
+ }
+
+ memset(&config_args, 0, sizeof(config_args));
+ config_args.hw_device = hw_device;
+
+ rc = cam_lrme_mgr_util_prepare_io_buffer(
+ hw_mgr->device_iommu.non_secure, args,
+ config_args.input_buf, config_args.output_buf,
+ CAM_LRME_MAX_IO_BUFFER);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Error in prepare IO Buf %d", rc);
+ goto error;
+ }
+ /* Check port number */
+ if (args->num_in_map_entries == 0 || args->num_out_map_entries == 0) {
+ CAM_ERR(CAM_LRME, "Error in port number in %d, out %d",
+ args->num_in_map_entries, args->num_out_map_entries);
+ goto error;
+ }
+
+ rc = cam_lrme_mgr_util_prepare_hw_update_entries(hw_mgr, args,
+ &config_args, &kmd_buf);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Error in hw update entries %d", rc);
+ goto error;
+ }
+
+ rc = cam_lrme_mgr_util_get_frame_req(&hw_mgr->frame_free_list,
+ &frame_req, &hw_mgr->free_req_lock);
+ if (rc || !frame_req) {
+ CAM_ERR(CAM_LRME, "Can not get free frame request");
+ goto error;
+ }
+
+ frame_req->ctxt_to_hw_map = args->ctxt_to_hw_map;
+ frame_req->req_id = args->packet->header.request_id;
+ frame_req->hw_device = hw_device;
+ frame_req->num_hw_update_entries = args->num_hw_update_entries;
+ for (i = 0; i < args->num_hw_update_entries; i++)
+ frame_req->hw_update_entries[i] = args->hw_update_entries[i];
+
+ args->priv = frame_req;
+
+ CAM_DBG(CAM_LRME, "FramePrepare : Frame[%lld]", frame_req->req_id);
+
+ return 0;
+
+error:
+ return rc;
+}
+
+static int cam_lrme_mgr_hw_config(void *hw_mgr_priv,
+ void *hw_config_args)
+{
+ int rc = 0;
+ struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv;
+ struct cam_hw_config_args *args =
+ (struct cam_hw_config_args *)hw_config_args;
+ struct cam_lrme_frame_request *frame_req;
+ struct cam_lrme_device *hw_device = NULL;
+ enum cam_lrme_hw_mgr_ctx_priority priority;
+
+ if (!hw_mgr_priv || !hw_config_args) {
+ CAM_ERR(CAM_LRME, "Invalid arguments, hw_mgr %pK, config %pK",
+ hw_mgr_priv, hw_config_args);
+ return -EINVAL;
+ }
+
+ if (!args->num_hw_update_entries) {
+ CAM_ERR(CAM_LRME, "No hw update entries");
+ return -EINVAL;
+ }
+
+ frame_req = (struct cam_lrme_frame_request *)args->priv;
+ if (!frame_req) {
+ CAM_ERR(CAM_LRME, "No frame request");
+ return -EINVAL;
+ }
+
+ hw_device = frame_req->hw_device;
+ if (!hw_device)
+ return -EINVAL;
+
+ priority = CAM_LRME_DECODE_PRIORITY(args->ctxt_to_hw_map);
+ if (priority == CAM_LRME_PRIORITY_HIGH) {
+ cam_lrme_mgr_util_put_frame_req(
+ &hw_device->frame_pending_list_high,
+ &frame_req->frame_list, &hw_device->high_req_lock);
+ } else {
+ cam_lrme_mgr_util_put_frame_req(
+ &hw_device->frame_pending_list_normal,
+ &frame_req->frame_list, &hw_device->normal_req_lock);
+ }
+
+ CAM_DBG(CAM_LRME, "schedule req %llu", frame_req->req_id);
+ rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device);
+
+ return rc;
+}
+
+int cam_lrme_mgr_register_device(
+ struct cam_hw_intf *lrme_hw_intf,
+ struct cam_iommu_handle *device_iommu,
+ struct cam_iommu_handle *cdm_iommu)
+{
+ struct cam_lrme_device *hw_device;
+ char buf[128];
+ int i, rc;
+
+ hw_device = &g_lrme_hw_mgr.hw_device[lrme_hw_intf->hw_idx];
+
+ g_lrme_hw_mgr.device_iommu = *device_iommu;
+ g_lrme_hw_mgr.cdm_iommu = *cdm_iommu;
+
+ memcpy(&hw_device->hw_intf, lrme_hw_intf, sizeof(struct cam_hw_intf));
+
+ spin_lock_init(&hw_device->high_req_lock);
+ spin_lock_init(&hw_device->normal_req_lock);
+ INIT_LIST_HEAD(&hw_device->frame_pending_list_high);
+ INIT_LIST_HEAD(&hw_device->frame_pending_list_normal);
+
+ rc = snprintf(buf, sizeof(buf), "cam_lrme_device_submit_worker%d",
+ lrme_hw_intf->hw_idx);
+ CAM_DBG(CAM_LRME, "Create submit workq for %s", buf);
+ rc = cam_req_mgr_workq_create(buf,
+ CAM_LRME_WORKQ_NUM_TASK,
+ &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ);
+ if (rc) {
+ CAM_ERR(CAM_LRME,
+ "Unable to create a worker, rc=%d", rc);
+ return rc;
+ }
+
+ for (i = 0; i < CAM_LRME_WORKQ_NUM_TASK; i++)
+ hw_device->work->task.pool[i].payload =
+ &hw_device->work_data[i];
+
+ if (hw_device->hw_intf.hw_ops.process_cmd) {
+ struct cam_lrme_hw_cmd_set_cb cb_args;
+
+ cb_args.cam_lrme_hw_mgr_cb = cam_lrme_mgr_cb;
+ cb_args.data = hw_device;
+
+ rc = hw_device->hw_intf.hw_ops.process_cmd(
+ hw_device->hw_intf.hw_priv,
+ CAM_LRME_HW_CMD_REGISTER_CB,
+ &cb_args, sizeof(cb_args));
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Register cb failed");
+ goto destroy_workqueue;
+ }
+ CAM_DBG(CAM_LRME, "cb registered");
+ }
+
+ if (hw_device->hw_intf.hw_ops.get_hw_caps) {
+ rc = hw_device->hw_intf.hw_ops.get_hw_caps(
+ hw_device->hw_intf.hw_priv, &hw_device->hw_caps,
+ sizeof(hw_device->hw_caps));
+ if (rc)
+ CAM_ERR(CAM_LRME, "Get caps failed");
+ } else {
+ CAM_ERR(CAM_LRME, "No get_hw_caps function");
+ goto destroy_workqueue;
+ }
+ g_lrme_hw_mgr.lrme_caps.dev_caps[lrme_hw_intf->hw_idx] =
+ hw_device->hw_caps;
+ g_lrme_hw_mgr.device_count++;
+ g_lrme_hw_mgr.lrme_caps.device_iommu = g_lrme_hw_mgr.device_iommu;
+ g_lrme_hw_mgr.lrme_caps.cdm_iommu = g_lrme_hw_mgr.cdm_iommu;
+ g_lrme_hw_mgr.lrme_caps.num_devices = g_lrme_hw_mgr.device_count;
+
+ hw_device->valid = true;
+
+ CAM_DBG(CAM_LRME, "device registration done");
+ return 0;
+
+destroy_workqueue:
+ cam_req_mgr_workq_destroy(&hw_device->work);
+
+ return rc;
+}
+
+int cam_lrme_mgr_deregister_device(int device_index)
+{
+ struct cam_lrme_device *hw_device;
+
+ hw_device = &g_lrme_hw_mgr.hw_device[device_index];
+ cam_req_mgr_workq_destroy(&hw_device->work);
+ memset(hw_device, 0x0, sizeof(struct cam_lrme_device));
+ g_lrme_hw_mgr.device_count--;
+
+ return 0;
+}
+
+int cam_lrme_hw_mgr_deinit(void)
+{
+ mutex_destroy(&g_lrme_hw_mgr.hw_mgr_mutex);
+ memset(&g_lrme_hw_mgr, 0x0, sizeof(g_lrme_hw_mgr));
+
+ return 0;
+}
+
+int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf,
+ cam_hw_event_cb_func cam_lrme_dev_buf_done_cb)
+{
+ int i, rc = 0;
+ struct cam_lrme_frame_request *frame_req;
+
+ if (!hw_mgr_intf)
+ return -EINVAL;
+
+ CAM_DBG(CAM_LRME, "device count %d", g_lrme_hw_mgr.device_count);
+ if (g_lrme_hw_mgr.device_count > CAM_LRME_HW_MAX) {
+ CAM_ERR(CAM_LRME, "Invalid count of devices");
+ return -EINVAL;
+ }
+
+ memset(hw_mgr_intf, 0, sizeof(*hw_mgr_intf));
+
+ mutex_init(&g_lrme_hw_mgr.hw_mgr_mutex);
+ spin_lock_init(&g_lrme_hw_mgr.free_req_lock);
+ INIT_LIST_HEAD(&g_lrme_hw_mgr.frame_free_list);
+
+ /* Init hw mgr frame requests and add to free list */
+ for (i = 0; i < CAM_CTX_REQ_MAX * CAM_CTX_MAX; i++) {
+ frame_req = &g_lrme_hw_mgr.frame_req[i];
+
+ memset(frame_req, 0x0, sizeof(*frame_req));
+ INIT_LIST_HEAD(&frame_req->frame_list);
+
+ list_add_tail(&frame_req->frame_list,
+ &g_lrme_hw_mgr.frame_free_list);
+ }
+
+ hw_mgr_intf->hw_mgr_priv = &g_lrme_hw_mgr;
+ hw_mgr_intf->hw_get_caps = cam_lrme_mgr_get_caps;
+ hw_mgr_intf->hw_acquire = cam_lrme_mgr_hw_acquire;
+ hw_mgr_intf->hw_release = cam_lrme_mgr_hw_release;
+ hw_mgr_intf->hw_start = cam_lrme_mgr_hw_start;
+ hw_mgr_intf->hw_stop = cam_lrme_mgr_hw_stop;
+ hw_mgr_intf->hw_prepare_update = cam_lrme_mgr_hw_prepare_update;
+ hw_mgr_intf->hw_config = cam_lrme_mgr_hw_config;
+ hw_mgr_intf->hw_read = NULL;
+ hw_mgr_intf->hw_write = NULL;
+ hw_mgr_intf->hw_close = NULL;
+
+ g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb;
+
+ CAM_DBG(CAM_LRME, "Hw mgr init done");
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h
new file mode 100644
index 0000000..f7ce4d2
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_LRME_HW_MGR_H_
+#define _CAM_LRME_HW_MGR_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <media/cam_lrme.h>
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_cpas_api.h"
+#include "cam_debug_util.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_context.h"
+
+#define CAM_LRME_HW_MAX 1
+#define CAM_LRME_WORKQ_NUM_TASK 10
+
+#define CAM_LRME_DECODE_DEVICE_INDEX(ctxt_to_hw_map) \
+ ((uint64_t)ctxt_to_hw_map & 0xF)
+
+#define CAM_LRME_DECODE_PRIORITY(ctxt_to_hw_map) \
+ (((uint64_t)ctxt_to_hw_map & 0xF0) >> 4)
+
+#define CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map) \
+ ((uint64_t)ctxt_to_hw_map >> CAM_LRME_CTX_INDEX_SHIFT)
+
+/**
+ * enum cam_lrme_hw_mgr_ctx_priority
+ *
+ * CAM_LRME_PRIORITY_HIGH : High priority client
+ * CAM_LRME_PRIORITY_NORMAL : Normal priority client
+ */
+enum cam_lrme_hw_mgr_ctx_priority {
+ CAM_LRME_PRIORITY_HIGH,
+ CAM_LRME_PRIORITY_NORMAL,
+};
+
+/**
+ * struct cam_lrme_mgr_work_data : HW Mgr work data
+ *
+ * hw_device : Pointer to the hw device
+ */
+struct cam_lrme_mgr_work_data {
+ struct cam_lrme_device *hw_device;
+};
+
+/**
+ * struct cam_lrme_device : LRME HW device
+ *
+ * @hw_caps : HW device's capabilities
+ * @hw_intf : HW device's interface information
+ * @num_context : Number of contexts using this device
+ * @valid : Whether this device is valid
+ * @work : HW device's work queue
+ * @work_data : HW device's work data
+ * @frame_pending_list_high : High priority request queue
+ * @frame_pending_list_normal : Normal priority request queue
+ * @high_req_lock : Spinlock of high priority queue
+ * @normal_req_lock : Spinlock of normal priority queue
+ */
+struct cam_lrme_device {
+ struct cam_lrme_dev_cap hw_caps;
+ struct cam_hw_intf hw_intf;
+ uint32_t num_context;
+ bool valid;
+ struct cam_req_mgr_core_workq *work;
+ struct cam_lrme_mgr_work_data work_data[CAM_LRME_WORKQ_NUM_TASK];
+ struct list_head frame_pending_list_high;
+ struct list_head frame_pending_list_normal;
+ spinlock_t high_req_lock;
+ spinlock_t normal_req_lock;
+};
+
+/**
+ * struct cam_lrme_hw_mgr : LRME HW manager
+ *
+ * @device_count : Number of HW devices
+ * @frame_free_list : List of free frame request
+ * @hw_mgr_mutex : Mutex to protect HW manager data
+ * @free_req_lock :Spinlock to protect frame_free_list
+ * @hw_device : List of HW devices
+ * @device_iommu : Device iommu
+ * @cdm_iommu : cdm iommu
+ * @frame_req : List of frame request to use
+ * @lrme_caps : LRME capabilities
+ * @event_cb : IRQ callback function
+ */
+struct cam_lrme_hw_mgr {
+ uint32_t device_count;
+ struct list_head frame_free_list;
+ struct mutex hw_mgr_mutex;
+ spinlock_t free_req_lock;
+ struct cam_lrme_device hw_device[CAM_LRME_HW_MAX];
+ struct cam_iommu_handle device_iommu;
+ struct cam_iommu_handle cdm_iommu;
+ struct cam_lrme_frame_request frame_req[CAM_CTX_REQ_MAX * CAM_CTX_MAX];
+ struct cam_lrme_query_cap_cmd lrme_caps;
+ cam_hw_event_cb_func event_cb;
+};
+
+int cam_lrme_mgr_register_device(struct cam_hw_intf *lrme_hw_intf,
+ struct cam_iommu_handle *device_iommu,
+ struct cam_iommu_handle *cdm_iommu);
+int cam_lrme_mgr_deregister_device(int device_index);
+
+#endif /* _CAM_LRME_HW_MGR_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h
new file mode 100644
index 0000000..8bb609c
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_LRME_HW_MGR_INTF_H_
+#define _CAM_LRME_HW_MGR_INTF_H_
+
+#include <linux/of.h>
+
+#include "cam_debug_util.h"
+#include "cam_hw_mgr_intf.h"
+
+int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf,
+ cam_hw_event_cb_func cam_lrme_dev_buf_done_cb);
+int cam_lrme_hw_mgr_deinit(void);
+
+#endif /* _CAM_LRME_HW_MGR_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile
new file mode 100644
index 0000000..c65d862
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile
@@ -0,0 +1,13 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw
+ccflags-y += -Idrivers/media/platform/msm/camera0
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_dev.o cam_lrme_hw_core.o cam_lrme_hw_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
new file mode 100644
index 0000000..0318739
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
@@ -0,0 +1,1022 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_smmu_api.h"
+
+static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer,
+ uint32_t *index, uint32_t reg_offset, uint32_t reg_value)
+{
+ buffer[(*index)++] = reg_offset;
+ buffer[(*index)++] = reg_value;
+}
+
+static void cam_lrme_hw_util_fill_fe_reg(struct cam_lrme_hw_io_buffer *io_buf,
+ uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd,
+ struct cam_lrme_hw_info *hw_info)
+{
+ uint32_t reg_val;
+
+ /* 1. config buffer size */
+ reg_val = io_buf->io_cfg->planes[0].width;
+ reg_val |= (io_buf->io_cfg->planes[0].height << 16);
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[index].rd_buffer_size,
+ reg_val);
+
+ CAM_DBG(CAM_LRME,
+ "width %d", io_buf->io_cfg->planes[0].width);
+ CAM_DBG(CAM_LRME,
+ "height %d", io_buf->io_cfg->planes[0].height);
+
+ /* 2. config image address */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[index].addr_image,
+ io_buf->io_addr[0]);
+
+ CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]);
+
+ /* 3. config stride */
+ reg_val = io_buf->io_cfg->planes[0].plane_stride;
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[index].rd_stride,
+ reg_val);
+
+ CAM_DBG(CAM_LRME, "plane_stride %d",
+ io_buf->io_cfg->planes[0].plane_stride);
+
+ /* 4. enable client */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[index].core_cfg, 0x1);
+
+ /* 5. unpack_cfg */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, 0x0);
+}
+
+static void cam_lrme_hw_util_fill_we_reg(struct cam_lrme_hw_io_buffer *io_buf,
+ uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd,
+ struct cam_lrme_hw_info *hw_info)
+{
+ /* config client mode */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_wr_reg.bus_client_reg[index].cfg,
+ 0x1);
+
+ /* image address */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_wr_reg.bus_client_reg[index].addr_image,
+ io_buf->io_addr[0]);
+ CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]);
+
+ /* buffer width and height */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_wr_reg.bus_client_reg[index].buffer_width_cfg,
+ io_buf->io_cfg->planes[0].width);
+ CAM_DBG(CAM_LRME, "width %d", io_buf->io_cfg->planes[0].width);
+
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_wr_reg.bus_client_reg[index].buffer_height_cfg,
+ io_buf->io_cfg->planes[0].height);
+ CAM_DBG(CAM_LRME, "height %d", io_buf->io_cfg->planes[0].height);
+
+ /* packer cfg */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_wr_reg.bus_client_reg[index].packer_cfg,
+ (index == 0) ? 0x1 : 0x5);
+
+ /* client stride */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+ hw_info->bus_wr_reg.bus_client_reg[index].wr_stride,
+ io_buf->io_cfg->planes[0].meta_stride);
+ CAM_DBG(CAM_LRME, "plane_stride %d",
+ io_buf->io_cfg->planes[0].plane_stride);
+}
+
+
+static int cam_lrme_hw_util_process_config_hw(struct cam_hw_info *lrme_hw,
+ struct cam_lrme_hw_cmd_config_args *config_args)
+{
+ int i;
+ struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+ struct cam_lrme_cdm_info *hw_cdm_info;
+ uint32_t *cmd_buf_addr = config_args->cmd_buf_addr;
+ uint32_t reg_val_pair[CAM_LRME_MAX_REG_PAIR_NUM];
+ struct cam_lrme_hw_io_buffer *io_buf;
+ struct cam_lrme_hw_info *hw_info =
+ ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info;
+ uint32_t num_cmd = 0;
+ uint32_t size;
+ uint32_t mem_base, available_size = config_args->size;
+ uint32_t output_res_mask = 0, input_res_mask = 0;
+
+
+ if (!cmd_buf_addr) {
+ CAM_ERR(CAM_LRME, "Invalid input args");
+ return -EINVAL;
+ }
+
+ hw_cdm_info =
+ ((struct cam_lrme_core *)lrme_hw->core_info)->hw_cdm_info;
+
+ for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) {
+ io_buf = &config_args->input_buf[i];
+
+ if (io_buf->valid == false)
+ break;
+
+ if (io_buf->io_cfg->direction != CAM_BUF_INPUT) {
+ CAM_ERR(CAM_LRME, "Incorrect direction %d %d",
+ io_buf->io_cfg->direction, CAM_BUF_INPUT);
+ return -EINVAL;
+ }
+ CAM_DBG(CAM_LRME,
+ "resource_type %d", io_buf->io_cfg->resource_type);
+
+ switch (io_buf->io_cfg->resource_type) {
+ case CAM_LRME_IO_TYPE_TAR:
+ cam_lrme_hw_util_fill_fe_reg(io_buf, 0, reg_val_pair,
+ &num_cmd, hw_info);
+
+ input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_TAR;
+ break;
+ case CAM_LRME_IO_TYPE_REF:
+ cam_lrme_hw_util_fill_fe_reg(io_buf, 1, reg_val_pair,
+ &num_cmd, hw_info);
+
+ input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_REF;
+ break;
+ default:
+ CAM_ERR(CAM_LRME, "wrong resource_type %d",
+ io_buf->io_cfg->resource_type);
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++)
+ if (!((input_res_mask >> i) & 0x1))
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd,
+ hw_info->bus_rd_reg.bus_client_reg[i].core_cfg,
+ 0x0);
+
+ for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) {
+ io_buf = &config_args->output_buf[i];
+
+ if (io_buf->valid == false)
+ break;
+
+ if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) {
+ CAM_ERR(CAM_LRME, "Incorrect direction %d %d",
+ io_buf->io_cfg->direction, CAM_BUF_INPUT);
+ return -EINVAL;
+ }
+
+ CAM_DBG(CAM_LRME, "resource_type %d",
+ io_buf->io_cfg->resource_type);
+ switch (io_buf->io_cfg->resource_type) {
+ case CAM_LRME_IO_TYPE_DS2:
+ cam_lrme_hw_util_fill_we_reg(io_buf, 0, reg_val_pair,
+ &num_cmd, hw_info);
+
+ output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_DS2;
+ break;
+ case CAM_LRME_IO_TYPE_RES:
+ cam_lrme_hw_util_fill_we_reg(io_buf, 1, reg_val_pair,
+ &num_cmd, hw_info);
+
+ output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_RES;
+ break;
+
+ default:
+ CAM_ERR(CAM_LRME, "wrong resource_type %d",
+ io_buf->io_cfg->resource_type);
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++)
+ if (!((output_res_mask >> i) & 0x1))
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd,
+ hw_info->bus_wr_reg.bus_client_reg[i].cfg, 0x0);
+
+ if (output_res_mask) {
+ /* write composite mask */
+ cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd,
+ hw_info->bus_wr_reg.common_reg.composite_mask_0,
+ output_res_mask);
+ }
+
+ size = hw_cdm_info->cdm_ops->cdm_required_size_changebase();
+ if ((size * 4) > available_size) {
+ CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d",
+ available_size, size);
+ return -EINVAL;
+ }
+
+ mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, CAM_LRME_BASE_IDX);
+
+ hw_cdm_info->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base);
+ cmd_buf_addr += size;
+ available_size -= (size * 4);
+
+ size = hw_cdm_info->cdm_ops->cdm_required_size_reg_random(
+ num_cmd / 2);
+
+ if ((size * 4) > available_size) {
+ CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d",
+ available_size, size);
+ return -ENOMEM;
+ }
+
+ hw_cdm_info->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmd / 2,
+ reg_val_pair);
+ cmd_buf_addr += size;
+ available_size -= (size * 4);
+
+ config_args->config_buf_size =
+ config_args->size - available_size;
+
+ return 0;
+}
+
+static int cam_lrme_hw_util_submit_go(struct cam_hw_info *lrme_hw)
+{
+ struct cam_lrme_core *lrme_core;
+ struct cam_hw_soc_info *soc_info;
+ struct cam_lrme_hw_info *hw_info;
+
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+ hw_info = lrme_core->hw_info;
+ soc_info = &lrme_hw->soc_info;
+
+ cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.cmd);
+
+ return 0;
+}
+
+static int cam_lrme_hw_util_reset(struct cam_hw_info *lrme_hw,
+ uint32_t reset_type)
+{
+ struct cam_lrme_core *lrme_core;
+ struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+ struct cam_lrme_hw_info *hw_info;
+ long time_left;
+
+ lrme_core = lrme_hw->core_info;
+ hw_info = lrme_core->hw_info;
+
+ switch (reset_type) {
+ case CAM_LRME_HW_RESET_TYPE_HW_RESET:
+ reinit_completion(&lrme_core->reset_complete);
+ cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_rst_cmd);
+ time_left = wait_for_completion_timeout(
+ &lrme_core->reset_complete,
+ msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT));
+ if (time_left <= 0) {
+ CAM_ERR(CAM_LRME,
+ "HW reset wait failed time_left=%ld",
+ time_left);
+ return -ETIMEDOUT;
+ }
+ break;
+ case CAM_LRME_HW_RESET_TYPE_SW_RESET:
+ cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.sw_reset);
+ cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.sw_reset);
+ reinit_completion(&lrme_core->reset_complete);
+ cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_rst_cmd);
+ time_left = wait_for_completion_timeout(
+ &lrme_core->reset_complete,
+ msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT));
+ if (time_left <= 0) {
+ CAM_ERR(CAM_LRME,
+ "SW reset wait failed time_left=%ld",
+ time_left);
+ return -ETIMEDOUT;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw,
+ struct cam_lrme_dev_cap *hw_caps)
+{
+ struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+ struct cam_lrme_hw_info *hw_info =
+ ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info;
+ uint32_t reg_value;
+
+ if (!hw_info) {
+ CAM_ERR(CAM_LRME, "Invalid hw info data");
+ return -EINVAL;
+ }
+
+ reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ hw_info->clc_reg.clc_hw_version);
+ hw_caps->clc_hw_version.gen =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+ hw_caps->clc_hw_version.rev =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+ hw_caps->clc_hw_version.step =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+ reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.hw_version);
+ hw_caps->bus_rd_hw_version.gen =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+ hw_caps->bus_rd_hw_version.rev =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+ hw_caps->bus_rd_hw_version.step =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+ reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.hw_version);
+ hw_caps->bus_wr_hw_version.gen =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+ hw_caps->bus_wr_hw_version.rev =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+ hw_caps->bus_wr_hw_version.step =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+ reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_hw_version);
+ hw_caps->top_hw_version.gen =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+ hw_caps->top_hw_version.rev =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+ hw_caps->top_hw_version.step =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+ reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_titan_version);
+ hw_caps->top_titan_version.gen =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C);
+ hw_caps->top_titan_version.rev =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+ hw_caps->top_titan_version.step =
+ CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+ return 0;
+}
+
+static int cam_lrme_hw_util_submit_req(struct cam_lrme_core *lrme_core,
+ struct cam_lrme_frame_request *frame_req)
+{
+ struct cam_lrme_cdm_info *hw_cdm_info =
+ lrme_core->hw_cdm_info;
+ struct cam_cdm_bl_request *cdm_cmd = hw_cdm_info->cdm_cmd;
+ struct cam_hw_update_entry *cmd;
+ int i, rc = 0;
+
+ if (frame_req->num_hw_update_entries > 0) {
+ cdm_cmd->cmd_arrary_count = frame_req->num_hw_update_entries;
+ cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE;
+ cdm_cmd->flag = false;
+ cdm_cmd->userdata = NULL;
+ cdm_cmd->cookie = 0;
+
+ for (i = 0; i <= frame_req->num_hw_update_entries; i++) {
+ cmd = (frame_req->hw_update_entries + i);
+ cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle;
+ cdm_cmd->cmd[i].offset = cmd->offset;
+ cdm_cmd->cmd[i].len = cmd->len;
+ }
+
+ rc = cam_cdm_submit_bls(hw_cdm_info->cdm_handle, cdm_cmd);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to submit cdm commands");
+ return -EINVAL;
+ }
+ } else {
+ CAM_ERR(CAM_LRME, "No hw update entry");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int cam_lrme_hw_util_process_err(struct cam_hw_info *lrme_hw)
+{
+ struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+ struct cam_lrme_frame_request *req_proc, *req_submit;
+ struct cam_lrme_hw_cb_args cb_args;
+ int rc;
+
+ req_proc = lrme_core->req_proc;
+ req_submit = lrme_core->req_submit;
+ cb_args.cb_type = CAM_LRME_CB_ERROR;
+
+ if ((lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) &&
+ (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING) &&
+ (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PROC_PEND)) {
+ CAM_ERR(CAM_LRME, "Get error irq in wrong state %d",
+ lrme_core->state);
+ }
+
+ CAM_ERR_RATE_LIMIT(CAM_LRME, "Start recovery");
+ lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY;
+ rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Failed to reset");
+
+ lrme_core->req_proc = NULL;
+ lrme_core->req_submit = NULL;
+ if (!rc)
+ lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+
+ cb_args.frame_req = req_proc;
+ lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data,
+ &cb_args);
+
+ cb_args.frame_req = req_submit;
+ lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data,
+ &cb_args);
+
+ return rc;
+}
+
+static int cam_lrme_hw_util_process_reg_update(
+ struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args)
+{
+ struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+ int rc = 0;
+
+ cb_args->cb_type |= CAM_LRME_CB_COMP_REG_UPDATE;
+ if (lrme_core->state == CAM_LRME_CORE_STATE_REQ_PENDING) {
+ lrme_core->state = CAM_LRME_CORE_STATE_PROCESSING;
+ } else {
+ CAM_ERR(CAM_LRME, "Reg update in wrong state %d",
+ lrme_core->state);
+ rc = cam_lrme_hw_util_process_err(lrme_hw);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Failed to reset");
+ return -EINVAL;
+ }
+
+ lrme_core->req_proc = lrme_core->req_submit;
+ lrme_core->req_submit = NULL;
+
+ return 0;
+}
+
+static int cam_lrme_hw_util_process_idle(
+ struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args)
+{
+ struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+ int rc = 0;
+
+ cb_args->cb_type |= CAM_LRME_CB_BUF_DONE;
+ switch (lrme_core->state) {
+ case CAM_LRME_CORE_STATE_REQ_PROC_PEND:
+ cam_lrme_hw_util_submit_go(lrme_hw);
+ lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING;
+ break;
+
+ case CAM_LRME_CORE_STATE_PROCESSING:
+ lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+ break;
+
+ default:
+ CAM_ERR(CAM_LRME, "Idle in wrong state %d",
+ lrme_core->state);
+ rc = cam_lrme_hw_util_process_err(lrme_hw);
+ return rc;
+ }
+ cb_args->frame_req = lrme_core->req_proc;
+ lrme_core->req_proc = NULL;
+
+ return 0;
+}
+
+void cam_lrme_set_irq(struct cam_hw_info *lrme_hw,
+ enum cam_lrme_irq_set set)
+{
+ struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+ struct cam_lrme_core *lrme_core = lrme_hw->core_info;
+ struct cam_lrme_hw_info *hw_info = lrme_core->hw_info;
+
+ switch (set) {
+ case CAM_LRME_IRQ_ENABLE:
+ cam_io_w_mb(0xFFFF,
+ soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_irq_mask);
+ cam_io_w_mb(0xFFFF,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_mask_0);
+ cam_io_w_mb(0xFFFF,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_mask_1);
+ cam_io_w_mb(0xFFFF,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.irq_mask);
+ break;
+
+ case CAM_LRME_IRQ_DISABLE:
+ cam_io_w_mb(0x0,
+ soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_irq_mask);
+ cam_io_w_mb(0x0,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_mask_0);
+ cam_io_w_mb(0x0,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_mask_1);
+ cam_io_w_mb(0x0,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.irq_mask);
+ break;
+ }
+}
+
+
+int cam_lrme_hw_process_irq(void *priv, void *data)
+{
+ struct cam_lrme_hw_work_data *work_data;
+ struct cam_hw_info *lrme_hw;
+ struct cam_lrme_core *lrme_core;
+ int rc = 0;
+ uint32_t top_irq_status, fe_irq_status;
+ uint32_t *we_irq_status;
+ struct cam_lrme_hw_cb_args cb_args;
+
+ if (!data || !priv) {
+ CAM_ERR(CAM_LRME, "Invalid data %pK %pK", data, priv);
+ return -EINVAL;
+ }
+
+ memset(&cb_args, 0, sizeof(struct cam_lrme_hw_cb_args));
+ lrme_hw = (struct cam_hw_info *)priv;
+ work_data = (struct cam_lrme_hw_work_data *)data;
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+ top_irq_status = work_data->top_irq_status;
+ fe_irq_status = work_data->fe_irq_status;
+ we_irq_status = work_data->we_irq_status;
+
+ CAM_DBG(CAM_LRME,
+ "top status %x, fe status %x, we status0 %x, we status1 %x",
+ top_irq_status, fe_irq_status, we_irq_status[0],
+ we_irq_status[1]);
+ CAM_DBG(CAM_LRME, "Current state %d", lrme_core->state);
+
+ mutex_lock(&lrme_hw->hw_mutex);
+
+ if (top_irq_status & (1 << 3)) {
+ CAM_DBG(CAM_LRME, "Error");
+ rc = cam_lrme_hw_util_process_err(lrme_hw);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Process error failed");
+ goto end;
+ }
+
+ if (we_irq_status[0] & (1 << 1)) {
+ CAM_DBG(CAM_LRME, "reg update");
+ rc = cam_lrme_hw_util_process_reg_update(lrme_hw, &cb_args);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Process reg_update failed");
+ goto end;
+ }
+ }
+
+ if (top_irq_status & (1 << 4)) {
+ CAM_DBG(CAM_LRME, "IDLE");
+
+ rc = cam_lrme_hw_util_process_idle(lrme_hw, &cb_args);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Process idle failed");
+ goto end;
+ }
+ }
+
+ if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) {
+ lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->
+ hw_mgr_cb.data, &cb_args);
+ } else {
+ CAM_ERR(CAM_LRME, "No hw mgr cb");
+ rc = -EINVAL;
+ }
+
+end:
+ mutex_unlock(&lrme_hw->hw_mutex);
+ return rc;
+}
+
+int cam_lrme_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size)
+{
+ struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+ int rc = 0;
+ struct cam_lrme_core *lrme_core;
+
+ if (!lrme_hw) {
+ CAM_ERR(CAM_LRME,
+ "Invalid input params, lrme_hw %pK",
+ lrme_hw);
+ return -EINVAL;
+ }
+
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+
+ mutex_lock(&lrme_hw->hw_mutex);
+
+ if (lrme_hw->open_count > 0) {
+ CAM_DBG(CAM_LRME, "This device is activated before");
+ goto unlock;
+ }
+
+ rc = cam_lrme_soc_enable_resources(lrme_hw);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to enable soc resources");
+ goto unlock;
+ }
+
+ rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to reset hw");
+ goto disable_soc;
+ }
+
+ if (lrme_core->hw_cdm_info) {
+ struct cam_lrme_cdm_info *hw_cdm_info =
+ lrme_core->hw_cdm_info;
+
+ rc = cam_cdm_stream_on(hw_cdm_info->cdm_handle);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to stream on cdm");
+ goto disable_soc;
+ }
+ }
+
+ lrme_hw->hw_state = CAM_HW_STATE_POWER_UP;
+ lrme_hw->open_count++;
+ lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+
+ mutex_unlock(&lrme_hw->hw_mutex);
+ return rc;
+
+disable_soc:
+ if (cam_lrme_soc_disable_resources(lrme_hw))
+ CAM_ERR(CAM_LRME, "Error in disable soc resources");
+unlock:
+ mutex_unlock(&lrme_hw->hw_mutex);
+ return rc;
+}
+
+int cam_lrme_hw_stop(void *hw_priv, void *hw_stop_args, uint32_t arg_size)
+{
+ struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+ int rc = 0;
+ struct cam_lrme_core *lrme_core;
+
+ if (!lrme_hw) {
+ CAM_ERR(CAM_LRME, "Invalid argument");
+ return -EINVAL;
+ }
+
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+
+ mutex_lock(&lrme_hw->hw_mutex);
+
+ if (lrme_hw->open_count == 0) {
+ mutex_unlock(&lrme_hw->hw_mutex);
+ CAM_ERR(CAM_LRME, "Error Unbalanced stop");
+ return -EINVAL;
+ }
+ lrme_hw->open_count--;
+
+ if (lrme_hw->open_count)
+ goto unlock;
+
+ lrme_core->req_proc = NULL;
+ lrme_core->req_submit = NULL;
+
+ if (lrme_core->hw_cdm_info) {
+ struct cam_lrme_cdm_info *hw_cdm_info =
+ lrme_core->hw_cdm_info;
+
+ rc = cam_cdm_stream_off(hw_cdm_info->cdm_handle);
+ if (rc) {
+ CAM_ERR(CAM_LRME,
+ "Failed in CDM StreamOff, handle=0x%x, rc=%d",
+ hw_cdm_info->cdm_handle, rc);
+ goto unlock;
+ }
+ }
+
+ rc = cam_lrme_soc_disable_resources(lrme_hw);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed in Disable SOC, rc=%d", rc);
+ goto unlock;
+ }
+
+ lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+ if (lrme_core->state == CAM_LRME_CORE_STATE_IDLE) {
+ lrme_core->state = CAM_LRME_CORE_STATE_INIT;
+ } else {
+ CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state);
+ return -EINVAL;
+ }
+
+unlock:
+ mutex_unlock(&lrme_hw->hw_mutex);
+ return rc;
+}
+
+int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args,
+ uint32_t arg_size)
+{
+ struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+ struct cam_lrme_core *lrme_core;
+ struct cam_lrme_hw_submit_args *args =
+ (struct cam_lrme_hw_submit_args *)hw_submit_args;
+ int rc = 0;
+ struct cam_lrme_frame_request *frame_req;
+
+
+ if (!hw_priv || !hw_submit_args) {
+ CAM_ERR(CAM_LRME, "Invalid input");
+ return -EINVAL;
+ }
+
+ if (sizeof(struct cam_lrme_hw_submit_args) != arg_size) {
+ CAM_ERR(CAM_LRME,
+ "size of args %lu, arg_size %d",
+ sizeof(struct cam_lrme_hw_submit_args), arg_size);
+ return -EINVAL;
+ }
+
+ frame_req = args->frame_req;
+
+ mutex_lock(&lrme_hw->hw_mutex);
+
+ if (lrme_hw->open_count == 0) {
+ CAM_ERR(CAM_LRME, "HW is not open");
+ mutex_unlock(&lrme_hw->hw_mutex);
+ return -EINVAL;
+ }
+
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+ if (lrme_core->state != CAM_LRME_CORE_STATE_IDLE &&
+ lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) {
+ mutex_unlock(&lrme_hw->hw_mutex);
+ CAM_DBG(CAM_LRME, "device busy, can not submit, state %d",
+ lrme_core->state);
+ return -EBUSY;
+ }
+
+ if (lrme_core->req_submit != NULL) {
+ CAM_ERR(CAM_LRME, "req_submit is not NULL");
+ return -EBUSY;
+ }
+
+ rc = cam_lrme_hw_util_submit_req(lrme_core, frame_req);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Submit req failed");
+ goto error;
+ }
+
+ switch (lrme_core->state) {
+ case CAM_LRME_CORE_STATE_PROCESSING:
+ lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND;
+ break;
+
+ case CAM_LRME_CORE_STATE_IDLE:
+ cam_lrme_hw_util_submit_go(lrme_hw);
+ lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING;
+ break;
+
+ default:
+ CAM_ERR(CAM_LRME, "Wrong hw state");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ lrme_core->req_submit = frame_req;
+ mutex_unlock(&lrme_hw->hw_mutex);
+ CAM_DBG(CAM_LRME, "Release lock, submit done for req %llu",
+ frame_req->req_id);
+
+ return 0;
+
+error:
+ mutex_unlock(&lrme_hw->hw_mutex);
+
+ return rc;
+
+}
+
+int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size)
+{
+ struct cam_hw_info *lrme_hw = hw_priv;
+ struct cam_lrme_core *lrme_core;
+ struct cam_lrme_hw_reset_args *lrme_reset_args = reset_core_args;
+ int rc;
+
+ if (!hw_priv) {
+ CAM_ERR(CAM_LRME, "Invalid input args");
+ return -EINVAL;
+ }
+
+ if (!reset_core_args ||
+ sizeof(struct cam_lrme_hw_reset_args) != arg_size) {
+ CAM_ERR(CAM_LRME, "Invalid reset args");
+ return -EINVAL;
+ }
+
+ lrme_core = lrme_hw->core_info;
+
+ mutex_lock(&lrme_hw->hw_mutex);
+ if (lrme_core->state == CAM_LRME_CORE_STATE_RECOVERY) {
+ mutex_unlock(&lrme_hw->hw_mutex);
+ CAM_ERR(CAM_LRME, "Reset not allowed in %d state",
+ lrme_core->state);
+ return -EINVAL;
+ }
+
+ lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY;
+
+ rc = cam_lrme_hw_util_reset(lrme_hw, lrme_reset_args->reset_type);
+ if (rc) {
+ mutex_unlock(&lrme_hw->hw_mutex);
+ CAM_ERR(CAM_FD, "Failed to reset");
+ return rc;
+ }
+
+ lrme_core->state = CAM_LRME_CORE_STATE_IDLE;
+
+ mutex_unlock(&lrme_hw->hw_mutex);
+
+ return 0;
+}
+
+int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args,
+ uint32_t arg_size)
+{
+ struct cam_hw_info *lrme_hw;
+ struct cam_lrme_core *lrme_core;
+ struct cam_lrme_dev_cap *lrme_hw_caps =
+ (struct cam_lrme_dev_cap *)get_hw_cap_args;
+
+ if (!hw_priv || !get_hw_cap_args) {
+ CAM_ERR(CAM_LRME, "Invalid input pointers %pK %pK",
+ hw_priv, get_hw_cap_args);
+ return -EINVAL;
+ }
+
+ lrme_hw = (struct cam_hw_info *)hw_priv;
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+ *lrme_hw_caps = lrme_core->hw_caps;
+
+ return 0;
+}
+
+irqreturn_t cam_lrme_hw_irq(int irq_num, void *data)
+{
+ struct cam_hw_info *lrme_hw;
+ struct cam_lrme_core *lrme_core;
+ struct cam_hw_soc_info *soc_info;
+ struct cam_lrme_hw_info *hw_info;
+ struct crm_workq_task *task;
+ struct cam_lrme_hw_work_data *work_data;
+ uint32_t top_irq_status, fe_irq_status, we_irq_status0, we_irq_status1;
+ int rc;
+
+ if (!data) {
+ CAM_ERR(CAM_LRME, "Invalid data in IRQ callback");
+ return -EINVAL;
+ }
+
+ lrme_hw = (struct cam_hw_info *)data;
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+ soc_info = &lrme_hw->soc_info;
+ hw_info = lrme_core->hw_info;
+
+ top_irq_status = cam_io_r_mb(
+ soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_irq_status);
+ CAM_DBG(CAM_LRME, "top_irq_status %x", top_irq_status);
+ cam_io_w_mb(top_irq_status,
+ soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_irq_clear);
+ top_irq_status &= CAM_LRME_TOP_IRQ_MASK;
+
+ fe_irq_status = cam_io_r_mb(
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.irq_status);
+ CAM_DBG(CAM_LRME, "fe_irq_status %x", fe_irq_status);
+ cam_io_w_mb(fe_irq_status,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.irq_clear);
+ fe_irq_status &= CAM_LRME_FE_IRQ_MASK;
+
+ we_irq_status0 = cam_io_r_mb(
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_status_0);
+ CAM_DBG(CAM_LRME, "we_irq_status[0] %x", we_irq_status0);
+ cam_io_w_mb(we_irq_status0,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_clear_0);
+ we_irq_status0 &= CAM_LRME_WE_IRQ_MASK_0;
+
+ we_irq_status1 = cam_io_r_mb(
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_status_1);
+ CAM_DBG(CAM_LRME, "we_irq_status[1] %x", we_irq_status1);
+ cam_io_w_mb(we_irq_status1,
+ soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_clear_1);
+ we_irq_status1 &= CAM_LRME_WE_IRQ_MASK_1;
+
+ cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+ hw_info->titan_reg.top_irq_cmd);
+ cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+ hw_info->bus_wr_reg.common_reg.irq_cmd);
+ cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base +
+ hw_info->bus_rd_reg.common_reg.irq_cmd);
+
+ if (top_irq_status & 0x1) {
+ complete(&lrme_core->reset_complete);
+ top_irq_status &= (~0x1);
+ }
+
+ if (top_irq_status || fe_irq_status ||
+ we_irq_status0 || we_irq_status1) {
+ task = cam_req_mgr_workq_get_task(lrme_core->work);
+ if (!task) {
+ CAM_ERR(CAM_LRME, "no empty task available");
+ return -ENOMEM;
+ }
+ work_data = (struct cam_lrme_hw_work_data *)task->payload;
+ work_data->top_irq_status = top_irq_status;
+ work_data->fe_irq_status = fe_irq_status;
+ work_data->we_irq_status[0] = we_irq_status0;
+ work_data->we_irq_status[1] = we_irq_status1;
+ task->process_cb = cam_lrme_hw_process_irq;
+ rc = cam_req_mgr_workq_enqueue_task(task, data,
+ CRM_TASK_PRIORITY_0);
+ if (rc)
+ CAM_ERR(CAM_LRME,
+ "Failed in enqueue work task, rc=%d", rc);
+ }
+
+ return IRQ_HANDLED;
+}
+
+int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type,
+ void *cmd_args, uint32_t arg_size)
+{
+ struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv;
+ int rc = 0;
+
+ switch (cmd_type) {
+ case CAM_LRME_HW_CMD_PREPARE_HW_UPDATE: {
+ struct cam_lrme_hw_cmd_config_args *config_args;
+
+ config_args = (struct cam_lrme_hw_cmd_config_args *)cmd_args;
+ rc = cam_lrme_hw_util_process_config_hw(lrme_hw, config_args);
+ break;
+ }
+
+ case CAM_LRME_HW_CMD_REGISTER_CB: {
+ struct cam_lrme_hw_cmd_set_cb *cb_args;
+ struct cam_lrme_device *hw_device;
+ struct cam_lrme_core *lrme_core =
+ (struct cam_lrme_core *)lrme_hw->core_info;
+ cb_args = (struct cam_lrme_hw_cmd_set_cb *)cmd_args;
+ lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb =
+ cb_args->cam_lrme_hw_mgr_cb;
+ lrme_core->hw_mgr_cb.data = cb_args->data;
+ hw_device = cb_args->data;
+ rc = 0;
+ break;
+ }
+
+ case CAM_LRME_HW_CMD_SUBMIT: {
+ struct cam_lrme_hw_submit_args *submit_args;
+
+ submit_args = (struct cam_lrme_hw_submit_args *)cmd_args;
+ rc = cam_lrme_hw_submit_req(hw_priv,
+ submit_args, arg_size);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h
new file mode 100644
index 0000000..bf2f370
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h
@@ -0,0 +1,457 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_LRME_HW_CORE_H_
+#define _CAM_LRME_HW_CORE_H_
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_defs.h>
+#include <media/cam_lrme.h>
+
+#include "cam_common_util.h"
+#include "cam_debug_util.h"
+#include "cam_io_util.h"
+#include "cam_cpas_api.h"
+#include "cam_cdm_intf_api.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_req_mgr_workq.h"
+
+#define CAM_LRME_HW_RESET_TIMEOUT 3000
+
+#define CAM_LRME_BUS_RD_MAX_CLIENTS 2
+#define CAM_LRME_BUS_WR_MAX_CLIENTS 2
+
+#define CAM_LRME_HW_WORKQ_NUM_TASK 30
+
+#define CAM_LRME_TOP_IRQ_MASK 0x19
+#define CAM_LRME_WE_IRQ_MASK_0 0x2
+#define CAM_LRME_WE_IRQ_MASK_1 0x0
+#define CAM_LRME_FE_IRQ_MASK 0x0
+
+#define CAM_LRME_MAX_REG_PAIR_NUM 60
+
+/**
+ * enum cam_lrme_irq_set
+ *
+ * @CAM_LRME_IRQ_ENABLE : Enable irqs
+ * @CAM_LRME_IRQ_DISABLE : Disable irqs
+ */
+enum cam_lrme_irq_set {
+ CAM_LRME_IRQ_ENABLE,
+ CAM_LRME_IRQ_DISABLE,
+};
+
+/**
+ * struct cam_lrme_cdm_info : information used to submit cdm command
+ *
+ * @cdm_handle : CDM handle for this device
+ * @cdm_ops : CDM ops
+ * @cdm_cmd : CDM command pointer
+ */
+struct cam_lrme_cdm_info {
+ uint32_t cdm_handle;
+ struct cam_cdm_utils_ops *cdm_ops;
+ struct cam_cdm_bl_request *cdm_cmd;
+};
+
+/**
+ * struct cam_lrme_hw_work_data : Work data for HW work queue
+ *
+ * @top_irq_status : Top registers irq status
+ * @fe_irq_status : FE engine irq status
+ * @we_irq_status : WE engine irq status
+ */
+struct cam_lrme_hw_work_data {
+ uint32_t top_irq_status;
+ uint32_t fe_irq_status;
+ uint32_t we_irq_status[2];
+};
+
+/**
+ * enum cam_lrme_core_state : LRME core states
+ *
+ * @CAM_LRME_CORE_STATE_UNINIT : LRME is in uninit state
+ * @CAM_LRME_CORE_STATE_INIT : LRME is in init state after probe
+ * @ CAM_LRME_CORE_STATE_IDLE : LRME is in idle state. Hardware is in
+ * this state when no frame is processing
+ * or waiting for this core.
+ * @CAM_LRME_CORE_STATE_REQ_PENDING : LRME is in pending state. One frame is
+ * waiting for processing
+ * @CAM_LRME_CORE_STATE_PROCESSING : LRME is in processing state. HW manager
+ * can submit one more frame to HW
+ * @CAM_LRME_CORE_STATE_REQ_PROC_PEND : Indicate two frames are inside HW.
+ * @CAM_LRME_CORE_STATE_RECOVERY : Indicate core is in the process of reset
+ * @CAM_LRME_CORE_STATE_MAX : upper limit of states
+ */
+enum cam_lrme_core_state {
+ CAM_LRME_CORE_STATE_UNINIT,
+ CAM_LRME_CORE_STATE_INIT,
+ CAM_LRME_CORE_STATE_IDLE,
+ CAM_LRME_CORE_STATE_REQ_PENDING,
+ CAM_LRME_CORE_STATE_PROCESSING,
+ CAM_LRME_CORE_STATE_REQ_PROC_PEND,
+ CAM_LRME_CORE_STATE_RECOVERY,
+ CAM_LRME_CORE_STATE_MAX,
+};
+
+/**
+ * struct cam_lrme_core : LRME HW core information
+ *
+ * @hw_info : Pointer to base HW information structure
+ * @device_iommu : Device iommu handle
+ * @cdm_iommu : CDM iommu handle
+ * @hw_caps : Hardware capabilities
+ * @state : Hardware state
+ * @reset_complete : Reset completion
+ * @work : Hardware workqueue to handle irq events
+ * @work_data : Work data used by hardware workqueue
+ * @hw_mgr_cb : Hw manager callback
+ * @req_proc : Pointer to the processing frame request
+ * @req_submit : Pointer to the frame request waiting for processing
+ * @hw_cdm_info : CDM information used by this device
+ * @hw_idx : Hardware index
+ */
+struct cam_lrme_core {
+ struct cam_lrme_hw_info *hw_info;
+ struct cam_iommu_handle device_iommu;
+ struct cam_iommu_handle cdm_iommu;
+ struct cam_lrme_dev_cap hw_caps;
+ enum cam_lrme_core_state state;
+ struct completion reset_complete;
+ struct cam_req_mgr_core_workq *work;
+ struct cam_lrme_hw_work_data work_data[CAM_LRME_HW_WORKQ_NUM_TASK];
+ struct cam_lrme_hw_cmd_set_cb hw_mgr_cb;
+ struct cam_lrme_frame_request *req_proc;
+ struct cam_lrme_frame_request *req_submit;
+ struct cam_lrme_cdm_info *hw_cdm_info;
+ uint32_t hw_idx;
+};
+
+/**
+ * struct cam_lrme_bus_rd_reg_common : Offsets of FE common registers
+ *
+ * @hw_version : Offset of hw_version register
+ * @hw_capability : Offset of hw_capability register
+ * @sw_reset : Offset of sw_reset register
+ * @cgc_override : Offset of cgc_override register
+ * @irq_mask : Offset of irq_mask register
+ * @irq_clear : Offset of irq_clear register
+ * @irq_cmd : Offset of irq_cmd register
+ * @irq_status : Offset of irq_status register
+ * @cmd : Offset of cmd register
+ * @irq_set : Offset of irq_set register
+ * @misr_reset : Offset of misr_reset register
+ * @security_cfg : Offset of security_cfg register
+ * @pwr_iso_cfg : Offset of pwr_iso_cfg register
+ * @pwr_iso_seed : Offset of pwr_iso_seed register
+ * @test_bus_ctrl : Offset of test_bus_ctrl register
+ * @spare : Offset of spare register
+ */
+struct cam_lrme_bus_rd_reg_common {
+ uint32_t hw_version;
+ uint32_t hw_capability;
+ uint32_t sw_reset;
+ uint32_t cgc_override;
+ uint32_t irq_mask;
+ uint32_t irq_clear;
+ uint32_t irq_cmd;
+ uint32_t irq_status;
+ uint32_t cmd;
+ uint32_t irq_set;
+ uint32_t misr_reset;
+ uint32_t security_cfg;
+ uint32_t pwr_iso_cfg;
+ uint32_t pwr_iso_seed;
+ uint32_t test_bus_ctrl;
+ uint32_t spare;
+};
+
+/**
+ * struct cam_lrme_bus_wr_reg_common : Offset of WE common registers
+ * @hw_version : Offset of hw_version register
+ * @hw_capability : Offset of hw_capability register
+ * @sw_reset : Offset of sw_reset register
+ * @cgc_override : Offset of cgc_override register
+ * @misr_reset : Offset of misr_reset register
+ * @pwr_iso_cfg : Offset of pwr_iso_cfg register
+ * @test_bus_ctrl : Offset of test_bus_ctrl register
+ * @composite_mask_0 : Offset of composite_mask_0 register
+ * @irq_mask_0 : Offset of irq_mask_0 register
+ * @irq_mask_1 : Offset of irq_mask_1 register
+ * @irq_clear_0 : Offset of irq_clear_0 register
+ * @irq_clear_1 : Offset of irq_clear_1 register
+ * @irq_status_0 : Offset of irq_status_0 register
+ * @irq_status_1 : Offset of irq_status_1 register
+ * @irq_cmd : Offset of irq_cmd register
+ * @irq_set_0 : Offset of irq_set_0 register
+ * @irq_set_1 : Offset of irq_set_1 register
+ * @addr_fifo_status : Offset of addr_fifo_status register
+ * @frame_header_cfg0 : Offset of frame_header_cfg0 register
+ * @frame_header_cfg1 : Offset of frame_header_cfg1 register
+ * @spare : Offset of spare register
+ */
+struct cam_lrme_bus_wr_reg_common {
+ uint32_t hw_version;
+ uint32_t hw_capability;
+ uint32_t sw_reset;
+ uint32_t cgc_override;
+ uint32_t misr_reset;
+ uint32_t pwr_iso_cfg;
+ uint32_t test_bus_ctrl;
+ uint32_t composite_mask_0;
+ uint32_t irq_mask_0;
+ uint32_t irq_mask_1;
+ uint32_t irq_clear_0;
+ uint32_t irq_clear_1;
+ uint32_t irq_status_0;
+ uint32_t irq_status_1;
+ uint32_t irq_cmd;
+ uint32_t irq_set_0;
+ uint32_t irq_set_1;
+ uint32_t addr_fifo_status;
+ uint32_t frame_header_cfg0;
+ uint32_t frame_header_cfg1;
+ uint32_t spare;
+};
+
+/**
+ * struct cam_lrme_bus_rd_bus_client : Offset of FE registers
+ *
+ * @core_cfg : Offset of core_cfg register
+ * @ccif_meta_data : Offset of ccif_meta_data register
+ * @addr_image : Offset of addr_image register
+ * @rd_buffer_size : Offset of rd_buffer_size register
+ * @rd_stride : Offset of rd_stride register
+ * @unpack_cfg_0 : Offset of unpack_cfg_0 register
+ * @latency_buff_allocation : Offset of latency_buff_allocation register
+ * @burst_limit_cfg : Offset of burst_limit_cfg register
+ * @misr_cfg_0 : Offset of misr_cfg_0 register
+ * @misr_cfg_1 : Offset of misr_cfg_1 register
+ * @misr_rd_val : Offset of misr_rd_val register
+ * @debug_status_cfg : Offset of debug_status_cfg register
+ * @debug_status_0 : Offset of debug_status_0 register
+ * @debug_status_1 : Offset of debug_status_1 register
+ */
+struct cam_lrme_bus_rd_bus_client {
+ uint32_t core_cfg;
+ uint32_t ccif_meta_data;
+ uint32_t addr_image;
+ uint32_t rd_buffer_size;
+ uint32_t rd_stride;
+ uint32_t unpack_cfg_0;
+ uint32_t latency_buff_allocation;
+ uint32_t burst_limit_cfg;
+ uint32_t misr_cfg_0;
+ uint32_t misr_cfg_1;
+ uint32_t misr_rd_val;
+ uint32_t debug_status_cfg;
+ uint32_t debug_status_0;
+ uint32_t debug_status_1;
+};
+
+/**
+ * struct cam_lrme_bus_wr_bus_client : Offset of WE registers
+ *
+ * @status_0 : Offset of status_0 register
+ * @status_1 : Offset of status_1 register
+ * @cfg : Offset of cfg register
+ * @addr_frame_header : Offset of addr_frame_header register
+ * @frame_header_cfg : Offset of frame_header_cfg register
+ * @addr_image : Offset of addr_image register
+ * @addr_image_offset : Offset of addr_image_offset register
+ * @buffer_width_cfg : Offset of buffer_width_cfg register
+ * @buffer_height_cfg : Offset of buffer_height_cfg register
+ * @packer_cfg : Offset of packer_cfg register
+ * @wr_stride : Offset of wr_stride register
+ * @irq_subsample_cfg_period : Offset of irq_subsample_cfg_period register
+ * @irq_subsample_cfg_pattern : Offset of irq_subsample_cfg_pattern register
+ * @burst_limit_cfg : Offset of burst_limit_cfg register
+ * @misr_cfg : Offset of misr_cfg register
+ * @misr_rd_word_sel : Offset of misr_rd_word_sel register
+ * @misr_val : Offset of misr_val register
+ * @debug_status_cfg : Offset of debug_status_cfg register
+ * @debug_status_0 : Offset of debug_status_0 register
+ * @debug_status_1 : Offset of debug_status_1 register
+ */
+struct cam_lrme_bus_wr_bus_client {
+ uint32_t status_0;
+ uint32_t status_1;
+ uint32_t cfg;
+ uint32_t addr_frame_header;
+ uint32_t frame_header_cfg;
+ uint32_t addr_image;
+ uint32_t addr_image_offset;
+ uint32_t buffer_width_cfg;
+ uint32_t buffer_height_cfg;
+ uint32_t packer_cfg;
+ uint32_t wr_stride;
+ uint32_t irq_subsample_cfg_period;
+ uint32_t irq_subsample_cfg_pattern;
+ uint32_t burst_limit_cfg;
+ uint32_t misr_cfg;
+ uint32_t misr_rd_word_sel;
+ uint32_t misr_val;
+ uint32_t debug_status_cfg;
+ uint32_t debug_status_0;
+ uint32_t debug_status_1;
+};
+
+/**
+ * struct cam_lrme_bus_rd_hw_info : FE registers information
+ *
+ * @common_reg : FE common register
+ * @bus_client_reg : List of FE bus registers information
+ */
+struct cam_lrme_bus_rd_hw_info {
+ struct cam_lrme_bus_rd_reg_common common_reg;
+ struct cam_lrme_bus_rd_bus_client
+ bus_client_reg[CAM_LRME_BUS_RD_MAX_CLIENTS];
+};
+
+/**
+ * struct cam_lrme_bus_wr_hw_info : WE engine registers information
+ *
+ * @common_reg : WE common register
+ * @bus_client_reg : List of WE bus registers information
+ */
+struct cam_lrme_bus_wr_hw_info {
+ struct cam_lrme_bus_wr_reg_common common_reg;
+ struct cam_lrme_bus_wr_bus_client
+ bus_client_reg[CAM_LRME_BUS_WR_MAX_CLIENTS];
+};
+
+/**
+ * struct cam_lrme_clc_reg : Offset of clc registers
+ *
+ * @clc_hw_version : Offset of clc_hw_version register
+ * @clc_hw_status : Offset of clc_hw_status register
+ * @clc_hw_status_dbg : Offset of clc_hw_status_dbg register
+ * @clc_module_cfg : Offset of clc_module_cfg register
+ * @clc_moduleformat : Offset of clc_moduleformat register
+ * @clc_rangestep : Offset of clc_rangestep register
+ * @clc_offset : Offset of clc_offset register
+ * @clc_maxallowedsad : Offset of clc_maxallowedsad register
+ * @clc_minallowedtarmad : Offset of clc_minallowedtarmad register
+ * @clc_meaningfulsaddiff : Offset of clc_meaningfulsaddiff register
+ * @clc_minsaddiffdenom : Offset of clc_minsaddiffdenom register
+ * @clc_robustnessmeasuredistmap_0 : Offset of measuredistmap_0 register
+ * @clc_robustnessmeasuredistmap_1 : Offset of measuredistmap_1 register
+ * @clc_robustnessmeasuredistmap_2 : Offset of measuredistmap_2 register
+ * @clc_robustnessmeasuredistmap_3 : Offset of measuredistmap_3 register
+ * @clc_robustnessmeasuredistmap_4 : Offset of measuredistmap_4 register
+ * @clc_robustnessmeasuredistmap_5 : Offset of measuredistmap_5 register
+ * @clc_robustnessmeasuredistmap_6 : Offset of measuredistmap_6 register
+ * @clc_robustnessmeasuredistmap_7 : Offset of measuredistmap_7 register
+ * @clc_ds_crop_horizontal : Offset of clc_ds_crop_horizontal register
+ * @clc_ds_crop_vertical : Offset of clc_ds_crop_vertical register
+ * @clc_tar_pd_unpacker : Offset of clc_tar_pd_unpacker register
+ * @clc_ref_pd_unpacker : Offset of clc_ref_pd_unpacker register
+ * @clc_sw_override : Offset of clc_sw_override register
+ * @clc_tar_height : Offset of clc_tar_height register
+ * @clc_test_bus_ctrl : Offset of clc_test_bus_ctrl register
+ * @clc_spare : Offset of clc_spare register
+ */
+struct cam_lrme_clc_reg {
+ uint32_t clc_hw_version;
+ uint32_t clc_hw_status;
+ uint32_t clc_hw_status_dbg;
+ uint32_t clc_module_cfg;
+ uint32_t clc_moduleformat;
+ uint32_t clc_rangestep;
+ uint32_t clc_offset;
+ uint32_t clc_maxallowedsad;
+ uint32_t clc_minallowedtarmad;
+ uint32_t clc_meaningfulsaddiff;
+ uint32_t clc_minsaddiffdenom;
+ uint32_t clc_robustnessmeasuredistmap_0;
+ uint32_t clc_robustnessmeasuredistmap_1;
+ uint32_t clc_robustnessmeasuredistmap_2;
+ uint32_t clc_robustnessmeasuredistmap_3;
+ uint32_t clc_robustnessmeasuredistmap_4;
+ uint32_t clc_robustnessmeasuredistmap_5;
+ uint32_t clc_robustnessmeasuredistmap_6;
+ uint32_t clc_robustnessmeasuredistmap_7;
+ uint32_t clc_ds_crop_horizontal;
+ uint32_t clc_ds_crop_vertical;
+ uint32_t clc_tar_pd_unpacker;
+ uint32_t clc_ref_pd_unpacker;
+ uint32_t clc_sw_override;
+ uint32_t clc_tar_height;
+ uint32_t clc_ref_height;
+ uint32_t clc_test_bus_ctrl;
+ uint32_t clc_spare;
+};
+
+/**
+ * struct cam_lrme_titan_reg : Offset of LRME top registers
+ *
+ * @top_hw_version : Offset of top_hw_version register
+ * @top_titan_version : Offset of top_titan_version register
+ * @top_rst_cmd : Offset of top_rst_cmd register
+ * @top_core_clk_cfg : Offset of top_core_clk_cfg register
+ * @top_irq_status : Offset of top_irq_status register
+ * @top_irq_mask : Offset of top_irq_mask register
+ * @top_irq_clear : Offset of top_irq_clear register
+ * @top_irq_set : Offset of top_irq_set register
+ * @top_irq_cmd : Offset of top_irq_cmd register
+ * @top_violation_status : Offset of top_violation_status register
+ * @top_spare : Offset of top_spare register
+ */
+struct cam_lrme_titan_reg {
+ uint32_t top_hw_version;
+ uint32_t top_titan_version;
+ uint32_t top_rst_cmd;
+ uint32_t top_core_clk_cfg;
+ uint32_t top_irq_status;
+ uint32_t top_irq_mask;
+ uint32_t top_irq_clear;
+ uint32_t top_irq_set;
+ uint32_t top_irq_cmd;
+ uint32_t top_violation_status;
+ uint32_t top_spare;
+};
+
+/**
+ * struct cam_lrme_hw_info : LRME registers information
+ *
+ * @clc_reg : LRME CLC registers
+ * @bus_rd_reg : LRME FE registers
+ * @bus_wr_reg : LRME WE registers
+ * @titan_reg : LRME top reisters
+ */
+struct cam_lrme_hw_info {
+ struct cam_lrme_clc_reg clc_reg;
+ struct cam_lrme_bus_rd_hw_info bus_rd_reg;
+ struct cam_lrme_bus_wr_hw_info bus_wr_reg;
+ struct cam_lrme_titan_reg titan_reg;
+};
+
+int cam_lrme_hw_process_irq(void *priv, void *data);
+int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args,
+ uint32_t arg_size);
+int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size);
+int cam_lrme_hw_stop(void *hw_priv, void *stop_args, uint32_t arg_size);
+int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args,
+ uint32_t arg_size);
+irqreturn_t cam_lrme_hw_irq(int irq_num, void *data);
+int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type,
+ void *cmd_args, uint32_t arg_size);
+int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw,
+ struct cam_lrme_dev_cap *hw_caps);
+int cam_lrme_hw_start(void *hw_priv, void *hw_init_args, uint32_t arg_size);
+int cam_lrme_hw_flush(void *hw_priv, void *hw_flush_args, uint32_t arg_size);
+void cam_lrme_set_irq(struct cam_hw_info *lrme_hw, enum cam_lrme_irq_set set);
+
+#endif /* _CAM_LRME_HW_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
new file mode 100644
index 0000000..2e63752
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
@@ -0,0 +1,320 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_req_mgr.h>
+
+#include "cam_subdev.h"
+#include "cam_lrme_hw_intf.h"
+#include "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+#include "cam_lrme_hw_reg.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_lrme_hw_mgr.h"
+#include "cam_mem_mgr_api.h"
+#include "cam_smmu_api.h"
+
+#define CAM_LRME_HW_WORKQ_NUM_TASK 30
+
+static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core,
+ struct cam_hw_info *lrme_hw)
+{
+ int rc, i;
+ struct cam_cdm_bl_request *cdm_cmd;
+ struct cam_cdm_acquire_data cdm_acquire;
+ struct cam_lrme_cdm_info *hw_cdm_info;
+
+ hw_cdm_info = kzalloc(sizeof(struct cam_lrme_cdm_info),
+ GFP_KERNEL);
+ if (!hw_cdm_info) {
+ CAM_ERR(CAM_LRME, "No memory for hw_cdm_info");
+ return -ENOMEM;
+ }
+
+ cdm_cmd = kzalloc((sizeof(struct cam_cdm_bl_request) +
+ ((CAM_LRME_MAX_HW_ENTRIES - 1) *
+ sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
+ if (!cdm_cmd) {
+ CAM_ERR(CAM_LRME, "No memory for cdm_cmd");
+ kfree(hw_cdm_info);
+ return -ENOMEM;
+ }
+
+ memset(&cdm_acquire, 0, sizeof(cdm_acquire));
+ strlcpy(cdm_acquire.identifier, "lrmecdm", sizeof("lrmecdm"));
+ cdm_acquire.cell_index = lrme_hw->soc_info.index;
+ cdm_acquire.handle = 0;
+ cdm_acquire.userdata = hw_cdm_info;
+ cdm_acquire.cam_cdm_callback = NULL;
+ cdm_acquire.id = CAM_CDM_VIRTUAL;
+ cdm_acquire.base_array_cnt = lrme_hw->soc_info.num_reg_map;
+ for (i = 0; i < lrme_hw->soc_info.num_reg_map; i++)
+ cdm_acquire.base_array[i] = &lrme_hw->soc_info.reg_map[i];
+
+ rc = cam_cdm_acquire(&cdm_acquire);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Can't acquire cdm");
+ goto error;
+ }
+
+ hw_cdm_info->cdm_cmd = cdm_cmd;
+ hw_cdm_info->cdm_ops = cdm_acquire.ops;
+ hw_cdm_info->cdm_handle = cdm_acquire.handle;
+
+ lrme_core->hw_cdm_info = hw_cdm_info;
+ CAM_DBG(CAM_LRME, "cdm acquire done");
+
+ return 0;
+error:
+ kfree(cdm_cmd);
+ kfree(hw_cdm_info);
+ return rc;
+}
+
+static int cam_lrme_hw_dev_probe(struct platform_device *pdev)
+{
+ struct cam_hw_info *lrme_hw;
+ struct cam_hw_intf lrme_hw_intf;
+ struct cam_lrme_core *lrme_core;
+ const struct of_device_id *match_dev = NULL;
+ struct cam_lrme_hw_info *hw_info;
+ int rc, i;
+
+ lrme_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+ if (!lrme_hw) {
+ CAM_ERR(CAM_LRME, "No memory to create lrme_hw");
+ return -ENOMEM;
+ }
+
+ lrme_core = kzalloc(sizeof(struct cam_lrme_core), GFP_KERNEL);
+ if (!lrme_core) {
+ CAM_ERR(CAM_LRME, "No memory to create lrme_core");
+ kfree(lrme_hw);
+ return -ENOMEM;
+ }
+
+ lrme_hw->core_info = lrme_core;
+ lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+ lrme_hw->soc_info.pdev = pdev;
+ lrme_hw->soc_info.dev = &pdev->dev;
+ lrme_hw->soc_info.dev_name = pdev->name;
+ lrme_hw->open_count = 0;
+ lrme_core->state = CAM_LRME_CORE_STATE_INIT;
+
+ mutex_init(&lrme_hw->hw_mutex);
+ spin_lock_init(&lrme_hw->hw_lock);
+ init_completion(&lrme_hw->hw_complete);
+ init_completion(&lrme_core->reset_complete);
+
+ rc = cam_req_mgr_workq_create("cam_lrme_hw_worker",
+ CAM_LRME_HW_WORKQ_NUM_TASK,
+ &lrme_core->work, CRM_WORKQ_USAGE_IRQ);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc);
+ goto free_memory;
+ }
+
+ for (i = 0; i < CAM_LRME_HW_WORKQ_NUM_TASK; i++)
+ lrme_core->work->task.pool[i].payload =
+ &lrme_core->work_data[i];
+
+ match_dev = of_match_device(pdev->dev.driver->of_match_table,
+ &pdev->dev);
+ if (!match_dev || !match_dev->data) {
+ CAM_ERR(CAM_LRME, "No Of_match data, %pK", match_dev);
+ rc = -EINVAL;
+ goto destroy_workqueue;
+ }
+ hw_info = (struct cam_lrme_hw_info *)match_dev->data;
+ lrme_core->hw_info = hw_info;
+
+ rc = cam_lrme_soc_init_resources(&lrme_hw->soc_info,
+ cam_lrme_hw_irq, lrme_hw);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to init soc, rc=%d", rc);
+ goto destroy_workqueue;
+ }
+
+ rc = cam_lrme_hw_dev_util_cdm_acquire(lrme_core, lrme_hw);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to acquire cdm");
+ goto deinit_platform_res;
+ }
+
+ rc = cam_smmu_get_handle("lrme", &lrme_core->device_iommu.non_secure);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Get iommu handle failed");
+ goto release_cdm;
+ }
+
+ rc = cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_ATTACH);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "LRME attach iommu handle failed, rc=%d", rc);
+ goto destroy_smmu;
+ }
+
+ rc = cam_lrme_hw_start(lrme_hw, NULL, 0);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc);
+ goto detach_smmu;
+ }
+
+ rc = cam_lrme_hw_util_get_caps(lrme_hw, &lrme_core->hw_caps);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to get hw caps, rc=%d", rc);
+ if (cam_lrme_hw_stop(lrme_hw, NULL, 0))
+ CAM_ERR(CAM_LRME, "Failed in hw deinit");
+ goto detach_smmu;
+ }
+
+ rc = cam_lrme_hw_stop(lrme_hw, NULL, 0);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc);
+ goto detach_smmu;
+ }
+
+ lrme_core->hw_idx = lrme_hw->soc_info.index;
+ lrme_hw_intf.hw_priv = lrme_hw;
+ lrme_hw_intf.hw_idx = lrme_hw->soc_info.index;
+ lrme_hw_intf.hw_ops.get_hw_caps = cam_lrme_hw_get_caps;
+ lrme_hw_intf.hw_ops.init = NULL;
+ lrme_hw_intf.hw_ops.deinit = NULL;
+ lrme_hw_intf.hw_ops.reset = cam_lrme_hw_reset;
+ lrme_hw_intf.hw_ops.reserve = NULL;
+ lrme_hw_intf.hw_ops.release = NULL;
+ lrme_hw_intf.hw_ops.start = cam_lrme_hw_start;
+ lrme_hw_intf.hw_ops.stop = cam_lrme_hw_stop;
+ lrme_hw_intf.hw_ops.read = NULL;
+ lrme_hw_intf.hw_ops.write = NULL;
+ lrme_hw_intf.hw_ops.process_cmd = cam_lrme_hw_process_cmd;
+ lrme_hw_intf.hw_type = CAM_HW_LRME;
+
+ rc = cam_cdm_get_iommu_handle("lrmecdm", &lrme_core->cdm_iommu);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to acquire the CDM iommu handles");
+ goto detach_smmu;
+ }
+
+ rc = cam_lrme_mgr_register_device(&lrme_hw_intf,
+ &lrme_core->device_iommu,
+ &lrme_core->cdm_iommu);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to register device");
+ goto detach_smmu;
+ }
+
+ platform_set_drvdata(pdev, lrme_hw);
+ CAM_DBG(CAM_LRME, "LRME-%d probe successful", lrme_hw_intf.hw_idx);
+
+ return rc;
+
+detach_smmu:
+ cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH);
+destroy_smmu:
+ cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure);
+release_cdm:
+ cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle);
+ kfree(lrme_core->hw_cdm_info->cdm_cmd);
+ kfree(lrme_core->hw_cdm_info);
+deinit_platform_res:
+ if (cam_lrme_soc_deinit_resources(&lrme_hw->soc_info))
+ CAM_ERR(CAM_LRME, "Failed in soc deinit");
+ mutex_destroy(&lrme_hw->hw_mutex);
+destroy_workqueue:
+ cam_req_mgr_workq_destroy(&lrme_core->work);
+free_memory:
+ mutex_destroy(&lrme_hw->hw_mutex);
+ kfree(lrme_hw);
+ kfree(lrme_core);
+
+ return rc;
+}
+
+static int cam_lrme_hw_dev_remove(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct cam_hw_info *lrme_hw;
+ struct cam_lrme_core *lrme_core;
+
+ lrme_hw = platform_get_drvdata(pdev);
+ if (!lrme_hw) {
+ CAM_ERR(CAM_LRME, "Invalid lrme_hw from fd_hw_intf");
+ rc = -ENODEV;
+ goto deinit_platform_res;
+ }
+
+ lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
+ if (!lrme_core) {
+ CAM_ERR(CAM_LRME, "Invalid lrme_core from fd_hw");
+ rc = -EINVAL;
+ goto deinit_platform_res;
+ }
+
+ cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH);
+ cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure);
+ cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle);
+ cam_lrme_mgr_deregister_device(lrme_core->hw_idx);
+
+ kfree(lrme_core->hw_cdm_info->cdm_cmd);
+ kfree(lrme_core->hw_cdm_info);
+ kfree(lrme_core);
+
+deinit_platform_res:
+ rc = cam_lrme_soc_deinit_resources(&lrme_hw->soc_info);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Error in LRME soc deinit, rc=%d", rc);
+
+ mutex_destroy(&lrme_hw->hw_mutex);
+ kfree(lrme_hw);
+
+ return rc;
+}
+
+static const struct of_device_id cam_lrme_hw_dt_match[] = {
+ {
+ .compatible = "qcom,lrme",
+ .data = &cam_lrme10_hw_info,
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, cam_lrme_hw_dt_match);
+
+static struct platform_driver cam_lrme_hw_driver = {
+ .probe = cam_lrme_hw_dev_probe,
+ .remove = cam_lrme_hw_dev_remove,
+ .driver = {
+ .name = "cam_lrme_hw",
+ .owner = THIS_MODULE,
+ .of_match_table = cam_lrme_hw_dt_match,
+ },
+};
+
+static int __init cam_lrme_hw_init_module(void)
+{
+ return platform_driver_register(&cam_lrme_hw_driver);
+}
+
+static void __exit cam_lrme_hw_exit_module(void)
+{
+ platform_driver_unregister(&cam_lrme_hw_driver);
+}
+
+module_init(cam_lrme_hw_init_module);
+module_exit(cam_lrme_hw_exit_module);
+MODULE_DESCRIPTION("CAM LRME HW driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h
new file mode 100644
index 0000000..d16b174
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h
@@ -0,0 +1,200 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_LRME_HW_INTF_H_
+#define _CAM_LRME_HW_INTF_H_
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_cpas.h>
+#include <media/cam_req_mgr.h>
+#include <media/cam_lrme.h>
+
+#include "cam_io_util.h"
+#include "cam_soc_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_subdev.h"
+#include "cam_cpas_api.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_debug_util.h"
+
+
+#define CAM_LRME_MAX_IO_BUFFER 2
+#define CAM_LRME_MAX_HW_ENTRIES 5
+
+#define CAM_LRME_BASE_IDX 0
+
+/**
+ * enum cam_lrme_hw_type : Enum for LRME HW type
+ *
+ * @CAM_HW_LRME : LRME HW type
+ */
+enum cam_lrme_hw_type {
+ CAM_HW_LRME,
+};
+
+/**
+ * enum cam_lrme_cb_type : HW manager call back type
+ *
+ * @CAM_LRME_CB_BUF_DONE : Indicate buf done has been generated
+ * @CAM_LRME_CB_COMP_REG_UPDATE : Indicate receiving WE comp reg update
+ * @CAM_LRME_CB_PUT_FRAME : Request HW manager to put back the frame
+ * @CAM_LRME_CB_ERROR : Indicate error irq has been generated
+ */
+enum cam_lrme_cb_type {
+ CAM_LRME_CB_BUF_DONE = 1,
+ CAM_LRME_CB_COMP_REG_UPDATE = 1 << 1,
+ CAM_LRME_CB_PUT_FRAME = 1 << 2,
+ CAM_LRME_CB_ERROR = 1 << 3,
+};
+
+/**
+ * enum cam_lrme_hw_cmd_type : HW CMD type
+ *
+ * @CAM_LRME_HW_CMD_prepare_hw_update : Prepare HW update
+ * @CAM_LRME_HW_CMD_REGISTER_CB : register HW manager callback
+ * @CAM_LRME_HW_CMD_SUBMIT : Submit frame to HW
+ */
+enum cam_lrme_hw_cmd_type {
+ CAM_LRME_HW_CMD_PREPARE_HW_UPDATE,
+ CAM_LRME_HW_CMD_REGISTER_CB,
+ CAM_LRME_HW_CMD_SUBMIT,
+};
+
+/**
+ * enum cam_lrme_hw_reset_type : Type of reset
+ *
+ * @CAM_LRME_HW_RESET_TYPE_HW_RESET : HW reset
+ * @CAM_LRME_HW_RESET_TYPE_SW_RESET : SW reset
+ */
+enum cam_lrme_hw_reset_type {
+ CAM_LRME_HW_RESET_TYPE_HW_RESET,
+ CAM_LRME_HW_RESET_TYPE_SW_RESET,
+};
+
+/**
+ *struct cam_lrme_frame_request : LRME frame request
+ *
+ * @frame_list : List head
+ * @req_id : Request ID
+ * @ctxt_to_hw_map : Information about context id, priority and device id
+ * @hw_device : Pointer to HW device
+ * @hw_update_entries : List of hw_update_entries
+ * @num_hw_update_entries : number of hw_update_entries
+ */
+struct cam_lrme_frame_request {
+ struct list_head frame_list;
+ uint64_t req_id;
+ void *ctxt_to_hw_map;
+ struct cam_lrme_device *hw_device;
+ struct cam_hw_update_entry hw_update_entries[CAM_LRME_MAX_HW_ENTRIES];
+ uint32_t num_hw_update_entries;
+};
+
+/**
+ * struct cam_lrme_hw_io_buffer : IO buffer information
+ *
+ * @valid : Indicate whether this IO config is valid
+ * @io_cfg : Pointer to IO configuration
+ * @num_buf : Number of buffers
+ * @num_plane : Number of planes
+ * @io_addr : List of IO address
+ */
+struct cam_lrme_hw_io_buffer {
+ bool valid;
+ struct cam_buf_io_cfg *io_cfg;
+ uint32_t num_buf;
+ uint32_t num_plane;
+ uint64_t io_addr[CAM_PACKET_MAX_PLANES];
+};
+
+/**
+ * struct cam_lrme_hw_cmd_config_args : Args for prepare HW update
+ *
+ * @hw_device : Pointer to HW device
+ * @input_buf : List of input buffers
+ * @output_buf : List of output buffers
+ * @cmd_buf_addr : Pointer to available KMD buffer
+ * @size : Available KMD buffer size
+ * @config_buf_size : Size used to prepare update
+ */
+struct cam_lrme_hw_cmd_config_args {
+ struct cam_lrme_device *hw_device;
+ struct cam_lrme_hw_io_buffer input_buf[CAM_LRME_MAX_IO_BUFFER];
+ struct cam_lrme_hw_io_buffer output_buf[CAM_LRME_MAX_IO_BUFFER];
+ uint32_t *cmd_buf_addr;
+ uint32_t size;
+ uint32_t config_buf_size;
+};
+
+/**
+ * struct cam_lrme_hw_flush_args : Args for flush HW
+ *
+ * @ctxt_to_hw_map : Identity of context
+ * @req_to_flush : Pointer to the frame need to flush in
+ * case of single frame flush
+ * @flush_type : Flush type
+ */
+struct cam_lrme_hw_flush_args {
+ void *ctxt_to_hw_map;
+ struct cam_lrme_frame_request *req_to_flush;
+ uint32_t flush_type;
+};
+
+/**
+ * struct cam_lrme_hw_reset_args : Args for reset HW
+ *
+ * @reset_type : Enum cam_lrme_hw_reset_type
+ */
+struct cam_lrme_hw_reset_args {
+ uint32_t reset_type;
+};
+
+/**
+ * struct cam_lrme_hw_cb_args : HW manager callback args
+ *
+ * @cb_type : Callback event type
+ * @frame_req : Pointer to the frame associated with the cb
+ */
+struct cam_lrme_hw_cb_args {
+ uint32_t cb_type;
+ struct cam_lrme_frame_request *frame_req;
+};
+
+/**
+ * struct cam_lrme_hw_cmd_set_cb : Args for set callback function
+ *
+ * @cam_lrme_hw_mgr_cb : Callback function pointer
+ * @data : Data sent along with callback function
+ */
+struct cam_lrme_hw_cmd_set_cb {
+ int (*cam_lrme_hw_mgr_cb)(void *data,
+ struct cam_lrme_hw_cb_args *args);
+ void *data;
+};
+
+/**
+ * struct cam_lrme_hw_submit_args : Args for submit request
+ *
+ * @hw_update_entries : List of hw update entries used to program registers
+ * @num_hw_update_entries : Number of hw update entries
+ * @frame_req : Pointer to the frame request
+ */
+struct cam_lrme_hw_submit_args {
+ struct cam_hw_update_entry *hw_update_entries;
+ uint32_t num_hw_update_entries;
+ struct cam_lrme_frame_request *frame_req;
+};
+
+#endif /* _CAM_LRME_HW_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h
new file mode 100644
index 0000000..39cfde7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h
@@ -0,0 +1,193 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_LRME_HW_REG_H_
+#define _CAM_LRME_HW_REG_H_
+
+#include "cam_lrme_hw_core.h"
+
+static struct cam_lrme_hw_info cam_lrme10_hw_info = {
+ .clc_reg = {
+ .clc_hw_version = 0x00000000,
+ .clc_hw_status = 0x00000004,
+ .clc_hw_status_dbg = 0x00000008,
+ .clc_module_cfg = 0x00000060,
+ .clc_moduleformat = 0x000000A8,
+ .clc_rangestep = 0x00000068,
+ .clc_offset = 0x0000006C,
+ .clc_maxallowedsad = 0x00000070,
+ .clc_minallowedtarmad = 0x00000074,
+ .clc_meaningfulsaddiff = 0x00000078,
+ .clc_minsaddiffdenom = 0x0000007C,
+ .clc_robustnessmeasuredistmap_0 = 0x00000080,
+ .clc_robustnessmeasuredistmap_1 = 0x00000084,
+ .clc_robustnessmeasuredistmap_2 = 0x00000088,
+ .clc_robustnessmeasuredistmap_3 = 0x0000008C,
+ .clc_robustnessmeasuredistmap_4 = 0x00000090,
+ .clc_robustnessmeasuredistmap_5 = 0x00000094,
+ .clc_robustnessmeasuredistmap_6 = 0x00000098,
+ .clc_robustnessmeasuredistmap_7 = 0x0000009C,
+ .clc_ds_crop_horizontal = 0x000000A0,
+ .clc_ds_crop_vertical = 0x000000A4,
+ .clc_tar_pd_unpacker = 0x000000AC,
+ .clc_ref_pd_unpacker = 0x000000B0,
+ .clc_sw_override = 0x000000B4,
+ .clc_tar_height = 0x000000B8,
+ .clc_ref_height = 0x000000BC,
+ .clc_test_bus_ctrl = 0x000001F8,
+ .clc_spare = 0x000001FC,
+ },
+ .bus_rd_reg = {
+ .common_reg = {
+ .hw_version = 0x00000200,
+ .hw_capability = 0x00000204,
+ .sw_reset = 0x00000208,
+ .cgc_override = 0x0000020C,
+ .irq_mask = 0x00000210,
+ .irq_clear = 0x00000214,
+ .irq_cmd = 0x00000218,
+ .irq_status = 0x0000021C,
+ .cmd = 0x00000220,
+ .irq_set = 0x00000224,
+ .misr_reset = 0x0000022C,
+ .security_cfg = 0x00000230,
+ .pwr_iso_cfg = 0x00000234,
+ .pwr_iso_seed = 0x00000238,
+ .test_bus_ctrl = 0x00000248,
+ .spare = 0x0000024C,
+ },
+ .bus_client_reg = {
+ /* bus client 0 */
+ {
+ .core_cfg = 0x00000250,
+ .ccif_meta_data = 0x00000254,
+ .addr_image = 0x00000258,
+ .rd_buffer_size = 0x0000025C,
+ .rd_stride = 0x00000260,
+ .unpack_cfg_0 = 0x00000264,
+ .latency_buff_allocation = 0x00000278,
+ .burst_limit_cfg = 0x00000280,
+ .misr_cfg_0 = 0x00000284,
+ .misr_cfg_1 = 0x00000288,
+ .misr_rd_val = 0x0000028C,
+ .debug_status_cfg = 0x00000290,
+ .debug_status_0 = 0x00000294,
+ .debug_status_1 = 0x00000298,
+ },
+ /* bus client 1 */
+ {
+ .core_cfg = 0x000002F0,
+ .ccif_meta_data = 0x000002F4,
+ .addr_image = 0x000002F8,
+ .rd_buffer_size = 0x000002FC,
+ .rd_stride = 0x00000300,
+ .unpack_cfg_0 = 0x00000304,
+ .latency_buff_allocation = 0x00000318,
+ .burst_limit_cfg = 0x00000320,
+ .misr_cfg_0 = 0x00000324,
+ .misr_cfg_1 = 0x00000328,
+ .misr_rd_val = 0x0000032C,
+ .debug_status_cfg = 0x00000330,
+ .debug_status_0 = 0x00000334,
+ .debug_status_1 = 0x00000338,
+ },
+ },
+ },
+ .bus_wr_reg = {
+ .common_reg = {
+ .hw_version = 0x00000500,
+ .hw_capability = 0x00000504,
+ .sw_reset = 0x00000508,
+ .cgc_override = 0x0000050C,
+ .misr_reset = 0x000005C8,
+ .pwr_iso_cfg = 0x000005CC,
+ .test_bus_ctrl = 0x0000061C,
+ .composite_mask_0 = 0x00000510,
+ .irq_mask_0 = 0x00000544,
+ .irq_mask_1 = 0x00000548,
+ .irq_clear_0 = 0x00000550,
+ .irq_clear_1 = 0x00000554,
+ .irq_status_0 = 0x0000055C,
+ .irq_status_1 = 0x00000560,
+ .irq_cmd = 0x00000568,
+ .irq_set_0 = 0x000005BC,
+ .irq_set_1 = 0x000005C0,
+ .addr_fifo_status = 0x000005A8,
+ .frame_header_cfg0 = 0x000005AC,
+ .frame_header_cfg1 = 0x000005B0,
+ .spare = 0x00000620,
+ },
+ .bus_client_reg = {
+ /* bus client 0 */
+ {
+ .status_0 = 0x00000700,
+ .status_1 = 0x00000704,
+ .cfg = 0x00000708,
+ .addr_frame_header = 0x0000070C,
+ .frame_header_cfg = 0x00000710,
+ .addr_image = 0x00000714,
+ .addr_image_offset = 0x00000718,
+ .buffer_width_cfg = 0x0000071C,
+ .buffer_height_cfg = 0x00000720,
+ .packer_cfg = 0x00000724,
+ .wr_stride = 0x00000728,
+ .irq_subsample_cfg_period = 0x00000748,
+ .irq_subsample_cfg_pattern = 0x0000074C,
+ .burst_limit_cfg = 0x0000075C,
+ .misr_cfg = 0x00000760,
+ .misr_rd_word_sel = 0x00000764,
+ .misr_val = 0x00000768,
+ .debug_status_cfg = 0x0000076C,
+ .debug_status_0 = 0x00000770,
+ .debug_status_1 = 0x00000774,
+ },
+ /* bus client 1 */
+ {
+ .status_0 = 0x00000800,
+ .status_1 = 0x00000804,
+ .cfg = 0x00000808,
+ .addr_frame_header = 0x0000080C,
+ .frame_header_cfg = 0x00000810,
+ .addr_image = 0x00000814,
+ .addr_image_offset = 0x00000818,
+ .buffer_width_cfg = 0x0000081C,
+ .buffer_height_cfg = 0x00000820,
+ .packer_cfg = 0x00000824,
+ .wr_stride = 0x00000828,
+ .irq_subsample_cfg_period = 0x00000848,
+ .irq_subsample_cfg_pattern = 0x0000084C,
+ .burst_limit_cfg = 0x0000085C,
+ .misr_cfg = 0x00000860,
+ .misr_rd_word_sel = 0x00000864,
+ .misr_val = 0x00000868,
+ .debug_status_cfg = 0x0000086C,
+ .debug_status_0 = 0x00000870,
+ .debug_status_1 = 0x00000874,
+ },
+ },
+ },
+ .titan_reg = {
+ .top_hw_version = 0x00000900,
+ .top_titan_version = 0x00000904,
+ .top_rst_cmd = 0x00000908,
+ .top_core_clk_cfg = 0x00000920,
+ .top_irq_status = 0x0000090C,
+ .top_irq_mask = 0x00000910,
+ .top_irq_clear = 0x00000914,
+ .top_irq_set = 0x00000918,
+ .top_irq_cmd = 0x0000091C,
+ .top_violation_status = 0x00000924,
+ .top_spare = 0x000009FC,
+ },
+};
+
+#endif /* _CAM_LRME_HW_REG_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c
new file mode 100644
index 0000000..75de0dd
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c
@@ -0,0 +1,158 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_lrme_hw_core.h"
+#include "cam_lrme_hw_soc.h"
+
+
+int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw)
+{
+ struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+ struct cam_lrme_soc_private *soc_private =
+ (struct cam_lrme_soc_private *)soc_info->soc_private;
+ struct cam_ahb_vote ahb_vote;
+ struct cam_axi_vote axi_vote;
+ int rc = 0;
+
+ ahb_vote.type = CAM_VOTE_ABSOLUTE;
+ ahb_vote.vote.level = CAM_SVS_VOTE;
+ axi_vote.compressed_bw = 7200000;
+ axi_vote.uncompressed_bw = 7200000;
+ rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to start cpas, rc %d", rc);
+ return -EFAULT;
+ }
+
+ rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE,
+ true);
+ if (rc) {
+ CAM_ERR(CAM_LRME,
+ "Failed to enable platform resource, rc %d", rc);
+ goto stop_cpas;
+ }
+
+ cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_ENABLE);
+
+ return rc;
+
+stop_cpas:
+ if (cam_cpas_stop(soc_private->cpas_handle))
+ CAM_ERR(CAM_LRME, "Failed to stop cpas");
+
+ return rc;
+}
+
+int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw)
+{
+ struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info;
+ struct cam_lrme_soc_private *soc_private;
+ int rc = 0;
+
+ soc_private = soc_info->soc_private;
+
+ cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_DISABLE);
+
+ rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed to disable platform resource");
+ return rc;
+ }
+ rc = cam_cpas_stop(soc_private->cpas_handle);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Failed to stop cpas");
+
+ return rc;
+}
+
+int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info,
+ irq_handler_t irq_handler, void *private_data)
+{
+ struct cam_lrme_soc_private *soc_private;
+ struct cam_cpas_register_params cpas_register_param;
+ int rc;
+
+ rc = cam_soc_util_get_dt_properties(soc_info);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed in get_dt_properties, rc=%d", rc);
+ return rc;
+ }
+
+ rc = cam_soc_util_request_platform_resource(soc_info, irq_handler,
+ private_data);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "Failed in request_platform_resource rc=%d",
+ rc);
+ return rc;
+ }
+
+ soc_private = kzalloc(sizeof(struct cam_lrme_soc_private), GFP_KERNEL);
+ if (!soc_private) {
+ rc = -ENOMEM;
+ goto release_res;
+ }
+ soc_info->soc_private = soc_private;
+
+ memset(&cpas_register_param, 0, sizeof(cpas_register_param));
+ strlcpy(cpas_register_param.identifier,
+ "lrmecpas", CAM_HW_IDENTIFIER_LENGTH);
+ cpas_register_param.cell_index = soc_info->index;
+ cpas_register_param.dev = &soc_info->pdev->dev;
+ cpas_register_param.userdata = private_data;
+ cpas_register_param.cam_cpas_client_cb = NULL;
+
+ rc = cam_cpas_register_client(&cpas_register_param);
+ if (rc) {
+ CAM_ERR(CAM_LRME, "CPAS registration failed");
+ goto free_soc_private;
+ }
+ soc_private->cpas_handle = cpas_register_param.client_handle;
+ CAM_DBG(CAM_LRME, "CPAS handle=%d", soc_private->cpas_handle);
+
+ return rc;
+
+free_soc_private:
+ kfree(soc_info->soc_private);
+ soc_info->soc_private = NULL;
+release_res:
+ cam_soc_util_release_platform_resource(soc_info);
+
+ return rc;
+}
+
+int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info)
+{
+ struct cam_lrme_soc_private *soc_private =
+ (struct cam_lrme_soc_private *)soc_info->soc_private;
+ int rc;
+
+ rc = cam_cpas_unregister_client(soc_private->cpas_handle);
+ if (rc)
+ CAM_ERR(CAM_LRME, "Unregister cpas failed, handle=%d, rc=%d",
+ soc_private->cpas_handle, rc);
+
+ rc = cam_soc_util_release_platform_resource(soc_info);
+ if (rc)
+ CAM_ERR(CAM_LRME, "release platform failed, rc=%d", rc);
+
+ kfree(soc_info->soc_private);
+ soc_info->soc_private = NULL;
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h
new file mode 100644
index 0000000..44e8486
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_LRME_HW_SOC_H_
+#define _CAM_LRME_HW_SOC_H_
+
+#include "cam_soc_util.h"
+
+struct cam_lrme_soc_private {
+ uint32_t cpas_handle;
+};
+
+int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw);
+int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw);
+int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info,
+ irq_handler_t irq_handler, void *private_data);
+int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info);
+
+#endif /* _CAM_LRME_HW_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index f38af7d..244746b 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -810,15 +810,34 @@
*/
static void __cam_req_mgr_sof_freeze(unsigned long data)
{
- struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
- struct cam_req_mgr_core_link *link = NULL;
+ struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
+ struct cam_req_mgr_core_link *link = NULL;
+ struct cam_req_mgr_core_session *session = NULL;
+ struct cam_req_mgr_message msg;
if (!timer) {
CAM_ERR(CAM_CRM, "NULL timer");
return;
}
link = (struct cam_req_mgr_core_link *)timer->parent;
- CAM_ERR(CAM_CRM, "SOF freeze for link %x", link->link_hdl);
+ session = (struct cam_req_mgr_core_session *)link->parent;
+
+ CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x",
+ session->session_hdl, link->link_hdl);
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.session_hdl = session->session_hdl;
+ msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_DEVICE;
+ msg.u.err_msg.request_id = 0;
+ msg.u.err_msg.link_hdl = link->link_hdl;
+
+
+ if (cam_req_mgr_notify_message(&msg,
+ V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT))
+ CAM_ERR(CAM_CRM,
+ "Error notifying SOF freeze for session %d link 0x%x",
+ session->session_hdl, link->link_hdl);
}
/**
@@ -863,12 +882,14 @@
* @brief : Cleans up the mem allocated while linking
* @link : pointer to link, mem associated with this link is freed
*
+ * @return : returns if unlink for any device was success or failure
*/
-static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
+static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
{
int32_t i = 0;
struct cam_req_mgr_connected_device *dev;
struct cam_req_mgr_core_dev_link_setup link_data;
+ int rc = 0;
link_data.link_enable = 0;
link_data.link_hdl = link->link_hdl;
@@ -881,7 +902,11 @@
if (dev != NULL) {
link_data.dev_hdl = dev->dev_hdl;
if (dev->ops && dev->ops->link_setup)
- dev->ops->link_setup(&link_data);
+ rc = dev->ops->link_setup(&link_data);
+ if (rc)
+ CAM_ERR(CAM_CRM,
+ "Unlink failed dev_hdl %d",
+ dev->dev_hdl);
dev->dev_hdl = 0;
dev->parent = NULL;
dev->ops = NULL;
@@ -896,6 +921,7 @@
link->num_devs = 0;
link->max_delay = 0;
+ return rc;
}
/**
@@ -2024,8 +2050,12 @@
cam_req_mgr_workq_destroy(&link->workq);
- /* Cleanuprequest tables */
- __cam_req_mgr_destroy_link_info(link);
+ /* Cleanup request tables and unlink devices */
+ rc = __cam_req_mgr_destroy_link_info(link);
+ if (rc) {
+ CAM_ERR(CAM_CORE, "Unlink failed. Cannot proceed");
+ return rc;
+ }
/* Free memory holding data of linked devs */
__cam_req_mgr_destroy_subdev(link->l_dev);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index c316dbb..49c3c56e 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -462,7 +462,7 @@
return rc;
}
-int cam_req_mgr_notify_frame_message(struct cam_req_mgr_message *msg,
+int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg,
uint32_t id,
uint32_t type)
{
@@ -481,7 +481,7 @@
return 0;
}
-EXPORT_SYMBOL(cam_req_mgr_notify_frame_message);
+EXPORT_SYMBOL(cam_req_mgr_notify_message);
void cam_video_device_cleanup(void)
{
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
index 77faed9..93278b8 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.h
@@ -43,7 +43,7 @@
#define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \
(type *)((char *)ev.u.data)
-int cam_req_mgr_notify_frame_message(struct cam_req_mgr_message *msg,
+int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg,
uint32_t id,
uint32_t type);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
index 1d2169b..f357941 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
@@ -317,6 +317,8 @@
}
hdl_tbl->hdl[idx].state = HDL_FREE;
+ hdl_tbl->hdl[idx].ops = NULL;
+ hdl_tbl->hdl[idx].priv = NULL;
clear_bit(idx, hdl_tbl->bitmap);
spin_unlock_bh(&hdl_tbl_lock);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index f151b9b..d7a6504 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -730,17 +730,30 @@
reg_addr++;
} else {
if ((i + 1) <= cci_dev->payload_size) {
- if (i2c_msg->data_type ==
- CAMERA_SENSOR_I2C_TYPE_DWORD) {
+ switch (i2c_msg->data_type) {
+ case CAMERA_SENSOR_I2C_TYPE_DWORD:
data[i++] = (i2c_cmd->reg_data &
0xFF000000) >> 24;
+ /* fallthrough */
+ case CAMERA_SENSOR_I2C_TYPE_3B:
data[i++] = (i2c_cmd->reg_data &
0x00FF0000) >> 16;
+ /* fallthrough */
+ case CAMERA_SENSOR_I2C_TYPE_WORD:
+ data[i++] = (i2c_cmd->reg_data &
+ 0x0000FF00) >> 8;
+ /* fallthrough */
+ case CAMERA_SENSOR_I2C_TYPE_BYTE:
+ data[i++] = i2c_cmd->reg_data &
+ 0x000000FF;
+ break;
+ default:
+ CAM_ERR(CAM_CCI,
+ "invalid data type: %d",
+ i2c_msg->data_type);
+ return -EINVAL;
}
- data[i++] = (i2c_cmd->reg_data &
- 0x0000FF00) >> 8; /* MSB */
- data[i++] = i2c_cmd->reg_data &
- 0x000000FF; /* LSB */
+
if (c_ctrl->cmd ==
MSM_CCI_I2C_WRITE_SEQ)
reg_addr++;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
index 9eca4c7..d9b43a4 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -259,6 +259,7 @@
return -ENOMEM;
o_ctrl->soc_info.pdev = pdev;
+ o_ctrl->pdev = pdev;
o_ctrl->soc_info.dev = &pdev->dev;
o_ctrl->soc_info.dev_name = pdev->name;
diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild
index e72a1f0..1e087a1 100644
--- a/include/uapi/media/Kbuild
+++ b/include/uapi/media/Kbuild
@@ -14,3 +14,4 @@
header-y += msm_sde_rotator.h
header-y += radio-iris.h
header-y += radio-iris-commands.h
+header-y += cam_lrme.h
diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h
index 4a63292..afd109f 100644
--- a/include/uapi/media/cam_isp.h
+++ b/include/uapi/media/cam_isp.h
@@ -84,7 +84,9 @@
#define CAM_ISP_DSP_MODE_ROUND 2
/* ISP Generic Cmd Buffer Blob types */
-#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0
+#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0
+#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1
+#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2
/* Query devices */
/**
@@ -248,7 +250,7 @@
uint32_t framedrop_pattern;
uint32_t framedrop_period;
uint32_t reserved;
-};
+} __attribute__((packed));
/**
* struct cam_isp_resource_hfr_config - Resource HFR configuration
@@ -261,7 +263,7 @@
uint32_t num_ports;
uint32_t reserved;
struct cam_isp_port_hfr_config port_hfr_config[1];
-};
+} __attribute__((packed));
/**
* struct cam_isp_dual_split_params - dual isp spilt parameters
@@ -317,6 +319,60 @@
uint32_t reserved;
struct cam_isp_dual_split_params split_params;
struct cam_isp_dual_stripe_config stripes[1];
-};
+} __attribute__((packed));
+
+/**
+ * struct cam_isp_clock_config - Clock configuration
+ *
+ * @usage_type: Usage type (Single/Dual)
+ * @num_rdi: Number of RDI votes
+ * @left_pix_hz: Pixel Clock for Left ISP
+ * @right_pix_hz: Pixel Clock for Right ISP, valid only if Dual
+ * @rdi_hz: RDI Clock. ISP clock will be max of RDI and
+ * PIX clocks. For a particular context which ISP
+ * HW the RDI is allocated to is not known to UMD.
+ * Hence pass the clock and let KMD decide.
+ */
+struct cam_isp_clock_config {
+ uint32_t usage_type;
+ uint32_t num_rdi;
+ uint64_t left_pix_hz;
+ uint64_t right_pix_hz;
+ uint64_t rdi_hz[1];
+} __attribute__((packed));
+
+/**
+ * struct cam_isp_bw_vote - Bandwidth vote information
+ *
+ * @resource_id: Resource ID
+ * @reserved: Reserved field for alignment
+ * @cam_bw_bps: Bandwidth vote for CAMNOC
+ * @ext_bw_bps: Bandwidth vote for path-to-DDR after CAMNOC
+ */
+
+struct cam_isp_bw_vote {
+ uint32_t resource_id;
+ uint32_t reserved;
+ uint64_t cam_bw_bps;
+ uint64_t ext_bw_bps;
+} __attribute__((packed));
+
+/**
+ * struct cam_isp_bw_config - Bandwidth configuration
+ *
+ * @usage_type: Usage type (Single/Dual)
+ * @num_rdi: Number of RDI votes
+ * @left_pix_vote: Bandwidth vote for left ISP
+ * @right_pix_vote: Bandwidth vote for right ISP
+ * @rdi_vote: RDI bandwidth requirements
+ */
+
+struct cam_isp_bw_config {
+ uint32_t usage_type;
+ uint32_t num_rdi;
+ struct cam_isp_bw_vote left_pix_vote;
+ struct cam_isp_bw_vote right_pix_vote;
+ struct cam_isp_bw_vote rdi_vote[1];
+} __attribute__((packed));
#endif /* __UAPI_CAM_ISP_H__ */
diff --git a/include/uapi/media/cam_lrme.h b/include/uapi/media/cam_lrme.h
new file mode 100644
index 0000000..97d9578
--- /dev/null
+++ b/include/uapi/media/cam_lrme.h
@@ -0,0 +1,65 @@
+#ifndef __UAPI_CAM_LRME_H__
+#define __UAPI_CAM_LRME_H__
+
+#include "cam_defs.h"
+
+/* LRME Resource Types */
+
+enum CAM_LRME_IO_TYPE {
+ CAM_LRME_IO_TYPE_TAR,
+ CAM_LRME_IO_TYPE_REF,
+ CAM_LRME_IO_TYPE_RES,
+ CAM_LRME_IO_TYPE_DS2,
+};
+
+#define CAM_LRME_INPUT_PORT_TYPE_TAR (1 << 0)
+#define CAM_LRME_INPUT_PORT_TYPE_REF (1 << 1)
+
+#define CAM_LRME_OUTPUT_PORT_TYPE_DS2 (1 << 0)
+#define CAM_LRME_OUTPUT_PORT_TYPE_RES (1 << 1)
+
+#define CAM_LRME_DEV_MAX 1
+
+
+struct cam_lrme_hw_version {
+ uint32_t gen;
+ uint32_t rev;
+ uint32_t step;
+};
+
+struct cam_lrme_dev_cap {
+ struct cam_lrme_hw_version clc_hw_version;
+ struct cam_lrme_hw_version bus_rd_hw_version;
+ struct cam_lrme_hw_version bus_wr_hw_version;
+ struct cam_lrme_hw_version top_hw_version;
+ struct cam_lrme_hw_version top_titan_version;
+};
+
+/**
+ * struct cam_lrme_query_cap_cmd - LRME query device capability payload
+ *
+ * @dev_iommu_handle: LRME iommu handles for secure/non secure
+ * modes
+ * @cdm_iommu_handle: Iommu handles for secure/non secure modes
+ * @num_devices: number of hardware devices
+ * @dev_caps: Returned device capability array
+ */
+struct cam_lrme_query_cap_cmd {
+ struct cam_iommu_handle device_iommu;
+ struct cam_iommu_handle cdm_iommu;
+ uint32_t num_devices;
+ struct cam_lrme_dev_cap dev_caps[CAM_LRME_DEV_MAX];
+};
+
+struct cam_lrme_soc_info {
+ uint64_t clock_rate;
+ uint64_t bandwidth;
+ uint64_t reserved[4];
+};
+
+struct cam_lrme_acquire_args {
+ struct cam_lrme_soc_info lrme_soc_info;
+};
+
+#endif /* __UAPI_CAM_LRME_H__ */
+
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 9b7d055..233d84e 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -355,14 +355,14 @@
* @error_type: type of error
* @request_id: request id of frame
* @device_hdl: device handle
- * @reserved: reserved field
+ * @linke_hdl: link_hdl
* @resource_size: size of the resource
*/
struct cam_req_mgr_error_msg {
uint32_t error_type;
uint32_t request_id;
int32_t device_hdl;
- int32_t reserved;
+ int32_t link_hdl;
uint64_t resource_size;
};