msm: camera: sensor: Add support for CSIPHY TPG 1.2
Add KMD driver support for CSIPHY TPG version 1.2. CRs-Fixed: 3065086 Change-Id: I4236a8550ebb2c27f4231f963d283bc0a6f28005 Signed-off-by: Shravan Nevatia <quic_snevatia@quicinc.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "cam_tpg_core.h"
|
||||
#include "camera_main.h"
|
||||
#include "tpg_hw/tpg_hw_v_1_0/tpg_hw_v_1_0_data.h"
|
||||
#include "tpg_hw/tpg_hw_v_1_2/tpg_hw_v_1_2_data.h"
|
||||
#include "tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3_data.h"
|
||||
|
||||
static int cam_tpg_subdev_close(struct v4l2_subdev *sd,
|
||||
@@ -369,6 +370,10 @@ static const struct of_device_id cam_tpg_dt_match[] = {
|
||||
.compatible = "qcom,cam-tpg101",
|
||||
.data = &tpg_v_1_0_hw_info,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,cam-tpg102",
|
||||
.data = &tpg_v_1_2_hw_info,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,cam-tpg103",
|
||||
.data = &tpg_v_1_3_hw_info,
|
||||
|
@@ -379,6 +379,7 @@ int tpg_hw_start(struct tpg_hw *hw)
|
||||
if (hw->hw_info->ops->start)
|
||||
hw->hw_info->ops->start(hw, NULL);
|
||||
break;
|
||||
case TPG_HW_VERSION_1_2:
|
||||
case TPG_HW_VERSION_1_3:
|
||||
if (hw->hw_info->ops->start)
|
||||
hw->hw_info->ops->start(hw, NULL);
|
||||
@@ -405,6 +406,7 @@ int tpg_hw_stop(struct tpg_hw *hw)
|
||||
switch (hw->hw_info->version) {
|
||||
case TPG_HW_VERSION_1_0:
|
||||
case TPG_HW_VERSION_1_1:
|
||||
case TPG_HW_VERSION_1_2:
|
||||
case TPG_HW_VERSION_1_3:
|
||||
if (hw->hw_info->ops->stop)
|
||||
rc = hw->hw_info->ops->stop(hw, NULL);
|
||||
@@ -433,6 +435,7 @@ int tpg_hw_acquire(struct tpg_hw *hw,
|
||||
switch (hw->hw_info->version) {
|
||||
case TPG_HW_VERSION_1_0:
|
||||
case TPG_HW_VERSION_1_1:
|
||||
case TPG_HW_VERSION_1_2:
|
||||
case TPG_HW_VERSION_1_3:
|
||||
// Start Cpas and enable required clocks
|
||||
break;
|
||||
@@ -456,6 +459,7 @@ int tpg_hw_release(struct tpg_hw *hw)
|
||||
switch (hw->hw_info->version) {
|
||||
case TPG_HW_VERSION_1_0:
|
||||
case TPG_HW_VERSION_1_1:
|
||||
case TPG_HW_VERSION_1_2:
|
||||
case TPG_HW_VERSION_1_3:
|
||||
break;
|
||||
default:
|
||||
@@ -480,6 +484,7 @@ static int tpg_hw_configure_init_settings(
|
||||
switch (hw->hw_info->version) {
|
||||
case TPG_HW_VERSION_1_0:
|
||||
case TPG_HW_VERSION_1_1:
|
||||
case TPG_HW_VERSION_1_2:
|
||||
case TPG_HW_VERSION_1_3:
|
||||
rc = tpg_hw_soc_enable(hw, CAM_SVS_VOTE);
|
||||
if (hw->hw_info->ops->init)
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <media/cam_sensor.h>
|
||||
#define TPG_HW_VERSION_1_0 0x10000000
|
||||
#define TPG_HW_VERSION_1_1 0x10000001
|
||||
#define TPG_HW_VERSION_1_2 0x10000002
|
||||
#define TPG_HW_VERSION_1_3 0x10000003
|
||||
|
||||
|
||||
|
@@ -0,0 +1,282 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "tpg_hw_v_1_2.h"
|
||||
|
||||
/* TPG HW IDs */
|
||||
enum cam_tpg_hw_id {
|
||||
CAM_TPG_0 = 13,
|
||||
CAM_TPG_1,
|
||||
CAM_TPG_MAX,
|
||||
};
|
||||
|
||||
static struct cam_tpg_ver_1_2_reg_offset cam_tpg102_reg = {
|
||||
.tpg_hw_version = 0x0,
|
||||
.tpg_hw_status = 0x4,
|
||||
.tpg_module_cfg = 0x60,
|
||||
.tpg_cfg0 = 0x68,
|
||||
.tpg_cfg1 = 0x6C,
|
||||
.tpg_cfg2 = 0x70,
|
||||
.tpg_cfg3 = 0x74,
|
||||
.tpg_spare = 0x1FC,
|
||||
|
||||
/* configurations */
|
||||
.major_version = 1,
|
||||
.minor_version = 0,
|
||||
.version_incr = 2,
|
||||
.tpg_en_shift = 0,
|
||||
.tpg_hbi_shift = 20,
|
||||
.tpg_dt_shift = 11,
|
||||
.tpg_rotate_period_shift = 5,
|
||||
.tpg_split_en_shift = 4,
|
||||
.top_mux_reg_offset = 0x90,
|
||||
.tpg_mux_sel_tpg_0_shift = 0,
|
||||
.tpg_mux_sel_tpg_1_shift = 8,
|
||||
};
|
||||
|
||||
static int configure_global_configs(
|
||||
struct tpg_hw *hw,
|
||||
int num_vcs,
|
||||
struct tpg_global_config_t *configs)
|
||||
{
|
||||
uint32_t val;
|
||||
struct cam_hw_soc_info *soc_info = NULL;
|
||||
struct cam_tpg_ver_1_2_reg_offset *tpg_reg = &cam_tpg102_reg;
|
||||
|
||||
if (!hw) {
|
||||
CAM_ERR(CAM_TPG, "invalid params");
|
||||
return -EINVAL;
|
||||
}
|
||||
soc_info = hw->soc_info;
|
||||
|
||||
if (num_vcs <= 0) {
|
||||
CAM_ERR(CAM_TPG, "Invalid vc count");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Program number of frames */
|
||||
val = 0xFFFFF;
|
||||
cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_cfg3);
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] cfg3=0x%x",
|
||||
hw->hw_idx, val);
|
||||
|
||||
val = cam_io_r_mb(soc_info->reg_map[1].mem_base +
|
||||
tpg_reg->top_mux_reg_offset);
|
||||
|
||||
if (hw->hw_idx == CAM_TPG_0)
|
||||
val |= 1 << tpg_reg->tpg_mux_sel_tpg_0_shift;
|
||||
else if (hw->hw_idx == CAM_TPG_1)
|
||||
val |= 1 << tpg_reg->tpg_mux_sel_tpg_1_shift;
|
||||
|
||||
cam_io_w_mb(val,
|
||||
soc_info->reg_map[1].mem_base + tpg_reg->top_mux_reg_offset);
|
||||
CAM_INFO(CAM_TPG, "TPG[%d] Set CPAS top mux: 0x%x",
|
||||
hw->hw_idx, val);
|
||||
|
||||
val = (1 << tpg_reg->tpg_en_shift);
|
||||
cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_module_cfg);
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] tpg_module_cfg=0x%x", hw->hw_idx, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int configure_dt(
|
||||
struct tpg_hw *hw,
|
||||
uint32_t vc_slot,
|
||||
uint32_t dt_slot,
|
||||
struct tpg_stream_config_t *stream)
|
||||
{
|
||||
uint32_t val;
|
||||
struct cam_hw_soc_info *soc_info = NULL;
|
||||
struct cam_tpg_ver_1_2_reg_offset *tpg_reg = &cam_tpg102_reg;
|
||||
if (!hw) {
|
||||
CAM_ERR(CAM_TPG, "invalid params");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
soc_info = hw->soc_info;
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] slot(%d,%d) <= dt:%d",
|
||||
hw->hw_idx,
|
||||
vc_slot,
|
||||
dt_slot,
|
||||
stream->dt);
|
||||
|
||||
val = (((stream->stream_dimension.width & 0xFFFF) << 16) |
|
||||
(stream->stream_dimension.height & 0xFFFF));
|
||||
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
|
||||
tpg_reg->tpg_cfg0);
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] cfg0=0x%x",
|
||||
hw->hw_idx, val);
|
||||
|
||||
val = stream->dt << tpg_reg->tpg_dt_shift;
|
||||
cam_io_w_mb(val,
|
||||
soc_info->reg_map[0].mem_base +
|
||||
tpg_reg->tpg_cfg2);
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] cfg2=0x%x",
|
||||
hw->hw_idx, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int configure_vc(
|
||||
struct tpg_hw *hw,
|
||||
uint32_t vc_slot,
|
||||
int num_dts,
|
||||
struct tpg_stream_config_t *stream)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
struct cam_hw_soc_info *soc_info = NULL;
|
||||
struct cam_tpg_ver_1_2_reg_offset *tpg_reg = &cam_tpg102_reg;
|
||||
if (!hw) {
|
||||
CAM_ERR(CAM_TPG, "invalid params");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
soc_info = hw->soc_info;
|
||||
if (stream->cb_mode == TPG_COLOR_BAR_MODE_SPLIT)
|
||||
val |= (1 << tpg_reg->tpg_split_en_shift);
|
||||
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] period: %d", hw->hw_idx, stream->rotate_period);
|
||||
val |= ((stream->rotate_period & 0x3F) <<
|
||||
tpg_reg->tpg_rotate_period_shift);
|
||||
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
|
||||
tpg_reg->tpg_cfg2);
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] cfg2=0x%x",
|
||||
hw->hw_idx, val);
|
||||
|
||||
val = stream->hbi << tpg_reg->tpg_hbi_shift | stream->vbi;
|
||||
cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
|
||||
tpg_reg->tpg_cfg1);
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] cfg1=0x%x",
|
||||
hw->hw_idx, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpg_hw_v_1_2_reset(
|
||||
struct tpg_hw *hw, void *data)
|
||||
{
|
||||
struct cam_hw_soc_info *soc_info = NULL;
|
||||
uint32_t val;
|
||||
struct cam_tpg_ver_1_2_reg_offset *tpg_reg = &cam_tpg102_reg;
|
||||
if (!hw) {
|
||||
CAM_ERR(CAM_TPG, "invalid params");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
soc_info = hw->soc_info;
|
||||
|
||||
/* Clear out tpg_module_cfg before reset */
|
||||
cam_io_w_mb(0, soc_info->reg_map[0].mem_base + tpg_reg->tpg_module_cfg);
|
||||
|
||||
/* Read the version */
|
||||
val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
|
||||
tpg_reg->tpg_hw_version);
|
||||
CAM_INFO(CAM_TPG, "TPG[%d] TPG HW version: 0x%x started",
|
||||
hw->hw_idx, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpg_hw_v_1_2_process_cmd(
|
||||
struct tpg_hw *hw,
|
||||
uint32_t cmd,
|
||||
void *arg)
|
||||
{
|
||||
int rc = 0;
|
||||
if (hw == NULL) {
|
||||
CAM_ERR(CAM_TPG, "invalid argument");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CAM_DBG(CAM_TPG, "TPG[%d] Cmd opcode:0x%x", hw->hw_idx, cmd);
|
||||
switch(cmd) {
|
||||
case TPG_CONFIG_VC:
|
||||
{
|
||||
struct vc_config_args *vc_config =
|
||||
(struct vc_config_args *)arg;
|
||||
|
||||
if (vc_config == NULL) {
|
||||
CAM_ERR(CAM_TPG, "invalid argument");
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = configure_vc(hw,
|
||||
vc_config->vc_slot,
|
||||
vc_config->num_dts,
|
||||
vc_config->stream);
|
||||
}
|
||||
break;
|
||||
case TPG_CONFIG_DT:
|
||||
{
|
||||
struct dt_config_args *dt_config =
|
||||
(struct dt_config_args *)arg;
|
||||
|
||||
if (dt_config == NULL) {
|
||||
CAM_ERR(CAM_TPG, "invalid argument");
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = configure_dt(hw,
|
||||
dt_config->vc_slot,
|
||||
dt_config->dt_slot,
|
||||
dt_config->stream);
|
||||
}
|
||||
break;
|
||||
case TPG_CONFIG_CTRL:
|
||||
{
|
||||
struct global_config_args *global_args =
|
||||
(struct global_config_args *)arg;
|
||||
rc = configure_global_configs(hw,
|
||||
global_args->num_vcs,
|
||||
global_args->globalconfig);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CAM_ERR(CAM_TPG, "invalid argument");
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tpg_hw_v_1_2_start(struct tpg_hw *hw, void *data)
|
||||
{
|
||||
CAM_DBG(CAM_TPG, "TPG V1.2 HWL start");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpg_hw_v_1_2_stop(struct tpg_hw *hw, void *data)
|
||||
{
|
||||
CAM_DBG(CAM_TPG, "TPG V1.2 HWL stop");
|
||||
tpg_hw_v_1_2_reset(hw, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpg_hw_v_1_2_dump_status(struct tpg_hw *hw, void *data)
|
||||
{
|
||||
struct cam_hw_soc_info *soc_info = NULL;
|
||||
uint32_t val;
|
||||
struct cam_tpg_ver_1_2_reg_offset *tpg_reg = &cam_tpg102_reg;
|
||||
|
||||
if (!hw) {
|
||||
CAM_ERR(CAM_TPG, "invalid params");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
soc_info = hw->soc_info;
|
||||
CAM_DBG(CAM_TPG, "TPG V1.2 HWL status dump");
|
||||
/* Read the version */
|
||||
val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
|
||||
tpg_reg->tpg_hw_status);
|
||||
CAM_INFO(CAM_TPG, "TPG[%d] TPG HW status: 0x%x started",
|
||||
hw->hw_idx, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpg_hw_v_1_2_init(struct tpg_hw *hw, void *data)
|
||||
{
|
||||
CAM_DBG(CAM_TPG, "TPG V1.2 HWL init");
|
||||
tpg_hw_v_1_2_reset(hw, data);
|
||||
return 0;
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __TPG_HW_V_1_2_H__
|
||||
#define __TPG_HW_V_1_2_H__
|
||||
|
||||
#include "../tpg_hw.h"
|
||||
|
||||
struct cam_tpg_ver_1_2_reg_offset {
|
||||
uint32_t tpg_hw_version;
|
||||
uint32_t tpg_hw_status;
|
||||
uint32_t tpg_module_cfg;
|
||||
uint32_t tpg_cfg0;
|
||||
uint32_t tpg_cfg1;
|
||||
uint32_t tpg_cfg2;
|
||||
uint32_t tpg_cfg3;
|
||||
uint32_t tpg_spare;
|
||||
|
||||
/* configurations */
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
uint32_t version_incr;
|
||||
uint32_t tpg_en_shift;
|
||||
uint32_t tpg_hbi_shift;
|
||||
uint32_t tpg_dt_shift;
|
||||
uint32_t tpg_rotate_period_shift;
|
||||
uint32_t tpg_split_en_shift;
|
||||
uint32_t top_mux_reg_offset;
|
||||
uint32_t tpg_mux_sel_tpg_0_shift;
|
||||
uint32_t tpg_mux_sel_tpg_1_shift;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief initialize the tpg hw instance
|
||||
*
|
||||
* @param hw : tpg hw instance
|
||||
* @param data : argument for initialize
|
||||
*
|
||||
* @return : 0 on success
|
||||
*/
|
||||
int tpg_hw_v_1_2_init(struct tpg_hw *hw, void *data);
|
||||
|
||||
/**
|
||||
* @brief start tpg hw
|
||||
*
|
||||
* @param hw : tpg hw instance
|
||||
* @param data : tpg hw instance data
|
||||
*
|
||||
* @return : 0 on success
|
||||
*/
|
||||
int tpg_hw_v_1_2_start(struct tpg_hw *hw, void *data);
|
||||
|
||||
/**
|
||||
* @brief stop tpg hw
|
||||
*
|
||||
* @param hw : tpg hw instance
|
||||
* @param data : argument for tpg hw stop
|
||||
*
|
||||
* @return : 0 on success
|
||||
*/
|
||||
int tpg_hw_v_1_2_stop(struct tpg_hw *hw, void *data);
|
||||
|
||||
/**
|
||||
* @brief process a command send from hw layer
|
||||
*
|
||||
* @param hw : tpg hw instance
|
||||
* @param cmd : command to process
|
||||
* @param arg : argument corresponding to command
|
||||
*
|
||||
* @return : 0 on success
|
||||
*/
|
||||
int tpg_hw_v_1_2_process_cmd(struct tpg_hw *hw,
|
||||
uint32_t cmd, void *arg);
|
||||
|
||||
/**
|
||||
* @brief dump hw status registers
|
||||
*
|
||||
* @param hw : tpg hw instance
|
||||
* @param data : argument for status dump
|
||||
*
|
||||
* @return : 0 on sucdess
|
||||
*/
|
||||
int tpg_hw_v_1_2_dump_status(struct tpg_hw *hw, void *data);
|
||||
|
||||
#endif
|
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __TPG_HW_V_1_2_DATA_H__
|
||||
#define __TPG_HW_V_1_2_DATA_H__
|
||||
|
||||
#include "../tpg_hw.h"
|
||||
#include "tpg_hw_v_1_2.h"
|
||||
|
||||
struct tpg_hw_ops tpg_hw_v_1_2_ops = {
|
||||
.start = tpg_hw_v_1_2_start,
|
||||
.stop = tpg_hw_v_1_2_stop,
|
||||
.init = tpg_hw_v_1_2_init,
|
||||
.process_cmd = tpg_hw_v_1_2_process_cmd,
|
||||
.dump_status = tpg_hw_v_1_2_dump_status,
|
||||
};
|
||||
|
||||
struct tpg_hw_info tpg_v_1_2_hw_info = {
|
||||
.version = TPG_HW_VERSION_1_2,
|
||||
.max_vc_channels = 1,
|
||||
.max_dt_channels_per_vc = 1,
|
||||
.ops = &tpg_hw_v_1_2_ops,
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user