Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc79a57e authored by Junzhe Zou's avatar Junzhe Zou
Browse files

msm: camera: lrme: Add lrme driver implementation



Add camera Low Resolution Motion Estimation driver implementation
to enable LRME hw functionality. LRME HW block analyzes TAR and REF
frames to get motion estimation.

Change-Id: I2e5ac866430c087a956fa72f11e74bda4adc1bfa
Signed-off-by: default avatarJunzhe Zou <jnzhezou@codeaurora.org>
parent 11c30c7a
Loading
Loading
Loading
Loading
+149 −0
Original line number Diff line number Diff line
* 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";
	};
+1 −0
Original line number Diff line number Diff line
@@ -10,3 +10,4 @@ obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/
+14 −0
Original line number Diff line number Diff line
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
+241 −0
Original line number Diff line number Diff line
/* 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;
}
+41 −0
Original line number Diff line number Diff line
/* 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_ */
Loading