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

Commit c17646d0 authored by Lakshmi Narayana Kalavala's avatar Lakshmi Narayana Kalavala Committed by Gerrit - the friendly Code Review server
Browse files

msm: cpp: Changes to adapt cpp driver to soc layer



Adapt CPP driver to SOC layer by replacing the msm specific
routines with SOC API which eases the portability of cpp driver
on to non-msm platforms.

Change-Id: I8cd6bdcaa9d310b770f2dfe66047c64316a309de
Signed-off-by: default avatarLakshmi Narayana Kalavala <lkalaval@codeaurora.org>
parent a1e33505
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2,4 +2,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/isp/
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
obj-$(CONFIG_MSM_CPP) += msm_cpp.o
obj-$(CONFIG_MSM_CPP) += msm_cpp_soc.o msm_cpp.o
+127 −548

File changed.

Preview size limit exceeded, changes collapsed.

+15 −10
Original line number Diff line number Diff line
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2016, 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
@@ -20,6 +20,8 @@
#include <linux/interrupt.h>
#include <media/v4l2-subdev.h>
#include "msm_sd.h"
#include "cam_soc_api.h"
#include "cam_hw_ops.h"

/* hw version info:
  31:28  Major version
@@ -200,21 +202,16 @@ struct cpp_device {
	struct platform_device *pdev;
	struct msm_sd_subdev msm_sd;
	struct v4l2_subdev subdev;
	struct resource *mem;
	struct resource *irq;
	struct resource *io;
	struct resource	*vbif_mem;
	struct resource *vbif_io;
	struct resource	*cpp_hw_mem;
	struct resource	*camss_cpp;
	void __iomem *vbif_base;
	void __iomem *base;
	void __iomem *cpp_hw_base;
	void __iomem *camss_cpp_base;
	struct clk **cpp_clk;
	struct regulator *fs_cpp;
	struct regulator *fs_camss;
	struct regulator *fs_mmagic_camss;
	struct msm_cam_clk_info *clk_info;
	size_t num_clks;
	struct regulator **cpp_vdd;
	int num_reg;
	struct mutex mutex;
	enum cpp_state state;
	enum cpp_iommu_state iommu_state;
@@ -264,4 +261,12 @@ struct cpp_device {
	uint32_t bus_master_flag;
	struct msm_cpp_payload_params payload_params;
};

int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
int msm_update_freq_tbl(struct cpp_device *cpp_dev);
int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name);
long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx);
void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev);
int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev);

#endif /* __MSM_CPP_H__ */
+249 −0
Original line number Diff line number Diff line
/* Copyright (c) 2016, 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.
 */

#define pr_fmt(fmt) "MSM-CPP-SOC %s:%d " fmt, __func__, __LINE__

#include <linux/clk/msm-clk.h>
#include <linux/clk/msm-clk-provider.h>
#include <linux/delay.h>
#include <media/msmb_pproc.h>
#include "msm_cpp.h"


#define CPP_DT_READ_U32_ERR(_dev, _key, _str, _ret, _out) { \
		_key = _str; \
		_ret = of_property_read_u32(_dev, _key, &_out); \
		if (_ret) \
			break; \
	}

#define CPP_DT_READ_U32(_dev, _str, _out) { \
		of_property_read_u32(_dev, _str, &_out); \
	}

void msm_cpp_fetch_dt_params(struct cpp_device *cpp_dev)
{
	int rc = 0;
	struct device_node *of_node = cpp_dev->pdev->dev.of_node;

	if (!of_node) {
		pr_err("%s: invalid params\n", __func__);
		return;
	}

	of_property_read_u32(of_node, "cell-index", &cpp_dev->pdev->id);

	rc = of_property_read_u32(of_node, "qcom,min-clock-rate",
			&cpp_dev->min_clk_rate);
	if (rc < 0) {
		pr_debug("min-clk-rate not defined, setting it to 0\n");
		cpp_dev->min_clk_rate = 0;
	}

	rc = of_property_read_u32(of_node, "qcom,bus-master",
			&cpp_dev->bus_master_flag);
	if (rc)
		cpp_dev->bus_master_flag = 0;
}

int msm_cpp_get_clock_index(struct cpp_device *cpp_dev, const char *clk_name)
{
	uint32_t i = 0;

	for (i = 0; i < cpp_dev->num_clks; i++) {
		if (!strcmp(clk_name, cpp_dev->clk_info[i].clk_name))
			return i;
	}
	return -EINVAL;
}

static int cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info,
	uint32_t min_clk_rate)
{
	uint32_t i;
	uint32_t idx = 0;
	signed long freq_tbl_entry = 0;

	if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) ||
		(clk->ops->list_rate == NULL)) {
		pr_err("Bad parameter\n");
		return -EINVAL;
	}

	for (i = 0; i < MAX_FREQ_TBL; i++) {
		freq_tbl_entry = clk->ops->list_rate(clk, i);
		pr_debug("entry=%ld\n", freq_tbl_entry);
		if (freq_tbl_entry >= 0) {
			if (freq_tbl_entry >= min_clk_rate) {
				hw_info->freq_tbl[idx++] = freq_tbl_entry;
				pr_debug("tbl[%d]=%ld\n", idx-1,
					freq_tbl_entry);
			}
		} else {
			pr_debug("freq table returned invalid entry/end %ld\n",
				freq_tbl_entry);
			break;
		}
	}

	pr_debug("%s: idx %d", __func__, idx);
	hw_info->freq_tbl_count = idx;

	return 0;
}

int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev)
{
	uint32_t msm_micro_iface_idx;
	int rc;

	msm_micro_iface_idx = msm_cpp_get_clock_index(cpp_dev,
		"micro_iface_clk");
	if (msm_micro_iface_idx < 0)  {
		pr_err("Fail to get clock index\n");
		return -EINVAL;
	}

	rc = clk_reset(cpp_dev->cpp_clk[msm_micro_iface_idx],
		CLK_RESET_ASSERT);
	if (rc) {
		pr_err("%s:micro_iface_clk assert failed\n",
		__func__);
		return -EINVAL;
	}

	/*
	 * Below usleep values are chosen based on experiments
	 * and this was the smallest number which works. This
	 * sleep is needed to leave enough time for Microcontroller
	 * to resets all its registers.
	 */
	usleep_range(1000, 1200);

	rc = clk_reset(cpp_dev->cpp_clk[msm_micro_iface_idx],
		CLK_RESET_DEASSERT);
	if (rc) {
		pr_err("%s:micro_iface_clk de-assert failed\n", __func__);
		return -EINVAL;
	}

	/*
	 * Below usleep values are chosen based on experiments
	 * and this was the smallest number which works. This
	 * sleep is needed to leave enough time for Microcontroller
	 * to resets all its registers.
	 */
	usleep_range(1000, 1200);
	return 0;
}

int msm_update_freq_tbl(struct cpp_device *cpp_dev)
{
	uint32_t msm_cpp_core_clk_idx;
	int rc = 0;

	msm_cpp_core_clk_idx = msm_cpp_get_clock_index(cpp_dev, "cpp_core_clk");
	if (msm_cpp_core_clk_idx < 0)  {
		pr_err("%s: fail to get clock index\n", __func__);
		rc = msm_cpp_core_clk_idx;
		return rc;
	}
	rc = cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[msm_cpp_core_clk_idx],
		&cpp_dev->hw_info, cpp_dev->min_clk_rate);
	if (rc < 0)  {
		pr_err("%s: fail to get frequency table\n", __func__);
		return rc;
	}

	return rc;
}

long msm_cpp_set_core_clk(struct cpp_device *cpp_dev, long rate, int idx)
{
	long rc = 0;

	rc = msm_camera_clk_set_rate(&cpp_dev->pdev->dev,
		cpp_dev->cpp_clk[idx], rate);
	if (rc < 0) {
		pr_err("%s: fail to get frequency table\n", __func__);
		return rc;
	}

	return rc;
}

int msm_cpp_read_payload_params_from_dt(struct cpp_device *cpp_dev)
{
	struct platform_device *pdev = cpp_dev->pdev;
	struct device_node *fw_info_node = NULL, *dev_node = NULL;
	char *key = "qcom,cpp-fw-payload-info";
	struct msm_cpp_payload_params *payload_params;
	int ret = 0;

	if (!pdev || !pdev->dev.of_node) {
		pr_err("%s: Invalid platform device/node\n", __func__);
		ret = -ENODEV;
		goto no_cpp_node;
	}

	dev_node = pdev->dev.of_node;
	fw_info_node = of_find_node_by_name(dev_node, key);
	if (!fw_info_node) {
		ret = -ENODEV;
		goto no_binding;
	}
	payload_params = &cpp_dev->payload_params;
	memset(payload_params, 0x0, sizeof(struct msm_cpp_payload_params));

	do {
		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-base", ret,
			payload_params->stripe_base);
		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-base", ret,
			payload_params->plane_base);
		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,stripe-size", ret,
			payload_params->stripe_size);
		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,plane-size", ret,
			payload_params->plane_size);
		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,fe-ptr-off", ret,
			payload_params->rd_pntr_off);
		CPP_DT_READ_U32_ERR(fw_info_node, key, "qcom,we-ptr-off", ret,
			payload_params->wr_0_pntr_off);

		CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-ptr-off",
			payload_params->rd_ref_pntr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-ptr-off",
			payload_params->wr_ref_pntr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,we-meta-ptr-off",
			payload_params->wr_0_meta_data_wr_pntr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,fe-mmu-pf-ptr-off",
			payload_params->fe_mmu_pf_ptr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,ref-fe-mmu-pf-ptr-off",
			payload_params->ref_fe_mmu_pf_ptr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,we-mmu-pf-ptr-off",
			payload_params->we_mmu_pf_ptr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,dup-we-mmu-pf-ptr-off",
			payload_params->dup_we_mmu_pf_ptr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,ref-we-mmu-pf-ptr-off",
			payload_params->ref_we_mmu_pf_ptr_off);
		CPP_DT_READ_U32(fw_info_node, "qcom,set-group-buffer-len",
			payload_params->set_group_buffer_len);
		CPP_DT_READ_U32(fw_info_node, "qcom,dup-frame-indicator-off",
			payload_params->dup_frame_indicator_off);
	} while (0);

no_binding:
	if (ret)
		pr_err("%s: Error reading binding %s, ret %d\n",
			__func__, key, ret);
no_cpp_node:
	return ret;
}