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:
Shravan Nevatia
2021-10-27 15:41:34 +05:30
parent b06c540564
commit 5930b6dffa
7 changed files with 411 additions and 0 deletions

View File

@@ -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,

View File

@@ -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)

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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