Jelajahi Sumber

msm: camera: sensor: Add tpg driver support

Add new tpg subdev driver. This change exposes the tpg hw as a new
subdev similar to that of a sensor driver.

CRs-Fixed: 2973850
Change-Id: I6fdb4457d8cc829546896f26bdde8765a4258e7c
Signed-off-by: Tony Lijo Jose <[email protected]>
Tony Lijo Jose 4 tahun lalu
induk
melakukan
caa6b2a1a4

+ 5 - 0
Kbuild

@@ -191,6 +191,11 @@ camera-$(CONFIG_SPECTRA_SENSOR) += \
 	drivers/cam_sensor_module/cam_cci/cam_cci_dev.o \
 	drivers/cam_sensor_module/cam_cci/cam_cci_core.o \
 	drivers/cam_sensor_module/cam_cci/cam_cci_soc.o \
+	drivers/cam_sensor_module/cam_tpg/cam_tpg_dev.o \
+	drivers/cam_sensor_module/cam_tpg/cam_tpg_core.o \
+	drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.o \
+	drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_0/tpg_hw_v_1_0.o \
+	drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3.o \
 	drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.o \
 	drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.o \
 	drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.o \

+ 2 - 0
drivers/cam_req_mgr/cam_req_mgr_interface.h

@@ -186,6 +186,7 @@ enum cam_req_mgr_device_error {
  * @EXTERNAL_1  : third party device
  * @EXTERNAL_2  : third party device
  * @EXTERNAL_3  : third party device
+ * @TPG         : Test Pattern Generator
  * @MAX         : invalid device id
  */
 enum cam_req_mgr_device_id {
@@ -198,6 +199,7 @@ enum cam_req_mgr_device_id {
 	CAM_REQ_MGR_DEVICE_EXTERNAL_1,
 	CAM_REQ_MGR_DEVICE_EXTERNAL_2,
 	CAM_REQ_MGR_DEVICE_EXTERNAL_3,
+	CAM_REQ_MGR_DEVICE_TPG,
 	CAM_REQ_MGR_DEVICE_ID_MAX,
 };
 

+ 2 - 1
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_SENSOR_CMN_HEADER_
@@ -27,6 +27,7 @@
 #define CAM_FLASH_NAME     "cam-flash"
 #define CAM_EEPROM_NAME    "cam-eeprom"
 #define CAM_OIS_NAME       "cam-ois"
+#define CAM_TPG_NAME       "cam-tpg"
 
 #define MAX_SYSTEM_PIPELINE_DELAY 2
 

+ 748 - 0
drivers/cam_sensor_module/cam_tpg/cam_tpg_core.c

@@ -0,0 +1,748 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#include "cam_tpg_core.h"
+#include "cam_packet_util.h"
+#include <cam_mem_mgr.h>
+#include "tpg_hw/tpg_hw.h"
+
+int cam_tpg_shutdown(struct cam_tpg_device *tpg_dev)
+{
+	if (tpg_dev != NULL) {
+		CAM_INFO(CAM_TPG, "TPG[%d] shutdown cleanup.",
+				tpg_dev->soc_info.index);
+		tpg_hw_reset(&tpg_dev->tpg_hw);
+		tpg_dev->state = CAM_TPG_STATE_INIT;
+	}
+	return 0;
+}
+
+int cam_tpg_publish_dev_info(
+	struct cam_req_mgr_device_info *info)
+{
+	int rc = 0;
+	struct cam_tpg_device *tpg_dev = NULL;
+
+	if (!info)
+		return -EINVAL;
+
+	tpg_dev = (struct cam_tpg_device *)
+		cam_get_device_priv(info->dev_hdl);
+
+	if (!tpg_dev) {
+		CAM_ERR(CAM_TPG, "Device data is NULL");
+		return -EINVAL;
+	}
+
+	info->dev_id = CAM_REQ_MGR_DEVICE_TPG;
+	strlcpy(info->name, CAM_TPG_NAME, sizeof(info->name));
+	/* Hard code for now */
+	info->p_delay = 2;
+	info->trigger = CAM_TRIGGER_POINT_SOF;
+
+	return rc;
+}
+
+int cam_tpg_setup_link(
+	struct cam_req_mgr_core_dev_link_setup *link)
+{
+	struct cam_tpg_device *tpg_dev = NULL;
+
+	if (!link)
+		return -EINVAL;
+
+	tpg_dev = (struct cam_tpg_device *)
+		cam_get_device_priv(link->dev_hdl);
+	if (!tpg_dev) {
+		CAM_ERR(CAM_TPG, "Device data is NULL");
+		return -EINVAL;
+	}
+
+	mutex_lock(&tpg_dev->mutex);
+	if (link->link_enable) {
+		tpg_dev->crm_intf.link_hdl = link->link_hdl;
+		tpg_dev->crm_intf.crm_cb = link->crm_cb;
+		CAM_DBG(CAM_TPG, "TPG[%d] CRM enable link done", tpg_dev->soc_info.index);
+	} else {
+		tpg_dev->crm_intf.link_hdl = -1;
+		tpg_dev->crm_intf.crm_cb = NULL;
+		CAM_DBG(CAM_TPG, "TPG[%d] CRM disable link done", tpg_dev->soc_info.index);
+	}
+	mutex_unlock(&tpg_dev->mutex);
+	return 0;
+}
+
+static int cam_tpg_notify_frame_skip(
+	struct cam_req_mgr_apply_request *apply)
+{
+	CAM_DBG(CAM_TPG, "Got Skip frame from crm");
+	return 0;
+}
+
+static int cam_tpg_apply_req(
+	struct cam_req_mgr_apply_request *apply)
+{
+	if (!apply) {
+		CAM_ERR(CAM_TPG, "invalid parameters");
+		return -EINVAL;
+	}
+	CAM_DBG(CAM_TPG, "Got Apply request from crm %lld", apply->request_id);
+	return 0;
+}
+
+static int cam_tpg_flush_req(
+	struct cam_req_mgr_flush_request *flush)
+{
+	CAM_DBG(CAM_TPG, "Got Flush request from crm");
+	return 0;
+}
+
+static int cam_tpg_process_crm_evt(
+	struct cam_req_mgr_link_evt_data *event)
+{
+
+	struct cam_tpg_device *tpg_dev = NULL;
+	if (!event) {
+		CAM_ERR(CAM_TPG, "Invalid argument");
+		return -EINVAL;
+	}
+
+	tpg_dev = cam_get_device_priv(event->dev_hdl);
+	if (!tpg_dev) {
+		CAM_ERR(CAM_TPG, "Invalid dev_hdl");
+		return -EINVAL;
+	}
+
+	switch(event->evt_type) {
+	case CAM_REQ_MGR_LINK_EVT_SOF_FREEZE:
+		tpg_hw_dump_status(&tpg_dev->tpg_hw);
+		break;
+	default:
+		CAM_DBG(CAM_TPG, "Got crm event notification: %d", event->evt_type);
+		break;
+	}
+	return 0;
+}
+
+static int cam_tpg_dump_req(
+	struct cam_req_mgr_dump_info *dump_info)
+{
+	CAM_DBG(CAM_TPG, "Got dump request from CRM");
+	return 0;
+}
+
+int tpg_crm_intf_init(
+	struct cam_tpg_device *tpg_dev)
+{
+	if (tpg_dev == NULL)
+		return -EINVAL;
+
+	tpg_dev->crm_intf.device_hdl = -1;
+	tpg_dev->crm_intf.link_hdl = -1;
+	tpg_dev->crm_intf.ops.get_dev_info = cam_tpg_publish_dev_info;
+	tpg_dev->crm_intf.ops.link_setup = cam_tpg_setup_link;
+	tpg_dev->crm_intf.ops.apply_req = cam_tpg_apply_req;
+	tpg_dev->crm_intf.ops.notify_frame_skip =
+		cam_tpg_notify_frame_skip;
+	tpg_dev->crm_intf.ops.flush_req = cam_tpg_flush_req;
+	tpg_dev->crm_intf.ops.process_evt = cam_tpg_process_crm_evt;
+	tpg_dev->crm_intf.ops.dump_req = cam_tpg_dump_req;
+
+	return 0;
+}
+
+static int __cam_tpg_handle_query_cap(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_tpg_query_cap *query)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+
+	if (!tpg_dev || !query) {
+		CAM_ERR(CAM_TPG, "invalid argument");
+		return -EINVAL;
+	}
+
+	soc_info = &tpg_dev->soc_info;
+	CAM_DBG(CAM_TPG, "Handling tpg query capability for %d slot: %d phy:%d",
+			soc_info->index, tpg_dev->slot_id, tpg_dev->phy_id);
+	query->slot_info = soc_info->index;
+	query->csiphy_slot_id = tpg_dev->phy_id;
+	query->version = 0x0;
+	if (tpg_dev->tpg_hw.hw_info) {
+		query->version   = tpg_dev->tpg_hw.hw_info->version;
+	} else {
+		CAM_ERR(CAM_TPG, "Invalid hw info");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __cam_tpg_handle_acquire_dev(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_tpg_acquire_dev *acquire)
+{
+	int rc = 0;
+	struct cam_create_dev_hdl crm_intf_params;
+
+	if (!tpg_dev || !acquire) {
+		CAM_ERR(CAM_TPG, "invalid input ");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (tpg_dev->state != CAM_TPG_STATE_INIT) {
+		CAM_ERR(CAM_TPG, "TPG[%d] not in right state[%d] to acquire",
+				tpg_dev->soc_info.index, tpg_dev->state);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	crm_intf_params.session_hdl = acquire->session_handle;
+	crm_intf_params.ops = &tpg_dev->crm_intf.ops;
+	crm_intf_params.v4l2_sub_dev_flag = 0;
+	crm_intf_params.media_entity_flag = 0;
+	crm_intf_params.priv = tpg_dev;
+	crm_intf_params.dev_id = CAM_TPG;
+
+	acquire->device_handle =
+		cam_create_device_hdl(&crm_intf_params);
+	tpg_dev->crm_intf.device_hdl = acquire->device_handle;
+	tpg_dev->crm_intf.session_hdl = acquire->session_handle;
+	rc = tpg_hw_acquire(&tpg_dev->tpg_hw, (struct tpg_hw_acquire_args *)NULL);
+	if (rc) {
+		CAM_ERR(CAM_TPG, "TPG[%d] hw acquire failed", tpg_dev->soc_info.index);
+		cam_destroy_device_hdl(tpg_dev->crm_intf.device_hdl);
+		tpg_dev->crm_intf.device_hdl  = -1;
+		tpg_dev->crm_intf.session_hdl = -1;
+	} else {
+		tpg_dev->state = CAM_TPG_STATE_ACQUIRE;
+		CAM_INFO(CAM_TPG, "TPG[%d] Acquire Device done", tpg_dev->soc_info.index);
+	}
+exit:
+	return rc;
+}
+
+static int __cam_tpg_handle_release_dev(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_release_dev_cmd *release)
+{
+	int rc = 0;
+
+	if (!release || !tpg_dev) {
+		CAM_ERR(CAM_TPG, "Invalid params");
+		return -EINVAL;
+	}
+
+	if (release->dev_handle <= 0) {
+		CAM_ERR(CAM_TPG, "Invalid device handle for context");
+		return -EINVAL;
+	}
+
+	if (release->session_handle <= 0) {
+		CAM_ERR(CAM_TPG, "Invalid session handle for context");
+		return -EINVAL;
+	}
+	if (tpg_dev->state == CAM_TPG_STATE_INIT) {
+		CAM_WARN(CAM_TPG, "TPG[%d] not in right state[%d] to release",
+				tpg_dev->soc_info.index, tpg_dev->state);
+		return 0;
+	}
+
+	if (tpg_dev->state == CAM_TPG_STATE_START) {
+		CAM_DBG(CAM_TPG, "TPG[%d] release from start state",
+						tpg_dev->soc_info.index);
+		rc = tpg_hw_stop(&tpg_dev->tpg_hw);
+		if (rc < 0) {
+			CAM_ERR(CAM_TPG, "TPG[%d] unable to stop tpg",
+						tpg_dev->soc_info.index);
+			return rc;
+		}
+	}
+	rc = tpg_hw_release(&tpg_dev->tpg_hw);
+	if (rc) {
+		CAM_ERR(CAM_TPG, "TPG[%d] hw release failed",
+						tpg_dev->soc_info.index);
+	} else {
+		cam_destroy_device_hdl(tpg_dev->crm_intf.device_hdl);
+		tpg_dev->crm_intf.device_hdl  = -1;
+		tpg_dev->crm_intf.session_hdl = -1;
+		CAM_INFO(CAM_TPG, "TPG[%d] Release Done.", tpg_dev->soc_info.index);
+		tpg_dev->state = CAM_TPG_STATE_INIT;
+	}
+
+	return rc;
+}
+
+static int __cam_tpg_handle_start_dev(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_start_stop_dev_cmd *start)
+{
+	int rc = 0;
+	if (!start || !tpg_dev)
+		return -EINVAL;
+
+	if (start->dev_handle <= 0) {
+		CAM_ERR(CAM_TPG, "Invalid device handle for context");
+		return -EINVAL;
+	}
+
+	if (start->session_handle <= 0) {
+		CAM_ERR(CAM_TPG, "Invalid session handle for context");
+		return -EINVAL;
+	}
+	if (tpg_dev->state != CAM_TPG_STATE_ACQUIRE) {
+		CAM_ERR(CAM_TPG, "TPG[%d] not in right state[%d] to start",
+				tpg_dev->soc_info.index, tpg_dev->state);
+		return -EINVAL;
+	}
+	rc = tpg_hw_start(&tpg_dev->tpg_hw);
+	if (rc) {
+		CAM_ERR(CAM_TPG, "TPG[%d] START_DEV failed", tpg_dev->soc_info.index);
+	} else {
+		tpg_dev->state = CAM_TPG_STATE_START;
+		CAM_INFO(CAM_TPG, "TPG[%d] START_DEV done.", tpg_dev->soc_info.index);
+	}
+
+	return rc;
+}
+
+static int __cam_tpg_handle_stop_dev(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_start_stop_dev_cmd *stop)
+{
+	int rc = 0;
+	if (!stop || !tpg_dev)
+		return -EINVAL;
+
+	if (stop->dev_handle <= 0) {
+		CAM_ERR(CAM_TPG, "Invalid device handle for context");
+		return -EINVAL;
+	}
+
+	if (stop->session_handle <= 0) {
+		CAM_ERR(CAM_TPG, "Invalid session handle for context");
+		return -EINVAL;
+	}
+	if (tpg_dev->state != CAM_TPG_STATE_START) {
+		CAM_WARN(CAM_TPG, "TPG[%d] not in right state[%d] to stop",
+				tpg_dev->soc_info.index, tpg_dev->state);
+	}
+	rc = tpg_hw_stop(&tpg_dev->tpg_hw);
+	if (rc) {
+		CAM_ERR(CAM_TPG, "TPG[%d] STOP_DEV failed", tpg_dev->soc_info.index);
+	} else {
+		/* Free all allocated streams during stop dev */
+		tpg_hw_free_streams(&tpg_dev->tpg_hw);
+		tpg_dev->state = CAM_TPG_STATE_ACQUIRE;
+		CAM_INFO(CAM_TPG, "TPG[%d] STOP_DEV done.", tpg_dev->soc_info.index);
+	}
+
+	return rc;
+}
+
+static int cam_tpg_validate_cmd_descriptor(
+	struct cam_cmd_buf_desc *cmd_desc,
+	uint32_t *cmd_type, uintptr_t *cmd_addr)
+{
+	int rc = 0;
+	uintptr_t generic_ptr;
+	size_t len_of_buff = 0;
+	uint32_t                *cmd_buf = NULL;
+	struct tpg_command_header_t *cmd_header = NULL;
+
+	if (!cmd_desc || !cmd_type || !cmd_addr)
+		return -EINVAL;
+
+	rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle,
+		&generic_ptr, &len_of_buff);
+	if (rc < 0) {
+		CAM_ERR(CAM_TPG,
+			"Failed to get cmd buf Mem address : %d", rc);
+		return rc;
+	}
+
+	cmd_buf = (uint32_t *)generic_ptr;
+	cmd_buf += cmd_desc->offset / 4;
+	cmd_header = (struct tpg_command_header_t *)cmd_buf;
+
+	if (len_of_buff < sizeof(struct tpg_command_header_t)) {
+		CAM_ERR(CAM_TPG, "Got invalid command descriptor of invalid cmd buffer size");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	switch (cmd_header->cmd_type) {
+	case TPG_CMD_TYPE_GLOBAL_CONFIG: {
+		if (cmd_header->size != sizeof(struct tpg_global_config_t)) {
+			CAM_ERR(CAM_TPG, "Got invalid global config command recv: %d exp: %d",
+					cmd_header->size,
+					sizeof(struct tpg_global_config_t));
+			rc = -EINVAL;
+			goto end;
+		}
+		CAM_INFO(CAM_TPG, "Got global config cmd");
+		*cmd_type = TPG_CMD_TYPE_GLOBAL_CONFIG;
+		break;
+	}
+	case TPG_CMD_TYPE_STREAM_CONFIG: {
+		if (cmd_header->size != sizeof(struct tpg_stream_config_t)) {
+			CAM_ERR(CAM_TPG, "Got invalid stream config command recv: %d exp: %d",
+					cmd_header->size,
+					sizeof(struct tpg_stream_config_t));
+
+			rc = -EINVAL;
+			goto end;
+		}
+		CAM_INFO(CAM_TPG, "Got stream config cmd");
+		*cmd_type = TPG_CMD_TYPE_STREAM_CONFIG;
+		break;
+	}
+	case TPG_CMD_TYPE_ILLUMINATION_CONFIG: {
+		if (cmd_header->size != sizeof(struct tpg_illumination_control)) {
+			CAM_ERR(CAM_TPG, "Got invalid illumination config command");
+			rc = -EINVAL;
+			goto end;
+		}
+		*cmd_type = TPG_CMD_TYPE_ILLUMINATION_CONFIG;
+		break;
+	}
+	default:
+		rc = -EINVAL;
+		CAM_ERR(CAM_TPG, "invalid config command");
+		goto end;
+	}
+	if ((ssize_t)cmd_desc->offset > (len_of_buff - cmd_header->size)) {
+		CAM_ERR(CAM_TPG, "cmd header offset mismatch");
+		rc = -EINVAL;
+	}
+
+	*cmd_addr = (uintptr_t)cmd_header;
+end:
+	return rc;
+}
+
+static int cam_tpg_cmd_buf_parse(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_packet *packet)
+{
+	int rc = 0, i = 0;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+
+	if (!tpg_dev || !packet)
+		return -EINVAL;
+
+	for (i = 0; i < packet->num_cmd_buf; i++) {
+		uint32_t cmd_type = TPG_CMD_TYPE_INVALID;
+		uintptr_t cmd_addr;
+
+		cmd_desc = (struct cam_cmd_buf_desc *)
+			((uint32_t *)&packet->payload +
+			(packet->cmd_buf_offset / 4) +
+			(i * (sizeof(struct cam_cmd_buf_desc)/4)));
+
+		rc = cam_tpg_validate_cmd_descriptor(cmd_desc,
+				&cmd_type, &cmd_addr);
+		if (rc < 0)
+			goto end;
+
+		switch (cmd_type) {
+		case TPG_CMD_TYPE_GLOBAL_CONFIG:
+			rc = tpg_hw_copy_global_config(&tpg_dev->tpg_hw,
+				(struct tpg_global_config_t *)cmd_addr);
+			break;
+		case TPG_CMD_TYPE_STREAM_CONFIG: {
+			rc = tpg_hw_add_stream(&tpg_dev->tpg_hw,
+				(struct tpg_stream_config_t *)cmd_addr);
+			break;
+		}
+		case TPG_CMD_TYPE_ILLUMINATION_CONFIG:
+			CAM_ERR(CAM_TPG, "TPG[%d] ILLUMINATION CONFIG not supported now ",
+								tpg_dev->soc_info.index);
+			break;
+		default:
+			CAM_ERR(CAM_TPG, "TPG[%d] invalid command %d",
+				tpg_dev->soc_info.index,
+				cmd_type);
+			rc = -EINVAL;
+			break;
+		}
+	}
+end:
+	return rc;
+}
+
+static int cam_tpg_packet_parse(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_config_dev_cmd *config)
+{
+	int rc = 0;
+	uintptr_t generic_ptr;
+	size_t len_of_buff = 0, remain_len = 0;
+	struct cam_packet *csl_packet = NULL;
+
+	rc = cam_mem_get_cpu_buf(config->packet_handle,
+		&generic_ptr, &len_of_buff);
+	if (rc < 0) {
+		CAM_ERR(CAM_TPG, "Failed in getting the packet: %d", rc);
+		return rc;
+	}
+
+	if ((sizeof(struct cam_packet) > len_of_buff) ||
+		((size_t)config->offset >= len_of_buff -
+		sizeof(struct cam_packet))) {
+		CAM_ERR(CAM_TPG,
+			"Inval cam_packet struct size: %zu, len_of_buff: %zu",
+			 sizeof(struct cam_packet), len_of_buff);
+		rc = -EINVAL;
+		goto end;
+	}
+	remain_len = len_of_buff;
+	remain_len -= (size_t)config->offset;
+	csl_packet = (struct cam_packet *)(generic_ptr +
+		(uint32_t)config->offset);
+
+	if (cam_packet_util_validate_packet(csl_packet,
+		remain_len)) {
+		CAM_ERR(CAM_TPG, "Invalid packet params");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_TPG, "TPG[%d] "
+			"CONFIG_DEV, Packet opcode = %d num_cmds: %d num_ios: %d num_patch: %d",
+			tpg_dev->soc_info.index,
+			(csl_packet->header.op_code & 0xFF),
+			csl_packet->num_cmd_buf,
+			csl_packet->num_io_configs,
+			csl_packet->num_patches);
+	switch ((csl_packet->header.op_code & 0xFF)) {
+	case CAM_TPG_PACKET_OPCODE_INITIAL_CONFIG: {
+		if (csl_packet->num_cmd_buf <= 0) {
+			CAM_ERR(CAM_TPG, "Expecting atleast one command in Init packet");
+			rc = -EINVAL;
+			goto end;
+		}
+		rc = cam_tpg_cmd_buf_parse(tpg_dev, csl_packet);
+		if (rc < 0) {
+			CAM_ERR(CAM_TPG, "CMD buffer parse failed");
+			goto end;
+		}
+		tpg_hw_config(&tpg_dev->tpg_hw, TPG_HW_CMD_INIT_CONFIG, NULL);
+		break;
+	}
+	case CAM_TPG_PACKET_OPCODE_NOP: {
+		struct cam_req_mgr_add_request add_req = {0};
+
+		CAM_DBG(CAM_TPG, "TPG[%d] NOP packet request id : %llu",
+				tpg_dev->soc_info.index,
+				csl_packet->header.request_id);
+		if ((tpg_dev->crm_intf.link_hdl != -1) &&
+			(tpg_dev->crm_intf.device_hdl != -1) &&
+			(tpg_dev->crm_intf.crm_cb != NULL)) {
+			add_req.link_hdl = tpg_dev->crm_intf.link_hdl;
+			add_req.dev_hdl  = tpg_dev->crm_intf.device_hdl;
+			add_req.req_id = csl_packet->header.request_id;
+			tpg_dev->crm_intf.crm_cb->add_req(&add_req);
+		} else {
+			CAM_ERR(CAM_TPG, "TPG[%d] invalid link req: %llu",
+					tpg_dev->soc_info.index,
+					csl_packet->header.request_id);
+		}
+		break;
+	}
+	default:
+		CAM_ERR(CAM_TPG, "TPG[%d] Invalid packet %x",
+					tpg_dev->soc_info.index,
+					(csl_packet->header.op_code & 0xFF));
+		rc = -EINVAL;
+		break;
+	}
+end:
+	return rc;
+}
+
+static int __cam_tpg_handle_config_dev(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_config_dev_cmd *config)
+{
+	int rc = 0;
+
+	if (!config || !tpg_dev)
+		return -EINVAL;
+
+	if (config->dev_handle <= 0) {
+		CAM_ERR(CAM_TPG, "TPG[%d] Invalid device handle",
+				tpg_dev->soc_info.index);
+		return -EINVAL;
+	}
+
+	if (config->session_handle <= 0) {
+		CAM_ERR(CAM_TPG, "TPG[%d] Invalid session handle",
+				tpg_dev->soc_info.index);
+		return -EINVAL;
+	}
+
+	if (tpg_dev->state < CAM_TPG_STATE_ACQUIRE) {
+		CAM_ERR(CAM_TPG, "TPG[%d] not in right state[%d] to configure",
+				tpg_dev->soc_info.index, tpg_dev->state);
+	}
+	// Handle Config Dev
+	rc = cam_tpg_packet_parse(tpg_dev, config);
+	return rc;
+}
+
+static int validate_ioctl_params(
+	struct cam_tpg_device *tpg_dev,
+	struct cam_control *cmd)
+{
+	int rc = 0;
+
+	if (!tpg_dev || !cmd) {
+		CAM_ERR(CAM_TPG, "Invalid input args");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	if (cmd->handle_type != CAM_HANDLE_USER_POINTER) {
+		CAM_ERR(CAM_TPG, "TPG[%d] Invalid handle type: %d",
+			tpg_dev->soc_info.index,
+			cmd->handle_type);
+		rc = -EINVAL;
+	}
+	CAM_DBG(CAM_TPG, "TPG[%d] Opcode: %d", tpg_dev->soc_info.index, cmd->op_code);
+exit:
+	return rc;
+}
+
+int cam_tpg_core_cfg(
+	struct cam_tpg_device *tpg_dev,
+	void *arg)
+{
+	int rc = 0;
+	struct cam_control   *cmd = (struct cam_control *)arg;
+
+	rc = validate_ioctl_params(tpg_dev, cmd);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&tpg_dev->mutex);
+	switch (cmd->op_code) {
+	case CAM_QUERY_CAP: {
+		struct cam_tpg_query_cap query = {0};
+
+		if (copy_from_user(&query, u64_to_user_ptr(cmd->handle),
+			sizeof(query))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = __cam_tpg_handle_query_cap(tpg_dev, &query);
+		if (rc) {
+			CAM_ERR(CAM_TPG, "TPG[%d] querycap is failed(rc = %d)",
+				tpg_dev->soc_info.index,
+				rc);
+			break;
+		}
+
+		if (copy_to_user(u64_to_user_ptr(cmd->handle), &query,
+			sizeof(query)))
+			rc = -EFAULT;
+
+		break;
+	}
+	case CAM_ACQUIRE_DEV: {
+		struct cam_tpg_acquire_dev acquire = {0};
+
+		if (copy_from_user(&acquire, u64_to_user_ptr(cmd->handle),
+			sizeof(acquire))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = __cam_tpg_handle_acquire_dev(tpg_dev, &acquire);
+		if (rc) {
+			CAM_ERR(CAM_TPG, "TPG[%d] acquire device failed(rc = %d)",
+				tpg_dev->soc_info.index,
+				rc);
+			break;
+		}
+		if (copy_to_user(u64_to_user_ptr(cmd->handle), &acquire,
+			sizeof(acquire)))
+			rc = -EFAULT;
+		break;
+	}
+	case CAM_RELEASE_DEV: {
+		struct cam_release_dev_cmd release;
+
+		if (copy_from_user(&release, u64_to_user_ptr(cmd->handle),
+			sizeof(release)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_tpg_handle_release_dev(tpg_dev, &release);
+			if (rc)
+				CAM_ERR(CAM_TPG,
+					"TPG[%d] release device failed(rc = %d)",
+					tpg_dev->soc_info.index,
+					rc);
+		}
+		break;
+	}
+	case CAM_START_DEV: {
+		struct cam_start_stop_dev_cmd start;
+
+		if (copy_from_user(&start, u64_to_user_ptr(cmd->handle),
+			sizeof(start)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_tpg_handle_start_dev(tpg_dev, &start);
+			if (rc)
+				CAM_ERR(CAM_TPG,
+					"TPG[%d] start device failed(rc = %d)",
+					tpg_dev->soc_info.index,
+					rc);
+		}
+		break;
+	}
+	case CAM_STOP_DEV: {
+		struct cam_start_stop_dev_cmd stop;
+
+		if (copy_from_user(&stop, u64_to_user_ptr(cmd->handle),
+			sizeof(stop)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_tpg_handle_stop_dev(tpg_dev, &stop);
+			if (rc)
+				CAM_ERR(CAM_TPG,
+					"TPG[%d] stop device failed(rc = %d)",
+					tpg_dev->soc_info.index,
+					rc);
+		}
+		break;
+
+	}
+	case CAM_CONFIG_DEV: {
+		struct cam_config_dev_cmd config;
+
+		if (copy_from_user(&config, u64_to_user_ptr(cmd->handle),
+			sizeof(config)))
+			rc = -EFAULT;
+		else {
+			rc = __cam_tpg_handle_config_dev(tpg_dev, &config);
+			if (rc)
+				CAM_ERR(CAM_TPG,
+					"TPG[%d] config device failed(rc = %d)",
+					tpg_dev->soc_info.index,
+					rc);
+		}
+		break;
+	}
+	default:
+		CAM_ERR(CAM_TPG, "Invalid ioctl : %d", cmd->op_code);
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&tpg_dev->mutex);
+	return rc;
+}

+ 39 - 0
drivers/cam_sensor_module/cam_tpg/cam_tpg_core.h

@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __CAM_TPG_CORE_H__
+#define __CAM_TPG_CORE_H__
+
+#include "cam_tpg_dev.h"
+
+/**
+ * @brief : do clean up of driver on user space process restart
+ *
+ * @param tpg_dev: tpg device
+ *
+ * @return : 0 on success
+ */
+int cam_tpg_shutdown(struct cam_tpg_device *tpg_dev);
+
+/**
+ * @brief initialize crm interface
+ *
+ * @param tpg_dev: tpg device instance
+ *
+ * @return : 0 on success
+ */
+int tpg_crm_intf_init(struct cam_tpg_device *tpg_dev);
+
+/**
+ * @brief : handle tpg device configuration
+ *
+ * @param tpg_dev : tpg device instance
+ * @param arg     : configuration argument
+ *
+ * @return        : 0 on success
+ */
+int32_t cam_tpg_core_cfg(struct cam_tpg_device *tpg_dev, void *arg);
+
+#endif

+ 381 - 0
drivers/cam_sensor_module/cam_tpg/cam_tpg_dev.c

@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#include "cam_tpg_dev.h"
+#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_3/tpg_hw_v_1_3_data.h"
+
+static long cam_tpg_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct cam_tpg_device *tpg_dev = v4l2_get_subdevdata(sd);
+	int rc = 0;
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_tpg_core_cfg(tpg_dev, arg);
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "Wrong ioctl : %d", cmd);
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+
+	return rc;
+}
+
+
+#ifdef CONFIG_COMPAT
+static long cam_tpg_subdev_compat_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, unsigned long arg)
+{
+	int32_t rc = 0;
+	struct cam_control cmd_data;
+
+	if (copy_from_user(&cmd_data, (void __user *)arg,
+		sizeof(cmd_data))) {
+		CAM_ERR(CAM_TPG, "Failed to copy from user_ptr=%pK size=%zu",
+			(void __user *)arg, sizeof(cmd_data));
+		return -EFAULT;
+	}
+
+	/* All the arguments converted to 64 bit here
+	 * Passed to the api in core.c
+	 */
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_tpg_subdev_ioctl(sd, cmd, &cmd_data);
+		if (rc)
+			CAM_ERR(CAM_TPG,
+				"Failed in subdev_ioctl: %d", rc);
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "Invalid compat ioctl cmd: %d", cmd);
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+
+	if (!rc) {
+		if (copy_to_user((void __user *)arg, &cmd_data,
+			sizeof(cmd_data))) {
+			CAM_ERR(CAM_TPG,
+				"Failed to copy to user_ptr=%pK size=%zu",
+				(void __user *)arg, sizeof(cmd_data));
+			rc = -EFAULT;
+		}
+	}
+
+	return rc;
+}
+#endif
+
+
+static struct v4l2_subdev_core_ops tpg_subdev_core_ops = {
+	.ioctl = cam_tpg_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = cam_tpg_subdev_compat_ioctl,
+#endif
+};
+
+static int cam_tpg_subdev_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_tpg_device *tpg_dev =
+		v4l2_get_subdevdata(sd);
+
+	if (!tpg_dev) {
+		CAM_ERR(CAM_TPG, "tpg_dev ptr is NULL");
+		return -EINVAL;
+	}
+
+	mutex_lock(&tpg_dev->mutex);
+	cam_tpg_shutdown(tpg_dev);
+	mutex_unlock(&tpg_dev->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_ops tpg_subdev_ops = {
+	.core = &tpg_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops tpg_subdev_intern_ops = {
+	.close = cam_tpg_subdev_close,
+};
+
+irqreturn_t cam_tpg_irq_handler(int irq_num, void *data)
+{
+	CAM_DBG(CAM_TPG, "tpg irq handler");
+	return IRQ_HANDLED;
+}
+
+
+static int tpg_subdev_init(struct cam_tpg_device *tpg_dev,
+		struct device *dev)
+{
+	int32_t rc = 0;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	tpg_dev->tpg_subdev.pdev = pdev;
+	tpg_dev->tpg_subdev.internal_ops = &tpg_subdev_intern_ops;
+	tpg_dev->tpg_subdev.ops = &tpg_subdev_ops;
+	tpg_dev->tpg_subdev.name = tpg_dev->device_name;
+	tpg_dev->tpg_subdev.sd_flags =
+		(V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
+	tpg_dev->tpg_subdev.ent_function = CAM_TPG_DEVICE_TYPE;
+	tpg_dev->tpg_subdev.msg_cb = NULL;
+	tpg_dev->tpg_subdev.token = tpg_dev;
+
+	rc = cam_register_subdev(&(tpg_dev->tpg_subdev));
+	if (rc)
+		CAM_ERR(CAM_TPG, "cam_register_subdev Failed rc: %d", rc);
+	else
+		CAM_DBG(CAM_TPG, "TPG subdev init done");
+	return rc;
+
+}
+
+static int tpg_soc_info_init(struct cam_tpg_device *tpg_dev,
+		struct device *dev)
+{
+	int32_t rc = 0;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct device_node *of_node = NULL;
+
+	tpg_dev->soc_info.pdev = pdev;
+	tpg_dev->soc_info.dev = &pdev->dev;
+	tpg_dev->soc_info.dev_name = pdev->name;
+	if (!dev || !tpg_dev)
+		return -EINVAL;
+
+	of_node = dev->of_node;
+
+	rc = cam_soc_util_get_dt_properties(&tpg_dev->soc_info);
+	if (rc < 0) {
+		CAM_ERR(CAM_CSIPHY, "parsing common soc dt(rc %d)", rc);
+		return  rc;
+	}
+
+	rc = of_property_read_u32(of_node, "phy-id", &(tpg_dev->phy_id));
+	if (rc) {
+		CAM_ERR(CAM_TPG, "device %s failed to read phy-id",
+			tpg_dev->soc_info.dev_name);
+		return rc;
+	}
+
+	rc = cam_soc_util_request_platform_resource(
+			&tpg_dev->soc_info,
+			cam_tpg_irq_handler,
+			tpg_dev);
+	if (rc)
+		CAM_ERR(CAM_TPG, "unable to request platfrom resources");
+	else
+		CAM_DBG(CAM_TPG, "TPG dt parse done");
+
+	return rc;
+}
+
+static int tpg_register_cpas_client(struct cam_tpg_device *tpg_dev,
+		struct device *dev)
+{
+	int32_t rc = 0;
+	struct cam_cpas_register_params cpas_parms;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	cpas_parms.cam_cpas_client_cb = NULL;
+	cpas_parms.cell_index = tpg_dev->soc_info.index;
+	cpas_parms.dev = &pdev->dev;
+	cpas_parms.userdata = tpg_dev;
+
+	strlcpy(cpas_parms.identifier, "tpg", CAM_HW_IDENTIFIER_LENGTH);
+
+	rc = cam_cpas_register_client(&cpas_parms);
+	if (rc) {
+		CAM_ERR(CAM_TPG, "CPAS registration failed rc: %d", rc);
+		return rc;
+	}
+
+	tpg_dev->cpas_handle = cpas_parms.client_handle;
+	CAM_DBG(CAM_TPG, "CPAS registration successful handle=%d",
+		cpas_parms.client_handle);
+
+	return rc;
+}
+
+static int cam_tpg_hw_layer_init(struct cam_tpg_device *tpg_dev,
+		struct device *dev)
+{
+	int i = 0;
+	/* get top tpg hw information */
+	const struct of_device_id      *match_dev = NULL;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev) {
+		CAM_ERR(CAM_TPG, "No matching table for the top tpg hw");
+		return -EINVAL;
+	}
+
+	tpg_dev->tpg_hw.hw_idx   = tpg_dev->soc_info.index;
+	tpg_dev->tpg_hw.hw_info  = (struct tpg_hw_info *)match_dev->data;
+	tpg_dev->tpg_hw.soc_info = &tpg_dev->soc_info;
+	tpg_dev->tpg_hw.cpas_handle = tpg_dev->cpas_handle;
+	mutex_init(&tpg_dev->tpg_hw.mutex);
+
+	tpg_dev->tpg_hw.vc_slots = devm_kzalloc(&pdev->dev,
+			sizeof(struct tpg_vc_slot_info) * tpg_dev->tpg_hw.hw_info->max_vc_channels,
+			GFP_KERNEL);
+	if (!tpg_dev->tpg_hw.vc_slots) {
+		CAM_ERR(CAM_TPG, "TPG VC slot allocation failed");
+		mutex_destroy(&tpg_dev->tpg_hw.mutex);
+		return -ENOMEM;
+	}
+
+	for(i = 0; i < tpg_dev->tpg_hw.hw_info->max_vc_channels; i++) {
+		tpg_dev->tpg_hw.vc_slots[i].slot_id      =  i;
+		tpg_dev->tpg_hw.vc_slots[i].vc           = -1;
+		tpg_dev->tpg_hw.vc_slots[i].stream_count =  0;
+		INIT_LIST_HEAD(&(tpg_dev->tpg_hw.vc_slots[i].head));
+	}
+
+	return 0;
+}
+
+static int cam_tpg_component_bind(struct device *dev,
+	struct device *master_dev, void *data)
+{
+	int rc = 0;
+	struct cam_tpg_device  *tpg_dev = NULL;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	tpg_dev = devm_kzalloc(&pdev->dev,
+		sizeof(struct cam_tpg_device), GFP_KERNEL);
+	if (!tpg_dev) {
+		CAM_ERR(CAM_TPG, "TPG dev allocation failed");
+		return -ENOMEM;
+	}
+
+	strlcpy(tpg_dev->device_name, CAMX_TPG_DEV_NAME,
+		sizeof(tpg_dev->device_name));
+	mutex_init(&tpg_dev->mutex);
+	tpg_dev->tpg_subdev.pdev = pdev;
+	tpg_dev->state = CAM_TPG_STATE_INIT;
+	rc = tpg_subdev_init(tpg_dev, dev);
+	if (rc < 0) {
+		CAM_ERR(CAM_TPG, "subdev init failed");
+		goto bind_error_exit;
+	}
+
+	rc = tpg_soc_info_init(tpg_dev, dev);
+	if (rc < 0) {
+		CAM_ERR(CAM_TPG, "soc init failed");
+		goto release_subdev;
+	}
+
+	rc = tpg_register_cpas_client(tpg_dev, dev);
+	if (rc < 0) {
+		CAM_ERR(CAM_TPG, "cpas register failed");
+		goto release_subdev;
+	}
+	tpg_crm_intf_init(tpg_dev);
+	rc = cam_tpg_hw_layer_init(tpg_dev, dev);
+	if (rc < 0) {
+		CAM_ERR(CAM_TPG, "Hw layer init failed");
+		goto release_subdev;
+	}
+
+	return rc;
+
+release_subdev:
+	cam_unregister_subdev(&(tpg_dev->tpg_subdev));
+bind_error_exit:
+	mutex_destroy(&tpg_dev->mutex);
+	return rc;
+}
+
+static void cam_tpg_component_unbind(struct device *dev,
+	struct device *master_dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	struct cam_tpg_device *tpg_dev = v4l2_get_subdevdata(subdev);
+
+	CAM_INFO(CAM_TPG, "Unbind TPG component");
+	cam_cpas_unregister_client(tpg_dev->cpas_handle);
+	cam_soc_util_release_platform_resource(&tpg_dev->soc_info);
+	mutex_destroy(&tpg_dev->mutex);
+	mutex_destroy(&tpg_dev->tpg_hw.mutex);
+	platform_set_drvdata(pdev, NULL);
+	v4l2_set_subdevdata(&(tpg_dev->tpg_subdev.sd), NULL);
+	cam_unregister_subdev(&(tpg_dev->tpg_subdev));
+}
+
+const static struct component_ops cam_tpg_component_ops = {
+	.bind = cam_tpg_component_bind,
+	.unbind = cam_tpg_component_unbind,
+};
+
+static int32_t cam_tpg_platform_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	CAM_DBG(CAM_TPG, "Adding TPG component");
+	rc = component_add(&pdev->dev, &cam_tpg_component_ops);
+	if (rc)
+		CAM_ERR(CAM_TPG, "failed to add component rc: %d", rc);
+
+	return rc;
+}
+
+
+static int32_t cam_tpg_device_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &cam_tpg_component_ops);
+	return 0;
+}
+
+static const struct of_device_id cam_tpg_dt_match[] = {
+	{
+		.compatible = "qcom,cam-tpg101",
+		.data = &tpg_v_1_0_hw_info,
+	},
+	{
+		.compatible = "qcom,cam-tpg103",
+		.data = &tpg_v_1_3_hw_info,
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cam_tpg_dt_match);
+
+struct platform_driver cam_tpg_driver = {
+	.probe = cam_tpg_platform_probe,
+	.remove = cam_tpg_device_remove,
+	.driver = {
+		.name = CAMX_TPG_DEV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = cam_tpg_dt_match,
+		.suppress_bind_attrs = true,
+	},
+};
+
+int32_t cam_tpg_init_module(void)
+{
+	CAM_DBG(CAM_TPG, "tpg module init");
+	return platform_driver_register(&cam_tpg_driver);
+}
+
+void cam_tpg_exit_module(void)
+{
+	CAM_DBG(CAM_TPG, "tpg exit module");
+	platform_driver_unregister(&cam_tpg_driver);
+}
+
+MODULE_DESCRIPTION("CAM TPG driver");
+MODULE_LICENSE("GPL v2");

+ 142 - 0
drivers/cam_sensor_module/cam_tpg/cam_tpg_dev.h

@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __CAM_TPG_DEV_H__
+#define __CAM_TPG_DEV_H__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/irqreturn.h>
+#include <linux/iommu.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/cam_defs.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_req_mgr_interface.h>
+#include <cam_subdev.h>
+#include <cam_io_util.h>
+#include <media/cam_defs.h>
+#include "cam_debug_util.h"
+#include "cam_context.h"
+#include "cam_soc_util.h"
+#include <cam_cpas_api.h>
+#include "tpg_hw/tpg_hw.h"
+
+#define CAMX_TPG_DEV_NAME "cam-tpg-driver"
+
+struct cam_tpg_device;
+struct tpg_hw;
+
+struct cam_tpg_ioctl_ops {
+	int (*acquire_dev)(struct cam_tpg_device *tpg_dev,
+			struct cam_acquire_dev_cmd *cmd);
+	int (*release_dev)(struct cam_tpg_device *tpg_dev,
+			struct cam_release_dev_cmd *cmd);
+	int (*config_dev)(struct cam_tpg_device *tpg_dev,
+			struct cam_config_dev_cmd *cmd);
+	int (*start_dev)(struct cam_tpg_device *tpg_dev,
+			struct cam_start_stop_dev_cmd *cmd);
+	int (*stop_dev)(struct cam_tpg_device *tpg_dev,
+			struct cam_start_stop_dev_cmd *cmd);
+	int (*flush_dev)(struct cam_tpg_device *tpg_dev,
+			struct cam_flush_dev_cmd *cmd);
+	int (*acquire_hw)(struct cam_tpg_device *tpg_dev, void *args);
+	int (*release_hw)(struct cam_tpg_device *tpg_dev, void *args);
+};
+
+struct cam_tpg_crm_ops {
+	int (*get_dev_info)(struct cam_tpg_device *tpg_dev,
+			struct cam_req_mgr_device_info *device_info);
+	int (*link)(struct cam_tpg_device *tpg_dev,
+			struct cam_req_mgr_core_dev_link_setup *link);
+	int (*unlink)(struct cam_tpg_device *tpg_dev,
+			struct cam_req_mgr_core_dev_link_setup *unlink);
+	int (*apply_req)(struct cam_tpg_device *tpg_dev,
+			struct cam_req_mgr_apply_request *apply);
+	int (*notify_frame_skip)(struct cam_tpg_device *tpg_dev,
+			struct cam_req_mgr_apply_request *apply);
+	int (*flush_req)(struct cam_tpg_device *tpg_dev,
+			struct cam_req_mgr_flush_request *flush);
+	int (*process_evt)(struct cam_tpg_device *tpg_dev,
+			struct cam_req_mgr_link_evt_data *evt_data);
+};
+
+struct tpg_device_ops {
+	struct cam_tpg_ioctl_ops ioctl_ops;
+	struct cam_tpg_crm_ops   crm_ops;
+};
+
+enum cam_tpg_state {
+	CAM_TPG_STATE_INIT,
+	CAM_TPG_STATE_ACQUIRE,
+	CAM_TPG_STATE_START,
+	CAM_TPG_STATE_STATE_MAX
+};
+
+/**
+ * struct tpg_crm_intf_params
+ * @device_hdl: Device Handle
+ * @session_hdl: Session Handle
+ * @link_hdl: Link Handle
+ * @ops: KMD operations
+ * @crm_cb: Callback API pointers
+ */
+struct tpg_crm_intf_params {
+	int32_t device_hdl;
+	int32_t session_hdl;
+	int32_t link_hdl;
+	struct cam_req_mgr_kmd_ops ops;
+	struct cam_req_mgr_crm_cb *crm_cb;
+};
+
+/**
+ * cam_tpg_device
+ *
+ * @device_name: tpg device name
+ * @mutex: mutex object for private use
+ * @tpg_subdev: tpg subdevice instance
+ * @soc_info: tpg soc infrastructure
+ * @cpas_handle: cpas handle
+ * @state_machine: tpg state machine
+ * @crm_intf: crm interface
+ * @tpg_hw  : tpg hw instance
+ * @state   : state machine states
+ * @slot_id : slot index of this tpg
+ * @phy_id  : phy index mapped to this tpg
+ */
+struct cam_tpg_device {
+	char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH];
+	struct mutex mutex;
+	struct cam_subdev tpg_subdev;
+	struct cam_hw_soc_info soc_info;
+	uint32_t cpas_handle;
+	struct tpg_device_ops state_machine[CAM_TPG_STATE_STATE_MAX];
+	struct tpg_crm_intf_params crm_intf;
+	struct tpg_hw tpg_hw;
+	int state;
+	int slot_id;
+	int phy_id;
+};
+
+
+/**
+ * @brief : tpg module init
+ *
+ * @return : 0 on success
+ */
+int32_t cam_tpg_init_module(void);
+
+/**
+ * @brief : tpg module exit
+ */
+void cam_tpg_exit_module(void);
+
+#endif

+ 671 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c

@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#include "tpg_hw.h"
+
+#define BYTES_PER_REGISTER           4
+#define NUM_REGISTER_PER_LINE        4
+#define REG_OFFSET(__start, __i)    ((__start) + ((__i) * BYTES_PER_REGISTER))
+
+static int cam_io_tpg_dump(void __iomem *base_addr,
+	uint32_t start_offset, int size)
+{
+	char          line_str[128];
+	char         *p_str;
+	int           i;
+	uint32_t      data;
+
+	CAM_DBG(CAM_TPG, "addr=%pK offset=0x%x size=%d",
+		base_addr, start_offset, size);
+
+	if (!base_addr || (size <= 0))
+		return -EINVAL;
+
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size; i++) {
+		if (i % NUM_REGISTER_PER_LINE == 0) {
+			snprintf(p_str, 12, "0x%08x: ",
+				REG_OFFSET(start_offset, i));
+			p_str += 11;
+		}
+		data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i));
+		snprintf(p_str, 9, "%08x ", data);
+		p_str += 8;
+		if ((i + 1) % NUM_REGISTER_PER_LINE == 0) {
+			CAM_DBG(CAM_TPG, "%s", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		CAM_ERR(CAM_TPG, "%s", line_str);
+
+	return 0;
+}
+
+int32_t cam_tpg_mem_dmp(struct cam_hw_soc_info *soc_info)
+{
+	int32_t rc = 0;
+	resource_size_t size = 0;
+	void __iomem *addr = NULL;
+
+	if (!soc_info) {
+		rc = -EINVAL;
+		CAM_ERR(CAM_TPG, "invalid input %d", rc);
+		return rc;
+	}
+	addr = soc_info->reg_map[0].mem_base;
+	size = resource_size(soc_info->mem_block[0]);
+	rc = cam_io_tpg_dump(addr, 0, (size >> 2));
+	if (rc < 0) {
+		CAM_ERR(CAM_TPG, "generating dump failed %d", rc);
+	}
+	return rc;
+}
+
+
+#define __TPG_DEBUG_DUMP__
+#ifdef __TPG_DEBUG_DUMP__
+static const char * const tpg_phy_type_strings[] = {
+	"TPG_PHY_TYPE_INVALID",
+	"TPG_PHY_TYPE_DPHY",
+	"TPG_PHY_TYPE_CPHY",
+	"TPG_PHY_TYPE_MAX"
+};
+
+static const char * const tpg_interleaving_format_string[] = {
+	"TPG_INTERLEAVING_FORMAT_INVALID",
+	"TPG_INTERLEAVING_FORMAT_FRAME",
+	"TPG_INTERLEAVING_FORMAT_LINE",
+	"TPG_INTERLEAVING_FORMAT_MAX"
+};
+
+static const char * const tpg_shutter_type_strings[] = {
+	"TPG_SHUTTER_TYPE_INVALID",
+	"TPG_SHUTTER_TYPE_ROLLING",
+	"TPG_SHUTTER_TYPE_GLOBAL",
+	"TPG_SHUTTER_TYPE_MAX"
+};
+
+static const char *const tpg_pattern_type_strings[] = {
+	"TPG_PATTERN_INVALID",
+	"TPG_PATTERN_REAL_IMAGE",
+	"TPG_PATTERN_RANDOM_PIXL",
+	"TPG_PATTERN_RANDOM_INCREMENTING_PIXEL",
+	"TPG_PATTERN_COLOR_BAR",
+	"TPG_PATTERN_ALTERNATING_55_AA",
+	"TPG_PATTERN_ALTERNATING_USER_DEFINED",
+	"TPG_PATTERN_MAX"
+};
+
+static const char *const tpg_color_bar_mode_strings[] = {
+	"TPG_COLOR_BAR_MODE_INVALID",
+	"TPG_COLOR_BAR_MODE_NORMAL",
+	"TPG_COLOR_BAR_MODE_SPLIT",
+	"TPG_COLOR_BAR_MODE_ROTATING",
+	"TPG_COLOR_BAR_MODE_MAX"
+};
+
+static const char *const tpg_stream_type_strings[] = {
+	"TPG_STREAM_TYPE_INVALID",
+	"TPG_STREAM_TYPE_IMAGE",
+	"TPG_STREAM_TYPE_PDAF",
+	"TPG_STREAM_TYPE_META",
+	"TPG_STREAM_TYPE_MAX"
+};
+
+static const char *const tpg_image_format_type_strings[] = {
+	"TPG_IMAGE_FORMAT_INVALID",
+	"TPG_IMAGE_FORMAT_BAYER",
+	"TPG_IMAGE_FORMAT_QCFA",
+	"TPG_IMAGE_FORMAT_YUV",
+	"TPG_IMAGE_FORMAT_JPEG",
+	"TPG_IMAGE_FORMAT_MAX"
+};
+#endif
+
+int dump_global_configs(int idx,
+		struct tpg_global_config_t *global)
+{
+#ifdef __TPG_DEBUG_DUMP__
+	CAM_DBG(CAM_TPG, "TPG[%d] phy_type            : %s",
+			idx,
+			tpg_phy_type_strings[global->phy_type]);
+	CAM_DBG(CAM_TPG, "TPG[%d] lane_count          : %d",
+			idx,
+			global->lane_count);
+	CAM_DBG(CAM_TPG, "TPG[%d] interleaving_format : %s",
+			idx,
+			tpg_interleaving_format_string[global->interleaving_format]);
+	CAM_DBG(CAM_TPG, "TPG[%d] phy_mode            : %d",
+			idx,
+			global->phy_mode);
+	CAM_DBG(CAM_TPG, "TPG[%d] shutter_type        : %s",
+			idx,
+			tpg_shutter_type_strings[global->shutter_type]);
+	CAM_DBG(CAM_TPG, "TPG[%d] skip pattern        : 0x%x",
+			idx,
+			global->skip_pattern);
+	CAM_DBG(CAM_TPG, "TPG[%d] tpg clock           : %d",
+			idx,
+			global->tpg_clock);
+#endif
+	return 0;
+}
+
+int dump_stream_configs(int hw_idx,
+		int stream_idx,
+		struct tpg_stream_config_t *stream)
+{
+#ifdef __TPG_DEBUG_DUMP__
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] pattern_type    : %s",
+			hw_idx,
+			stream_idx,
+			tpg_pattern_type_strings[stream->pattern_type]);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] cb_mode         : %s",
+			hw_idx,
+			stream_idx,
+			tpg_color_bar_mode_strings[stream->cb_mode]);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] frame_count     : %d",
+			hw_idx,
+			stream_idx,
+			stream->frame_count);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] stream_type     : %s",
+			hw_idx,
+			stream_idx,
+			tpg_stream_type_strings[stream->stream_type]);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] left            : %d",
+			hw_idx,
+			stream_idx,
+			stream->stream_dimension.left);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] top             : %d",
+			hw_idx,
+			stream_idx,
+			stream->stream_dimension.top);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] width           : %d",
+			hw_idx,
+			stream_idx,
+			stream->stream_dimension.width);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] height          : %d",
+			hw_idx,
+			stream_idx,
+			stream->stream_dimension.height);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] pixel_depth     : %d",
+			hw_idx,
+			stream_idx,
+			stream->pixel_depth);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] cfa_arrangement : %d",
+			hw_idx,
+			stream_idx,
+			stream->cfa_arrangement);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] output_format   : %s",
+			hw_idx,
+			stream_idx,
+		tpg_image_format_type_strings[stream->output_format]);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] vc              : 0x%x",
+			hw_idx,
+			stream_idx,
+			stream->vc);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] dt              : 0x%x",
+			hw_idx,
+			stream_idx,
+			stream->dt);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] hbi             : %d",
+			hw_idx,
+			stream_idx,
+			stream->hbi);
+	CAM_DBG(CAM_TPG, "TPG[%d][%d] vbi             : %d",
+			hw_idx,
+			stream_idx,
+			stream->vbi);
+#endif
+	return 0;
+}
+
+
+static int tpg_hw_soc_disable(struct tpg_hw *hw)
+{
+	int rc = 0;
+
+	if (!hw || !hw->soc_info) {
+		CAM_ERR(CAM_TPG, "Error Invalid params");
+		return -EINVAL;
+	}
+
+	rc = cam_soc_util_disable_platform_resource(hw->soc_info, true, false);
+	if (rc)
+		CAM_ERR(CAM_TPG, "TPG[%d] Disable platform failed %d",
+				hw->hw_idx, rc);
+
+	if (cam_cpas_stop(hw->cpas_handle)) {
+		CAM_ERR(CAM_TPG, "TPG[%d] CPAS stop failed",
+				hw->hw_idx);
+	}
+
+	return rc;
+}
+
+static int tpg_hw_soc_enable(
+	struct tpg_hw *hw,
+	enum cam_vote_level clk_level)
+{
+	int rc = 0;
+	struct cam_ahb_vote ahb_vote;
+	struct cam_axi_vote axi_vote = {0};
+
+	ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	ahb_vote.vote.level = CAM_SVS_VOTE;
+	axi_vote.num_paths = 1;
+	axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL;
+	axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE;
+
+	axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW;
+
+	CAM_DBG(CAM_TPG, "TPG[%d] camnoc_bw:%lld mnoc_ab_bw:%lld mnoc_ib_bw:%lld ",
+		hw->hw_idx,
+		axi_vote.axi_path[0].camnoc_bw,
+		axi_vote.axi_path[0].mnoc_ab_bw,
+		axi_vote.axi_path[0].mnoc_ib_bw);
+
+	rc = cam_cpas_start(hw->cpas_handle, &ahb_vote, &axi_vote);
+	if (rc) {
+		CAM_ERR(CAM_TPG, "TPG[%d] CPAS start failed",
+				hw->hw_idx);
+		rc = -EFAULT;
+		goto end;
+	}
+
+	rc = cam_soc_util_enable_platform_resource(hw->soc_info, true,
+		clk_level, false);
+	if (rc) {
+		CAM_ERR(CAM_TPG, "TPG[%d] enable platform failed",
+				hw->hw_idx);
+		goto stop_cpas;
+	}
+
+	return rc;
+stop_cpas:
+	cam_cpas_stop(hw->cpas_handle);
+end:
+	return rc;
+}
+
+static int tpg_hw_start_default_new(struct tpg_hw *hw)
+{
+	int i = 0;
+	uint32_t stream_idx = 0;
+	int num_vcs = 0;
+	struct global_config_args globalargs = {0};
+	if (!hw ||
+		!hw->hw_info ||
+		!hw->hw_info->ops ||
+		!hw->hw_info->ops->process_cmd) {
+		CAM_ERR(CAM_TPG, "Invalid argument");
+		return -EINVAL;
+	}
+
+	dump_global_configs(hw->hw_idx, &hw->global_config);
+	for(i = 0; i < hw->hw_info->max_vc_channels; i++) {
+		int dt_slot = 0;
+		struct vc_config_args vc_config = {0};
+		struct list_head *pos = NULL, *pos_next = NULL;
+		struct tpg_hw_stream *entry = NULL, *vc_stream_entry = NULL;
+
+		if (hw->vc_slots[i].vc == -1)
+			break;
+		num_vcs++;
+		vc_config.vc_slot = i;
+		vc_config.num_dts = hw->vc_slots[i].stream_count;
+		vc_stream_entry = list_first_entry(&hw->vc_slots[i].head,
+			struct tpg_hw_stream, list);
+		vc_config.stream  = &vc_stream_entry->stream;
+		hw->hw_info->ops->process_cmd(hw,
+				TPG_CONFIG_VC, &vc_config);
+
+		list_for_each_safe(pos, pos_next, &hw->vc_slots[i].head) {
+			struct dt_config_args dt_config = {0};
+			entry = list_entry(pos, struct tpg_hw_stream, list);
+			dump_stream_configs(hw->hw_idx,
+				stream_idx++,
+				&entry->stream);
+			dt_config.vc_slot = i;
+			dt_config.dt_slot = dt_slot++;
+			dt_config.stream  = &entry->stream;
+			hw->hw_info->ops->process_cmd(hw, TPG_CONFIG_DT, &dt_config);
+		}
+	}
+
+	globalargs.num_vcs      = num_vcs;
+	globalargs.globalconfig = &hw->global_config;
+	hw->hw_info->ops->process_cmd(hw,
+		TPG_CONFIG_CTRL, &globalargs);
+
+	return 0;
+}
+
+int tpg_hw_dump_status(struct tpg_hw *hw)
+{
+	if (!hw || !hw->hw_info || !hw->hw_info->ops)
+		return -EINVAL;
+	switch (hw->hw_info->version) {
+	case TPG_HW_VERSION_1_3:
+		if (hw->hw_info->ops->dump_status)
+			hw->hw_info->ops->dump_status(hw, NULL);
+	default:
+		CAM_WARN(CAM_TPG, "Hw version doesn't support status dump");
+		break;
+	}
+	return 0;
+}
+
+int tpg_hw_start(struct tpg_hw *hw)
+{
+	int rc = 0;
+
+	if (!hw || !hw->hw_info || !hw->hw_info->ops)
+		return -EINVAL;
+	mutex_lock(&hw->mutex);
+	switch (hw->hw_info->version) {
+	case TPG_HW_VERSION_1_0:
+	case TPG_HW_VERSION_1_1:
+		if (hw->hw_info->ops->start)
+			hw->hw_info->ops->start(hw, NULL);
+		break;
+	case TPG_HW_VERSION_1_3:
+		if (hw->hw_info->ops->start)
+			hw->hw_info->ops->start(hw, NULL);
+		tpg_hw_start_default_new(hw);
+		cam_tpg_mem_dmp(hw->soc_info);
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version",
+				hw->hw_idx);
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&hw->mutex);
+	return rc;
+}
+
+int tpg_hw_stop(struct tpg_hw *hw)
+{
+	int rc = 0;
+
+	if (!hw || !hw->hw_info || !hw->hw_info->ops)
+		return -EINVAL;
+	mutex_lock(&hw->mutex);
+	switch (hw->hw_info->version) {
+	case TPG_HW_VERSION_1_0:
+	case TPG_HW_VERSION_1_1:
+	case TPG_HW_VERSION_1_3:
+		if (hw->hw_info->ops->stop)
+			rc = hw->hw_info->ops->stop(hw, NULL);
+		rc = tpg_hw_soc_disable(hw);
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version",
+				hw->hw_idx);
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&hw->mutex);
+
+	return rc;
+}
+
+int tpg_hw_acquire(struct tpg_hw *hw,
+		struct tpg_hw_acquire_args *acquire)
+{
+	int rc = 0;
+
+	if (!hw || !hw->hw_info || !hw->hw_info->ops)
+		return -EINVAL;
+
+	mutex_lock(&hw->mutex);
+	switch (hw->hw_info->version) {
+	case TPG_HW_VERSION_1_0:
+	case TPG_HW_VERSION_1_1:
+	case TPG_HW_VERSION_1_3:
+		// Start Cpas and enable required clocks
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version",
+				hw->hw_idx);
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&hw->mutex);
+	return rc;
+}
+
+int tpg_hw_release(struct tpg_hw *hw)
+{
+	int rc = 0;
+
+	if (!hw || !hw->hw_info || !hw->hw_info->ops)
+		return -EINVAL;
+	mutex_lock(&hw->mutex);
+	switch (hw->hw_info->version) {
+	case TPG_HW_VERSION_1_0:
+	case TPG_HW_VERSION_1_1:
+	case TPG_HW_VERSION_1_3:
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version",
+				hw->hw_idx);
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&hw->mutex);
+	return rc;
+}
+
+static int tpg_hw_configure_init_settings(
+		struct tpg_hw *hw,
+		struct tpg_hw_initsettings *settings)
+{
+	int rc = 0;
+
+	if (!hw || !hw->hw_info || !hw->hw_info->ops)
+		return -EINVAL;
+	mutex_lock(&hw->mutex);
+	switch (hw->hw_info->version) {
+	case TPG_HW_VERSION_1_0:
+	case TPG_HW_VERSION_1_1:
+	case TPG_HW_VERSION_1_3:
+		rc = tpg_hw_soc_enable(hw, CAM_SVS_VOTE);
+		if (hw->hw_info->ops->init)
+			rc = hw->hw_info->ops->init(hw, settings);
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version",
+				hw->hw_idx);
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&hw->mutex);
+	return rc;
+}
+
+int tpg_hw_config(
+	struct tpg_hw *hw,
+	enum tpg_hw_cmd_t config_cmd,
+	void *config_args)
+{
+	int rc = 0;
+
+	if (!hw || !hw->hw_info || !hw->hw_info->ops)
+		return -EINVAL;
+	switch (config_cmd) {
+	case TPG_HW_CMD_INIT_CONFIG:
+		//validate_stream_list(hw);
+		tpg_hw_configure_init_settings(hw,
+			(struct tpg_hw_initsettings *)config_args);
+		break;
+	default:
+		CAM_ERR(CAM_TPG, "TPG[%d] Unsupported hw config command",
+				hw->hw_idx);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int tpg_hw_free_streams(struct tpg_hw *hw)
+{
+	struct list_head *pos = NULL, *pos_next = NULL;
+	struct tpg_hw_stream *entry;
+	int i = 0;
+
+	if (!hw)
+		return -EINVAL;
+
+	mutex_lock(&hw->mutex);
+	/* free up the streams */
+	CAM_DBG(CAM_TPG, "TPG[%d] Freeing all the streams", hw->hw_idx);
+
+	/* reset the slots */
+	for(i = 0; i < hw->hw_info->max_vc_channels; i++) {
+		hw->vc_slots[i].slot_id      =  i;
+		hw->vc_slots[i].vc           = -1;
+		hw->vc_slots[i].stream_count =  0;
+		list_for_each_safe(pos, pos_next, &hw->vc_slots[i].head) {
+			entry = list_entry(pos, struct tpg_hw_stream, list);
+			list_del(pos);
+			kfree(entry);
+		}
+		INIT_LIST_HEAD(&(hw->vc_slots[i].head));
+	}
+	hw->vc_count = 0;
+
+	mutex_unlock(&hw->mutex);
+	return 0;
+}
+
+int tpg_hw_copy_global_config(
+	struct tpg_hw *hw,
+	struct tpg_global_config_t *global)
+{
+	if (!hw || !global) {
+		CAM_ERR(CAM_TPG, "invalid parameter");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw->mutex);
+	memcpy(&hw->global_config,
+		global,
+		sizeof(struct tpg_global_config_t));
+	mutex_unlock(&hw->mutex);
+	return 0;
+}
+
+static int assign_vc_slot(
+	struct tpg_hw *hw,
+	int  vc,
+	struct tpg_hw_stream *stream
+	)
+{
+	int rc = -EINVAL, i = 0, slot_matched = 0;
+
+	if (!hw || !stream) {
+		return -EINVAL;
+	}
+
+	for(i = 0; i < hw->hw_info->max_vc_channels; i++) {
+		/* Found a matching slot */
+		if(hw->vc_slots[i].vc == vc) {
+			slot_matched = 1;
+			if (hw->vc_slots[i].stream_count
+					< hw->hw_info->max_dt_channels_per_vc) {
+				list_add_tail(&stream->list, &hw->vc_slots[i].head);
+				hw->vc_slots[i].stream_count++;
+				hw->vc_slots[i].vc = vc;
+				rc = 0;
+				CAM_DBG(CAM_TPG, "vc[%d]dt[%d]=>slot[%d]", vc, stream->stream.dt, i);
+				break;
+			} else {
+
+				/**
+				 * already slot was assigned for this vc
+				 * however this slot have been filled with
+				 * full streams
+				 */
+				rc = -EINVAL;
+				CAM_ERR(CAM_TPG, "vc[%d]dt[%d]=>slot[%d] is overlfown",
+						vc, stream->stream.dt, i);
+				break;
+			}
+		}
+
+		/**
+		 * none of the above slots matched, and now found an empty slot
+		 * so assigning stream to that slot
+		 */
+		if (hw->vc_slots[i].vc == -1) {
+			list_add_tail(&stream->list, &hw->vc_slots[i].head);
+			hw->vc_slots[i].stream_count++;
+			hw->vc_slots[i].vc = vc;
+			hw->vc_count++;
+			rc = 0;
+			CAM_DBG(CAM_TPG, "vc[%d]dt[%d]=>slot[%d]", vc, stream->stream.dt, i);
+			break;
+		}
+	}
+	if ((slot_matched == 0) && (rc != 0)) {
+		CAM_ERR(CAM_TPG, "No slot matched");
+	}
+	return rc;
+}
+
+int tpg_hw_reset(struct tpg_hw *hw)
+{
+	int rc = 0;
+	if (!hw)
+		return -EINVAL;
+
+	/* free up the streams if any*/
+	rc = tpg_hw_free_streams(hw);
+	if (rc)
+		CAM_ERR(CAM_TPG, "TPG[%d] Unable to free up the streams", hw->hw_idx);
+
+	/* disable the hw */
+	if (cam_cpas_stop(hw->cpas_handle)) {
+		CAM_ERR(CAM_TPG, "TPG[%d] CPAS stop failed",
+				hw->hw_idx);
+	}
+
+	return rc;
+}
+
+int tpg_hw_add_stream(
+	struct tpg_hw *hw,
+	struct tpg_stream_config_t *cmd)
+{
+	int rc = 0;
+	struct tpg_hw_stream *stream = NULL;
+	if (!hw || !cmd) {
+		CAM_ERR(CAM_TPG, "Invalid params");
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw->mutex);
+	stream = kzalloc(sizeof(struct tpg_hw_stream), GFP_KERNEL);
+	if (!stream) {
+		CAM_ERR(CAM_TPG, "TPG[%d] stream allocation failed",
+				hw->hw_idx);
+		mutex_unlock(&hw->mutex);
+		return -ENOMEM;
+	}
+	memcpy(&stream->stream,
+		cmd,
+		sizeof(struct tpg_stream_config_t));
+
+	rc = assign_vc_slot(hw, stream->stream.vc, stream);
+	mutex_unlock(&hw->mutex);
+	return rc;
+}

+ 314 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.h

@@ -0,0 +1,314 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __TPG_HW_H__
+#define __TPG_HW_H__
+
+#include <linux/kernel.h>
+#include "cam_debug_util.h"
+#include "cam_soc_util.h"
+#include <cam_cpas_api.h>
+#include <media/cam_sensor.h>
+#define TPG_HW_VERSION_1_0 0x10000000
+#define TPG_HW_VERSION_1_1 0x10000001
+#define TPG_HW_VERSION_1_3 0x10000003
+
+
+struct tpg_hw;
+
+/**
+ * tpg_hw_ops : tpg hw operations
+ *
+ * @init        : tpg hw layer init
+ * @start       : tpg hw start stream
+ * @stop        : tpg hw stop  stream
+ * @deinit      : tpg hw deinit
+ * @read        : tpg hw read register
+ * @write       : tpg hw write register
+ * @process_cmd : tpg hw process command
+ * @dump_status : dump any status registers
+ */
+struct tpg_hw_ops {
+	int (*init)(struct tpg_hw *hw, void *data);
+	int (*start)(struct tpg_hw *hw, void *data);
+	int (*stop)(struct tpg_hw *hw, void *data);
+	int (*deinit)(struct tpg_hw *hw, void *data);
+	int (*read)(struct tpg_hw *hw, uint32_t  *addr, uint32_t *val);
+	int (*write)(struct tpg_hw *hw, uint32_t *addr, uint32_t *val);
+	int (*process_cmd)(struct tpg_hw *hw, uint32_t cmd, void *arg);
+	int (*dump_status)(struct tpg_hw *hw, void *data);
+};
+
+/**
+ * @brief tpg_vc_slot_info
+ * @slot_id      : slot id of this vc slot
+ * @vc           : virtual channel configured
+ * @stream_count : number of streams in this slot
+ * @head         : head pointing all data types in with this vc
+ */
+struct tpg_vc_slot_info {
+	int    slot_id;
+	int    vc;
+	int    stream_count;
+	struct list_head head;
+};
+
+/**
+ * tpg_hw_info : tpg hw layer info
+ *
+ * @version:  version of tpg hw
+ * @max_vc_channels: max number of virtual channels supported by tpg
+ * @max_dt_channels_per_vc: max dts supported in each vc
+ * @ops:   tpg hw operations
+ */
+struct tpg_hw_info {
+	uint32_t          version;
+	uint32_t          max_vc_channels;
+	uint32_t          max_dt_channels_per_vc;
+	struct tpg_hw_ops *ops;
+};
+
+
+/**
+ * tpg_hw_stream : tpg hw stream
+ *
+ * @stream : tpg stream;
+ * @list   : entry to tpg stream list
+ */
+struct tpg_hw_stream {
+	struct tpg_stream_config_t stream;
+	struct list_head list;
+};
+
+/**
+ * tpg_hw : tpg hw
+ *
+ * @hw_idx        : hw id
+ * @state         : tpg hw state
+ * @cpas_handle   : handle to cpas
+ * @hw_info       : tp hw info
+ * @soc_info      : soc info
+ * @mutex         : lock
+ * @stream_list   : list of tpg stream
+ * @global_config : global configuration
+ */
+struct tpg_hw {
+	uint32_t                   hw_idx;
+	uint32_t                   state;
+	uint32_t                   cpas_handle;
+	uint32_t                   vc_count;
+	struct tpg_hw_info        *hw_info;
+	struct cam_hw_soc_info    *soc_info;
+	struct mutex               mutex;
+	struct tpg_vc_slot_info   *vc_slots;
+	struct tpg_global_config_t global_config;
+};
+
+/**
+ * tpg_hw_acquire_args : tpg hw acquire arguments
+ *
+ * @resource_list  : list of resources to acquire
+ * @count          : number of resources to acquire
+ */
+struct tpg_hw_acquire_args {
+	/* Integer id of resources */
+	uint32_t *resource_list;
+	ssize_t  count;
+};
+
+enum tpg_hw_cmd_t {
+	TPG_HW_CMD_INVALID = 0,
+	TPG_HW_CMD_INIT_CONFIG,
+	TPG_HW_CMD_MAX,
+};
+
+#define TPG_HW_CONFIG_BASE 0x4000
+#define TPG_CONFIG_CTRL    (TPG_HW_CONFIG_BASE + 0)
+#define TPG_CONFIG_VC      (TPG_HW_CONFIG_BASE + 1)
+#define TPG_CONFIG_DT      (TPG_HW_CONFIG_BASE + 2)
+
+/* pixel bit width */
+#define PACK_8_BIT    8
+#define PACK_10_BIT   10
+#define PACK_12_BIT   12
+#define PACK_14_BIT   14
+#define PACK_16_BIT   16
+
+/**
+ * @vc_config_args : arguments for vc config process cmd
+ *
+ * @vc_slot : slot to configure this vc
+ * @num_dts : number of dts in this vc
+ * @stream  : output stream
+ */
+struct vc_config_args {
+	uint32_t vc_slot;
+	uint32_t num_dts;
+	struct tpg_stream_config_t *stream;
+};
+
+/**
+ * dt_config_args : arguments for dt config process cmd
+ *
+ * @vc_slot  : vc slot to configure this dt
+ * @dt_slot  : dt slot to configure this dt
+ * @stream   : stream packet to configure for this dt
+ */
+struct dt_config_args {
+	uint32_t vc_slot;
+	uint32_t dt_slot;
+	struct tpg_stream_config_t *stream;
+};
+
+/**
+ * global_config_args : tpg global config args
+ *
+ * @num_vcs : number of vcs to be configured
+ * @globalconfig: global config cmd
+ */
+struct global_config_args {
+	uint32_t num_vcs;
+	struct tpg_global_config_t *globalconfig;
+};
+
+/**
+ * tpg_hw_initsettings : initial configurations
+ *
+ * @global_config : global configuration
+ * @streamconfigs : array of stream configurations
+ * @num_streams   : number of streams in strea config array
+ */
+struct tpg_hw_initsettings {
+	struct tpg_global_config_t globalconfig;
+	struct tpg_stream_config_t *streamconfigs;
+	uint32_t num_streams;
+};
+
+/**
+ * @brief dump the tpg memory info
+ *
+ * @param soc_info: soc info for soc related info
+ *
+ * @return : 0 on succuss
+ */
+int32_t cam_tpg_mem_dmp(struct cam_hw_soc_info *soc_info);
+
+/**
+ * @brief dump global config command
+ *
+ * @param idx    : hw index
+ * @param global : global config command
+ *
+ * @return       : 0 on success
+ */
+int dump_global_configs(int idx, struct tpg_global_config_t *global);
+
+/**
+ * @brief : dump stream config command
+ *
+ * @param hw_idx: hw index
+ * @param stream_idx: stream index
+ * @param stream: stream config command
+ *
+ * @return : 0 on success
+ */
+int dump_stream_configs(int hw_idx, int stream_idx, struct tpg_stream_config_t *stream);
+
+/**
+ * @brief : dump any hw status registers
+ *
+ * @param hw: tpg hw instance
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_dump_status(struct tpg_hw *hw);
+/**
+ * @brief : start tpg hw stream
+ *
+ * @param hw: tpg hw instance
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_start(struct tpg_hw *hw);
+
+/**
+ * @brief : stop tpg hw stream
+ *
+ * @param hw: tpg hw instance
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_stop(struct tpg_hw *hw);
+
+/**
+ * @brief : tpg hw acquire
+ *
+ * @param hw: tpg hw instance
+ * @param acquire: list of resources to acquire
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_acquire(struct tpg_hw *hw,
+		struct tpg_hw_acquire_args *acquire);
+/**
+ * @brief release tpg hw
+ *
+ * @param hw: tpg hw instance
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_release(struct tpg_hw *hw);
+
+/**
+ * @brief : configure tpg hw
+ *
+ * @param hw: tpg hw instance
+ * @param cmd: configuration command
+ * @param arg: configuration command argument
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_config(struct tpg_hw *hw, enum tpg_hw_cmd_t cmd, void *arg);
+
+/**
+ * @brief : tpg free streams
+ *
+ * @param hw: tpg hw instance
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_free_streams(struct tpg_hw *hw);
+
+/**
+ * @brief : reset the tpg hw instance
+ *
+ * @param hw: tpg hw instance
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_reset(struct tpg_hw *hw);
+
+/**
+ * @brief : tp hw add stream
+ *
+ * @param hw: tpg hw instance
+ * @param cmd: tpg hw command
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_add_stream(struct tpg_hw *hw, struct tpg_stream_config_t *cmd);
+
+/**
+ * @brief : copy global config command
+ *
+ * @param hw: tpg hw instance
+ * @param global: global config command
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_copy_global_config(struct tpg_hw *hw, struct tpg_global_config_t *global);
+
+#endif

+ 283 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_0/tpg_hw_v_1_0.c

@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#include "tpg_hw_v_1_0.h"
+
+enum tpg_hw_encode_format_t {
+	RAW_8_BIT = 1,
+	RAW_10_BIT,
+	RAW_12_BIT,
+	RAW_14_BIT,
+	RAW_16_BIT
+};
+
+static struct cam_tpg_ver1_reg_offset cam_tpg101_reg = {
+	.tpg_hw_version     = 0x0,
+	.tpg_hw_status      = 0x4,
+	.tpg_ctrl           = 0x60,
+	.tpg_vc_cfg0        = 0x64,
+	.tpg_vc_cfg1        = 0x68,
+	.tpg_lfsr_seed      = 0x6c,
+	.tpg_dt_0_cfg_0     = 0x70,
+	.tpg_dt_1_cfg_0     = 0x74,
+	.tpg_dt_2_cfg_0     = 0x78,
+	.tpg_dt_3_cfg_0     = 0x7C,
+	.tpg_dt_0_cfg_1     = 0x80,
+	.tpg_dt_1_cfg_1     = 0x84,
+	.tpg_dt_2_cfg_1     = 0x88,
+	.tpg_dt_3_cfg_1     = 0x8C,
+	.tpg_dt_0_cfg_2     = 0x90,
+	.tpg_dt_1_cfg_2     = 0x94,
+	.tpg_dt_2_cfg_2     = 0x98,
+	.tpg_dt_3_cfg_2     = 0x9C,
+	.tpg_color_bar_cfg  = 0xA0,
+	.tpg_common_gen_cfg = 0xA4,
+	.tpg_vbi_cfg        = 0xA8,
+	.tpg_test_bus_crtl  = 0xF8,
+	.tpg_spare          = 0xFC,
+
+	/* configurations */
+	.major_version     = 1,
+	.minor_version     = 0,
+	.version_incr      = 0,
+	.tpg_en_shift_val  = 0,
+	.tpg_phy_sel_shift_val      = 3,
+	.tpg_num_active_lines_shift = 4,
+	.tpg_fe_pkt_en_shift        = 2,
+	.tpg_fs_pkt_en_shift        = 1,
+	.tpg_line_interleaving_mode_shift = 10,
+	.tpg_num_dts_shift_val            = 8,
+	.tpg_v_blank_cnt_shift            = 12,
+	.tpg_dt_encode_format_shift       = 16,
+	.tpg_payload_mode_color = 0x8,
+	.tpg_split_en_shift     = 5,
+	.top_mux_reg_offset     = 0x1C,
+};
+
+static int configure_global_configs(struct tpg_hw *hw,
+		struct tpg_global_config_t *configs)
+{
+	uint32_t val;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_tpg_ver1_reg_offset *tpg_reg = &cam_tpg101_reg;
+
+	if (hw == NULL) {
+		CAM_ERR(CAM_TPG, "invalid argument");
+		return -EINVAL;
+	}
+	soc_info = hw->soc_info;
+
+	val = cam_io_r_mb(soc_info->reg_map[1].mem_base +
+			tpg_reg->top_mux_reg_offset);
+	val |= (1 << hw->hw_idx);
+
+	cam_io_w_mb(val,
+			soc_info->reg_map[1].mem_base + tpg_reg->top_mux_reg_offset);
+	CAM_INFO(CAM_ISP, "TPG:%d Set top Mux: 0x%x",
+			hw->hw_idx, val);
+
+	val = ((4 - 1) <<
+			tpg_reg->tpg_num_active_lines_shift) |
+		(1 << tpg_reg->tpg_fe_pkt_en_shift) |
+		(1 << tpg_reg->tpg_fs_pkt_en_shift) |
+		(0 << tpg_reg->tpg_phy_sel_shift_val) |
+		(1 << tpg_reg->tpg_en_shift_val);
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl);
+
+	return 0;
+}
+
+static int get_tpg_encode_format(int sw_encode_format)
+{
+	switch (sw_encode_format) {
+	case PACK_8_BIT:
+		return RAW_8_BIT;
+	case PACK_10_BIT:
+		return RAW_10_BIT;
+	case PACK_12_BIT:
+		return RAW_12_BIT;
+	case PACK_14_BIT:
+		return RAW_14_BIT;
+	case PACK_16_BIT:
+		return RAW_16_BIT;
+	}
+	return RAW_8_BIT;
+}
+
+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_ver1_reg_offset *tpg_reg = &cam_tpg101_reg;
+
+	if (hw == NULL) {
+		CAM_ERR(CAM_TPG, "invalid argument");
+		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);
+	/* configure width and height */
+	val = (((stream->stream_dimension.width & 0xFFFF) << 16) |
+			(stream->stream_dimension.height & 0x3FFF));
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_dt_0_cfg_0 + 0x10 * dt_slot);
+
+	/* configure data type */
+	cam_io_w_mb(stream->dt,
+			soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_dt_0_cfg_1 + 0x10 * dt_slot);
+
+	/* configure bpp */
+	val = ((get_tpg_encode_format(stream->pixel_depth) & 0xF) <<
+			tpg_reg->tpg_dt_encode_format_shift) |
+		tpg_reg->tpg_payload_mode_color;
+
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_dt_0_cfg_2 + 0x10 * dt_slot);
+
+	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_ver1_reg_offset *tpg_reg = &cam_tpg101_reg;
+
+	if (hw == NULL) {
+		CAM_ERR(CAM_TPG, "invalid argument");
+		return -EINVAL;
+	}
+	soc_info = hw->soc_info;
+
+	CAM_DBG(CAM_TPG, "Configureing vc : %d at the slot : %d num_dts=%d",
+			stream->vc, vc_slot, num_dts);
+	val = ((num_dts - 1) <<
+			tpg_reg->tpg_num_dts_shift_val) | stream->vc;
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg0);
+
+	cam_io_w_mb(stream->hbi,
+			soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc_cfg1);
+
+	val = (1 << tpg_reg->tpg_split_en_shift);
+	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_common_gen_cfg);
+
+	cam_io_w_mb(stream->vbi,
+			soc_info->reg_map[0].mem_base + tpg_reg->tpg_vbi_cfg);
+
+	return 0;
+}
+
+static int tpg_hw_v_1_0_reset(struct tpg_hw *hw, void *data)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+	uint32_t val;
+	struct cam_tpg_ver1_reg_offset *tpg_reg = &cam_tpg101_reg;
+	if (hw == NULL) {
+		CAM_ERR(CAM_TPG, "invalid argument");
+		return -EINVAL;
+	}
+	soc_info = hw->soc_info;
+
+	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_ctrl);
+
+	/* Reset the TOP tpg mux sel*/
+	val = cam_io_r_mb(soc_info->reg_map[1].mem_base +
+			tpg_reg->top_mux_reg_offset);
+	val &= ~(1 << hw->hw_idx);
+
+	cam_io_w_mb(val,
+			soc_info->reg_map[1].mem_base + tpg_reg->top_mux_reg_offset);
+	CAM_INFO(CAM_TPG, "TPG:%d Reset Top Mux: 0x%x",
+			hw->hw_idx, val);
+
+	return 0;
+}
+
+int tpg_hw_v_1_0_process_cmd(
+	struct tpg_hw *hw,
+	uint32_t       cmd,
+	void          *arg)
+{
+
+	if (hw == NULL) {
+		CAM_ERR(CAM_TPG, "invalid argument");
+		return -EINVAL;
+	}
+	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;
+		}
+		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;
+		}
+		configure_dt(hw,
+			dt_config->vc_slot,
+			dt_config->dt_slot,
+			dt_config->stream);
+	}
+	break;
+	case TPG_CONFIG_CTRL:
+		configure_global_configs(hw, arg);
+	break;
+	default:
+		CAM_ERR(CAM_TPG, "invalid argument");
+		break;
+	}
+	return 0;
+}
+
+int tpg_hw_v_1_0_stop(struct tpg_hw *hw, void *data)
+{
+	CAM_INFO(CAM_TPG, "TPG V1.0 HWL stop");
+	tpg_hw_v_1_0_reset(hw, data);
+	return 0;
+}
+
+int tpg_hw_v_1_0_start(struct tpg_hw *hw, void *data)
+{
+	CAM_DBG(CAM_TPG, "TPG V1.3 HWL start");
+	return 0;
+}
+
+int tpg_hw_v_1_0_init(struct tpg_hw *hw, void *data)
+{
+	CAM_INFO(CAM_TPG, "TPG V1.0 HWL init");
+	tpg_hw_v_1_0_reset(hw, data);
+	return 0;
+}

+ 85 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_0/tpg_hw_v_1_0.h

@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __TPG_HW_V_1_0_H__
+#define __TPG_HW_V_1_0_H__
+
+#include "../tpg_hw.h"
+
+struct cam_tpg_ver1_reg_offset {
+	uint32_t tpg_hw_version;
+	uint32_t tpg_hw_status;
+	uint32_t tpg_ctrl;
+	uint32_t tpg_vc_cfg0;
+	uint32_t tpg_vc_cfg1;
+	uint32_t tpg_lfsr_seed;
+	uint32_t tpg_dt_0_cfg_0;
+	uint32_t tpg_dt_1_cfg_0;
+	uint32_t tpg_dt_2_cfg_0;
+	uint32_t tpg_dt_3_cfg_0;
+	uint32_t tpg_dt_0_cfg_1;
+	uint32_t tpg_dt_1_cfg_1;
+	uint32_t tpg_dt_2_cfg_1;
+	uint32_t tpg_dt_3_cfg_1;
+	uint32_t tpg_dt_0_cfg_2;
+	uint32_t tpg_dt_1_cfg_2;
+	uint32_t tpg_dt_2_cfg_2;
+	uint32_t tpg_dt_3_cfg_2;
+	uint32_t tpg_color_bar_cfg;
+	uint32_t tpg_common_gen_cfg;
+	uint32_t tpg_vbi_cfg;
+	uint32_t tpg_test_bus_crtl;
+	uint32_t tpg_spare;
+
+	/* configurations */
+	uint32_t major_version;
+	uint32_t minor_version;
+	uint32_t version_incr;
+	uint32_t tpg_en_shift_val;
+	uint32_t tpg_phy_sel_shift_val;
+	uint32_t tpg_num_active_lines_shift;
+	uint32_t tpg_fe_pkt_en_shift;
+	uint32_t tpg_fs_pkt_en_shift;
+	uint32_t tpg_line_interleaving_mode_shift;
+	uint32_t tpg_num_dts_shift_val;
+	uint32_t tpg_v_blank_cnt_shift;
+	uint32_t tpg_dt_encode_format_shift;
+	uint32_t tpg_payload_mode_color;
+	uint32_t tpg_split_en_shift;
+	uint32_t top_mux_reg_offset;
+};
+
+/**
+ * @brief  : initialize the tpg hw v 1.0
+ *
+ * @param hw: tpg hw instance
+ * @param data: initialize data
+ *
+ * @return : return 0 on success
+ */
+int tpg_hw_v_1_0_init(struct tpg_hw *hw, void *data);
+
+/**
+ * @brief : start tpg hw v 1.0
+ *
+ * @param hw: tpg hw instance
+ * @param data: start argument
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_v_1_0_start(struct tpg_hw *hw, void *data);
+
+/**
+ * @brief : stop tpg hw
+ *
+ * @param hw: tpg hw instance
+ * @param data: arguments to stop tpg hw 1.0
+ *
+ * @return : 0 on success
+ */
+int tpg_hw_v_1_0_stop(struct tpg_hw *hw, void *data);
+
+
+#endif

+ 25 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_0/tpg_hw_v_1_0_data.h

@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __TPG_HW_V_1_0_DATA_H__
+#define __TPG_HW_V_1_0_DATA_H__
+
+#include "../tpg_hw.h"
+#include "tpg_hw_v_1_0.h"
+
+struct tpg_hw_ops tpg_hw_v_1_0_ops = {
+	.start = tpg_hw_v_1_0_start,
+	.stop  = tpg_hw_v_1_0_stop,
+	.init = tpg_hw_v_1_0_init,
+};
+
+struct tpg_hw_info tpg_v_1_0_hw_info = {
+	.version = TPG_HW_VERSION_1_0,
+	.max_vc_channels = 2,
+	.max_dt_channels_per_vc = 4,
+	.ops = &tpg_hw_v_1_0_ops,
+};
+
+#endif

+ 486 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3.c

@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#include "tpg_hw_v_1_3.h"
+
+enum tpg_hw_v_1_3_encode_fomat_t {
+	RAW_8_BIT = 1,
+	RAW_10_BIT,
+	RAW_12_BIT,
+	RAW_14_BIT,
+	RAW_16_BIT
+};
+
+static struct cam_tpg_ver_1_3_reg_offset cam_tpg103_reg = {
+	.tpg_hw_version        = 0x0,
+	.tpg_hw_status         = 0x4,
+	.tpg_ctrl              = 0x64,
+	.tpg_vc0_cfg0          = 0x68,
+	.tpg_vc0_lfsr_seed     = 0x6C,
+	.tpg_vc0_hbi_cfg       = 0x70,
+	.tpg_vc0_vbi_cfg       = 0x74,
+	.tpg_vc0_color_bar_cfg = 0x78,
+	.tpg_vc0_dt_0_cfg_0   = 0x7C,
+	.tpg_vc0_dt_0_cfg_1   = 0x80,
+	.tpg_vc0_dt_0_cfg_2   = 0x84,
+	.tpg_vc0_dt_1_cfg_0   = 0x88,
+	.tpg_vc0_dt_1_cfg_1   = 0x8C,
+	.tpg_vc0_dt_1_cfg_2   = 0x90,
+	.tpg_vc0_dt_2_cfg_0   = 0x94,
+	.tpg_vc0_dt_2_cfg_1   = 0x98,
+	.tpg_vc0_dt_2_cfg_2   = 0x9C,
+	.tpg_vc0_dt_3_cfg_0   = 0xA0,
+	.tpg_vc0_dt_3_cfg_1   = 0xA4,
+	.tpg_vc0_dt_3_cfg_2   = 0xA8,
+
+	.tpg_vc1_cfg0          = 0xC8,
+	.tpg_vc1_lfsr_seed     = 0xCC,
+	.tpg_vc1_hbi_cfg       = 0xD0,
+	.tpg_vc1_vbi_cfg       = 0xD4,
+	.tpg_vc1_color_bar_cfg = 0xD8,
+	.tpg_vc1_dt_0_cfg_0   = 0xDC,
+	.tpg_vc1_dt_0_cfg_1   = 0xE0,
+	.tpg_vc1_dt_0_cfg_2   = 0xE4,
+	.tpg_vc1_dt_1_cfg_0   = 0xE8,
+	.tpg_vc1_dt_1_cfg_1   = 0xEC,
+	.tpg_vc1_dt_1_cfg_2   = 0xF0,
+	.tpg_vc1_dt_2_cfg_0   = 0xF4,
+	.tpg_vc1_dt_2_cfg_1   = 0xF8,
+	.tpg_vc1_dt_2_cfg_2   = 0xFC,
+	.tpg_vc1_dt_3_cfg_0   = 0x100,
+	.tpg_vc1_dt_3_cfg_1   = 0x104,
+	.tpg_vc1_dt_3_cfg_2   = 0x108,
+
+	.tpg_vc2_cfg0          = 0x128,
+	.tpg_vc2_lfsr_seed     = 0x12C,
+	.tpg_vc2_hbi_cfg       = 0x130,
+	.tpg_vc2_vbi_cfg       = 0x134,
+	.tpg_vc2_color_bar_cfg = 0x138,
+	.tpg_vc2_dt_0_cfg_0   = 0x13C,
+	.tpg_vc2_dt_0_cfg_1   = 0x140,
+	.tpg_vc2_dt_0_cfg_2   = 0x144,
+	.tpg_vc2_dt_1_cfg_0   = 0x148,
+	.tpg_vc2_dt_1_cfg_1   = 0x14C,
+	.tpg_vc2_dt_1_cfg_2   = 0x150,
+	.tpg_vc2_dt_2_cfg_0   = 0x154,
+	.tpg_vc2_dt_2_cfg_1   = 0x158,
+	.tpg_vc2_dt_2_cfg_2   = 0x15C,
+	.tpg_vc2_dt_3_cfg_0   = 0x160,
+	.tpg_vc2_dt_3_cfg_1   = 0x164,
+	.tpg_vc2_dt_3_cfg_2   = 0x168,
+
+	.tpg_vc3_cfg0          = 0x188,
+	.tpg_vc3_lfsr_seed     = 0x18C,
+	.tpg_vc3_hbi_cfg       = 0x190,
+	.tpg_vc3_vbi_cfg       = 0x194,
+	.tpg_vc3_color_bar_cfg = 0x198,
+	.tpg_vc3_dt_0_cfg_0   = 0x19C,
+	.tpg_vc3_dt_0_cfg_1   = 0x1A0,
+	.tpg_vc3_dt_0_cfg_2   = 0x1A4,
+	.tpg_vc3_dt_1_cfg_0   = 0x1A8,
+	.tpg_vc3_dt_1_cfg_1   = 0x1AC,
+	.tpg_vc3_dt_1_cfg_2   = 0x1B0,
+	.tpg_vc3_dt_2_cfg_0   = 0x1B4,
+	.tpg_vc3_dt_2_cfg_1   = 0x1B8,
+	.tpg_vc3_dt_2_cfg_2   = 0x1BC,
+	.tpg_vc3_dt_3_cfg_0   = 0x1C0,
+	.tpg_vc3_dt_3_cfg_1   = 0x1C4,
+	.tpg_vc3_dt_3_cfg_2   = 0x1C8,
+	.tpg_throttle          = 0x1CC,
+	.tpg_top_irq_status    = 0x1E0,
+	.tpg_top_irq_mask      = 0x1E4,
+	.tpg_top_irq_clear     = 0x1E8,
+	.tpg_top_irq_set       = 0x1EC,
+	.tpg_top_irq_cmd       = 0x1F0,
+	.tpg_top_clear         = 0x1F4,
+	.tpg_test_bus_crtl     = 0x1F8,
+	.tpg_spare             = 0x1FC,
+
+	/* configurations */
+	.major_version = 2,
+	.minor_version = 0,
+	.version_incr = 0,
+	.tpg_en_shift_val = 0,
+	.tpg_cphy_dphy_sel_shift_val = 3,
+	.tpg_num_active_lanes_shift = 4,
+	.tpg_fe_pkt_en_shift = 2,
+	.tpg_fs_pkt_en_shift = 1,
+	.tpg_line_interleaving_mode_shift = 10,
+	.tpg_num_frames_shift_val = 16,
+	.tpg_num_dts_shift_val = 8,
+	.tpg_v_blank_cnt_shift = 12,
+	.tpg_dt_encode_format_shift = 20,
+	.tpg_payload_mode_color = 0x8,
+	.tpg_split_en_shift = 4,
+	.top_mux_reg_offset = 0x1C,
+	.tpg_vc_dt_pattern_id_shift = 6,
+	.tpg_num_active_vcs_shift = 30,
+	.tpg_color_bar_qcfa_en_shift = 3,
+	.tpg_color_bar_qcfa_rotate_period_shift = 8,
+};
+
+#define  FRAME_INTERLEAVE  0x0
+#define  LINE_INTERLEAVE   0x1
+#define  SHDR_INTERLEAVE   0x2
+#define  SPARSE_PD_INTERLEAVE 0x3
+static int get_tpg_vc_dt_pattern_id(
+		enum tpg_interleaving_format_t vc_dt_pattern)
+{
+	switch (vc_dt_pattern) {
+	case TPG_INTERLEAVING_FORMAT_INVALID:
+	case TPG_INTERLEAVING_FORMAT_MAX:
+	case TPG_INTERLEAVING_FORMAT_FRAME:
+		return FRAME_INTERLEAVE;
+	case TPG_INTERLEAVING_FORMAT_LINE:
+		return LINE_INTERLEAVE;
+	case TPG_INTERLEAVING_FORMAT_SHDR:
+		return SHDR_INTERLEAVE;
+	case TPG_INTERLEAVING_FORMAT_SPARSE_PD:
+		return SPARSE_PD_INTERLEAVE;
+
+	}
+	return FRAME_INTERLEAVE;
+}
+
+static int configure_global_configs(
+	struct tpg_hw *hw,
+	int num_vcs,
+	struct tpg_global_config_t *configs)
+{
+	uint32_t val, phy_type = 0;
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_tpg_ver_1_3_reg_offset *tpg_reg = &cam_tpg103_reg;
+
+	if (!hw) {
+		CAM_ERR(CAM_TPG, "invalid params");
+		return -EINVAL;
+	}
+	soc_info = hw->soc_info;
+
+	if (configs->phy_type == TPG_PHY_TYPE_CPHY)
+		phy_type = 1;
+
+	if (num_vcs <= 0) {
+		CAM_ERR(CAM_TPG, "Invalid vc count");
+		return -EINVAL;
+	}
+
+	val = configs->skip_pattern;
+	cam_io_w_mb(val,
+		soc_info->reg_map[0].mem_base + tpg_reg->tpg_throttle);
+	CAM_DBG(CAM_TPG, "tpg[%d] throttle=0x%x", hw->hw_idx, val);
+
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_top_irq_mask);
+
+
+	val = ((num_vcs - 1) <<
+			(tpg_reg->tpg_num_active_vcs_shift) |
+			(configs->lane_count - 1) <<
+			tpg_reg->tpg_num_active_lanes_shift) |
+		get_tpg_vc_dt_pattern_id(configs->interleaving_format) <<
+		(tpg_reg->tpg_vc_dt_pattern_id_shift) |
+		(phy_type << tpg_reg->tpg_cphy_dphy_sel_shift_val) |
+		(1 << tpg_reg->tpg_en_shift_val);
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl);
+	CAM_DBG(CAM_TPG, "tpg[%d] tpg_ctrl=0x%x", hw->hw_idx, val);
+
+	return 0;
+}
+
+static int get_tpg_encode_format(int sw_encode_format)
+{
+	switch (sw_encode_format) {
+	case PACK_8_BIT:
+		return RAW_8_BIT;
+	case PACK_10_BIT:
+		return RAW_10_BIT;
+	case PACK_12_BIT:
+		return RAW_12_BIT;
+	case PACK_14_BIT:
+		return RAW_14_BIT;
+	case PACK_16_BIT:
+		return RAW_16_BIT;
+	}
+	return RAW_8_BIT;
+}
+
+#define  INCREMENTING       0x0
+#define  ALTERNATING_55_AA  0x1
+#define  RANDOM             0x4
+#define  USER_SPECIFIED     0x5
+#define  COLOR_BARS         0x8
+
+static int get_tpg_payload_mode(enum tpg_pattern_t pattern)
+{
+	switch (pattern) {
+	case TPG_PATTERN_INVALID:
+	case TPG_PATTERN_REAL_IMAGE:
+	case TPG_PATTERN_COLOR_BAR:
+		return COLOR_BARS;
+	case TPG_PATTERN_RANDOM_PIXL:
+	case TPG_PATTERN_RANDOM_INCREMENTING_PIXEL:
+		return RANDOM;
+	case TPG_PATTERN_ALTERNATING_55_AA:
+		return ALTERNATING_55_AA;
+	case TPG_PATTERN_ALTERNATING_USER_DEFINED:
+		return USER_SPECIFIED;
+	default:
+		return COLOR_BARS;
+	}
+	return COLOR_BARS;
+}
+
+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_3_reg_offset *tpg_reg = &cam_tpg103_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_vc0_dt_0_cfg_0 +
+			(0x60 * vc_slot) + (dt_slot * 0x0c));
+	CAM_DBG(CAM_TPG, "TPG[%d] vc%d_dt%d_cfg_0=0x%x",
+			hw->hw_idx,
+			vc_slot, dt_slot, val);
+
+	cam_io_w_mb(stream->dt,
+			soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_dt_0_cfg_1 +
+			(0x60 * vc_slot) + (dt_slot * 0x0c));
+	CAM_DBG(CAM_TPG, "TPG[%d] vc%d_dt%d_cfg_1=0x%x",
+			hw->hw_idx,
+			vc_slot, dt_slot, stream->dt);
+
+	val = ((get_tpg_encode_format(stream->pixel_depth) & 0xF) <<
+			tpg_reg->tpg_dt_encode_format_shift) |
+		get_tpg_payload_mode(stream->pattern_type);
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_dt_0_cfg_2 +
+			(0x60 * vc_slot) + (dt_slot * 0x0c));
+	CAM_DBG(CAM_TPG, "TPG[%d] vc%d_dt%d_cfg_2=0x%x",
+			hw->hw_idx,
+			vc_slot, dt_slot, 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_3_reg_offset *tpg_reg = &cam_tpg103_reg;
+	if (!hw) {
+		CAM_ERR(CAM_TPG, "invalid params");
+		return -EINVAL;
+	}
+
+	soc_info = hw->soc_info;
+	/* Use CFA pattern here */
+	if (stream->output_format == TPG_IMAGE_FORMAT_QCFA)
+		val |= (1 << tpg_reg->tpg_color_bar_qcfa_en_shift);
+
+	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_color_bar_qcfa_rotate_period_shift);
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_color_bar_cfg + (0x60 * vc_slot));
+	CAM_DBG(CAM_TPG, "TPG[%d] vc%d_color_bar_cfg=0x%x",
+			hw->hw_idx,
+			vc_slot, val);
+
+	val = stream->hbi;
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_hbi_cfg + (0x60 * vc_slot));
+	CAM_DBG(CAM_TPG, "TPG[%d] vc%d_hbi_cfg=0x%x",
+			hw->hw_idx,
+			vc_slot, val);
+
+	val = stream->vbi;
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_vbi_cfg + (0x60 * vc_slot));
+	CAM_DBG(CAM_TPG, "TPG[%d] vc%d_vbi_cgf=0x%x",
+			hw->hw_idx,
+			vc_slot, val);
+
+	cam_io_w_mb(0x12345678,
+		soc_info->reg_map[0].mem_base +
+		tpg_reg->tpg_vc0_lfsr_seed + (0x60 * vc_slot));
+
+	val = ((0 << tpg_reg->tpg_num_frames_shift_val) |
+		((num_dts-1) <<	 tpg_reg->tpg_num_dts_shift_val) |
+		stream->vc);
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_cfg0 + (0x60 * vc_slot));
+	CAM_DBG(CAM_TPG, "TPG[%d] vc%d_cfg0=0x%x",
+			hw->hw_idx,
+			vc_slot, val);
+
+	return 0;
+}
+
+static int tpg_hw_v_1_3_reset(
+	struct tpg_hw *hw, void *data)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+	uint32_t val;
+	struct cam_tpg_ver_1_3_reg_offset *tpg_reg = &cam_tpg103_reg;
+	if (!hw) {
+		CAM_ERR(CAM_TPG, "invalid params");
+		return -EINVAL;
+	}
+
+	soc_info = hw->soc_info;
+
+	/* Clear out tpg_ctrl and irqs before reset */
+	cam_io_w_mb(0, soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl);
+
+	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_top_irq_mask);
+
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_top_irq_clear);
+
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_top_irq_cmd);
+
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_top_clear);
+
+	/* 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_3_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;
+	}
+	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_3_start(struct tpg_hw *hw, void *data)
+{
+	CAM_DBG(CAM_TPG, "TPG V1.3 HWL start");
+	return 0;
+}
+
+int tpg_hw_v_1_3_stop(struct tpg_hw *hw, void *data)
+{
+	CAM_DBG(CAM_TPG, "TPG V1.3 HWL stop");
+	tpg_hw_v_1_3_reset(hw, data);
+	return 0;
+}
+
+int tpg_hw_v_1_3_dump_status(struct tpg_hw *hw, void *data)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+	uint32_t val;
+	struct cam_tpg_ver_1_3_reg_offset *tpg_reg = &cam_tpg103_reg;
+
+	if (!hw) {
+		CAM_ERR(CAM_TPG, "invalid params");
+		return -EINVAL;
+	}
+
+	soc_info = hw->soc_info;
+	CAM_DBG(CAM_TPG, "TPG V1.3 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);
+	val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_top_irq_status);
+	CAM_INFO(CAM_TPG, "TPG[%d] TPG HW irq status: 0x%x started",
+			hw->hw_idx, val);
+
+	return 0;
+}
+
+int tpg_hw_v_1_3_init(struct tpg_hw *hw, void *data)
+{
+	CAM_DBG(CAM_TPG, "TPG V1.3 HWL init");
+	tpg_hw_v_1_3_reset(hw, data);
+	return 0;
+}

+ 172 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3.h

@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __TPG_HW_V_1_3_H__
+#define __TPG_HW_V_1_3_H__
+
+#include "../tpg_hw.h"
+
+struct cam_tpg_ver_1_3_reg_offset {
+	uint32_t tpg_hw_version;
+	uint32_t tpg_hw_status;
+	uint32_t tpg_ctrl;
+	uint32_t tpg_vc0_cfg0;
+	uint32_t tpg_vc0_lfsr_seed;
+	uint32_t tpg_vc0_hbi_cfg;
+	uint32_t tpg_vc0_vbi_cfg;
+	uint32_t tpg_vc0_color_bar_cfg;
+	uint32_t tpg_vc0_dt_0_cfg_0;
+	uint32_t tpg_vc0_dt_0_cfg_1;
+	uint32_t tpg_vc0_dt_0_cfg_2;
+	uint32_t tpg_vc0_dt_1_cfg_0;
+	uint32_t tpg_vc0_dt_1_cfg_1;
+	uint32_t tpg_vc0_dt_1_cfg_2;
+	uint32_t tpg_vc0_dt_2_cfg_0;
+	uint32_t tpg_vc0_dt_2_cfg_1;
+	uint32_t tpg_vc0_dt_2_cfg_2;
+	uint32_t tpg_vc0_dt_3_cfg_0;
+	uint32_t tpg_vc0_dt_3_cfg_1;
+	uint32_t tpg_vc0_dt_3_cfg_2;
+
+	uint32_t tpg_vc1_cfg0;
+	uint32_t tpg_vc1_lfsr_seed;
+	uint32_t tpg_vc1_hbi_cfg;
+	uint32_t tpg_vc1_vbi_cfg;
+	uint32_t tpg_vc1_color_bar_cfg;
+	uint32_t tpg_vc1_dt_0_cfg_0;
+	uint32_t tpg_vc1_dt_0_cfg_1;
+	uint32_t tpg_vc1_dt_0_cfg_2;
+	uint32_t tpg_vc1_dt_1_cfg_0;
+	uint32_t tpg_vc1_dt_1_cfg_1;
+	uint32_t tpg_vc1_dt_1_cfg_2;
+	uint32_t tpg_vc1_dt_2_cfg_0;
+	uint32_t tpg_vc1_dt_2_cfg_1;
+	uint32_t tpg_vc1_dt_2_cfg_2;
+	uint32_t tpg_vc1_dt_3_cfg_0;
+	uint32_t tpg_vc1_dt_3_cfg_1;
+	uint32_t tpg_vc1_dt_3_cfg_2;
+
+	uint32_t tpg_vc2_cfg0;
+	uint32_t tpg_vc2_lfsr_seed;
+	uint32_t tpg_vc2_hbi_cfg;
+	uint32_t tpg_vc2_vbi_cfg;
+	uint32_t tpg_vc2_color_bar_cfg;
+	uint32_t tpg_vc2_dt_0_cfg_0;
+	uint32_t tpg_vc2_dt_0_cfg_1;
+	uint32_t tpg_vc2_dt_0_cfg_2;
+	uint32_t tpg_vc2_dt_1_cfg_0;
+	uint32_t tpg_vc2_dt_1_cfg_1;
+	uint32_t tpg_vc2_dt_1_cfg_2;
+	uint32_t tpg_vc2_dt_2_cfg_0;
+	uint32_t tpg_vc2_dt_2_cfg_1;
+	uint32_t tpg_vc2_dt_2_cfg_2;
+	uint32_t tpg_vc2_dt_3_cfg_0;
+	uint32_t tpg_vc2_dt_3_cfg_1;
+	uint32_t tpg_vc2_dt_3_cfg_2;
+
+	uint32_t tpg_vc3_cfg0;
+	uint32_t tpg_vc3_lfsr_seed;
+	uint32_t tpg_vc3_hbi_cfg;
+	uint32_t tpg_vc3_vbi_cfg;
+	uint32_t tpg_vc3_color_bar_cfg;
+	uint32_t tpg_vc3_dt_0_cfg_0;
+	uint32_t tpg_vc3_dt_0_cfg_1;
+	uint32_t tpg_vc3_dt_0_cfg_2;
+	uint32_t tpg_vc3_dt_1_cfg_0;
+	uint32_t tpg_vc3_dt_1_cfg_1;
+	uint32_t tpg_vc3_dt_1_cfg_2;
+	uint32_t tpg_vc3_dt_2_cfg_0;
+	uint32_t tpg_vc3_dt_2_cfg_1;
+	uint32_t tpg_vc3_dt_2_cfg_2;
+	uint32_t tpg_vc3_dt_3_cfg_0;
+	uint32_t tpg_vc3_dt_3_cfg_1;
+	uint32_t tpg_vc3_dt_3_cfg_2;
+	uint32_t tpg_throttle;
+	uint32_t tpg_top_irq_status;
+	uint32_t tpg_top_irq_mask;
+	uint32_t tpg_top_irq_clear;
+	uint32_t tpg_top_irq_set;
+	uint32_t tpg_top_irq_cmd;
+	uint32_t tpg_top_clear;
+	uint32_t tpg_test_bus_crtl;
+	uint32_t tpg_spare;
+
+	/* configurations */
+	uint32_t major_version;
+	uint32_t minor_version;
+	uint32_t version_incr;
+	uint32_t tpg_en_shift_val;
+	uint32_t tpg_cphy_dphy_sel_shift_val;
+	uint32_t tpg_num_active_lanes_shift;
+	uint32_t tpg_fe_pkt_en_shift;
+	uint32_t tpg_fs_pkt_en_shift;
+	uint32_t tpg_line_interleaving_mode_shift;
+	uint32_t tpg_num_frames_shift_val;
+	uint32_t tpg_num_dts_shift_val;
+	uint32_t tpg_v_blank_cnt_shift;
+	uint32_t tpg_dt_encode_format_shift;
+	uint32_t tpg_payload_mode_color;
+	uint32_t tpg_split_en_shift;
+	uint32_t top_mux_reg_offset;
+	uint32_t tpg_vc_dt_pattern_id_shift;
+	uint32_t tpg_num_active_vcs_shift;
+	uint32_t tpg_color_bar_qcfa_en_shift;
+	uint32_t tpg_color_bar_qcfa_rotate_period_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_3_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_3_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_3_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_3_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_3_dump_status(struct tpg_hw *hw, void *data);
+
+#endif

+ 27 - 0
drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3_data.h

@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __TPG_HW_V_1_3_DATA_H__
+#define __TPG_HW_V_1_3_DATA_H__
+
+#include "../tpg_hw.h"
+#include "tpg_hw_v_1_3.h"
+
+struct tpg_hw_ops tpg_hw_v_1_3_ops = {
+	.start = tpg_hw_v_1_3_start,
+	.stop  = tpg_hw_v_1_3_stop,
+	.init = tpg_hw_v_1_3_init,
+	.process_cmd = tpg_hw_v_1_3_process_cmd,
+	.dump_status = tpg_hw_v_1_3_dump_status,
+};
+
+struct tpg_hw_info tpg_v_1_3_hw_info = {
+	.version = TPG_HW_VERSION_1_3,
+	.max_vc_channels = 4,
+	.max_dt_channels_per_vc = 4,
+	.ops = &tpg_hw_v_1_3_ops,
+};
+
+#endif

+ 3 - 0
drivers/cam_utils/cam_debug_util.c

@@ -227,6 +227,9 @@ const char *cam_get_module_name(unsigned long long module_id)
 	case CAM_PRESIL_CORE:
 		name = "CAM-CORE-PRESIL";
 		break;
+	case CAM_TPG:
+		name = "CAM-TPG";
+		break;
 	default:
 		name = "CAM";
 		break;

+ 1 - 0
drivers/cam_utils/cam_debug_util.h

@@ -43,6 +43,7 @@
 #define CAM_SFE           BIT_ULL(30)
 #define CAM_CRE           BIT_ULL(31)
 #define CAM_PRESIL_CORE   BIT_ULL(32)
+#define CAM_TPG           BIT_ULL(33)
 
 /* Log level types */
 #define CAM_TYPE_TRACE      (1 << 0)

+ 2 - 0
drivers/camera_main.c

@@ -23,6 +23,7 @@
 #include "cam_csiphy_dev.h"
 #include "cam_eeprom_dev.h"
 #include "cam_ois_dev.h"
+#include "cam_tpg_dev.h"
 
 #if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2) || \
 	IS_REACHABLE(CONFIG_LEDS_QTI_FLASH)
@@ -105,6 +106,7 @@ static const struct camera_submodule_component camera_sensor[] = {
 	{&cam_res_mgr_init, &cam_res_mgr_exit},
 	{&cam_cci_init_module, &cam_cci_exit_module},
 	{&cam_csiphy_init_module, &cam_csiphy_exit_module},
+	{&cam_tpg_init_module, &cam_tpg_exit_module},
 	{&cam_actuator_driver_init, &cam_actuator_driver_exit},
 	{&cam_sensor_driver_init, &cam_sensor_driver_exit},
 	{&cam_eeprom_driver_init, &cam_eeprom_driver_exit},

+ 2 - 0
drivers/camera_main.h

@@ -34,6 +34,7 @@ extern struct platform_driver cam_actuator_platform_driver;
 extern struct platform_driver cam_sensor_platform_driver;
 extern struct platform_driver cam_eeprom_platform_driver;
 extern struct platform_driver cam_ois_platform_driver;
+extern struct platform_driver cam_tpg_driver;
 #if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2) || \
 	IS_REACHABLE(CONFIG_LEDS_QTI_FLASH)
 extern struct platform_driver cam_flash_platform_driver;
@@ -104,6 +105,7 @@ static struct platform_driver *const cam_component_drivers[] = {
 	&cam_sensor_platform_driver,
 	&cam_eeprom_platform_driver,
 	&cam_ois_platform_driver,
+	&cam_tpg_driver,
 #if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2) || \
 	IS_REACHABLE(CONFIG_LEDS_QTI_FLASH)
 	&cam_flash_platform_driver,

+ 1 - 0
include/uapi/camera/media/cam_req_mgr.h

@@ -33,6 +33,7 @@
 #define CAM_OPE_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 15)
 #define CAM_TFE_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 16)
 #define CAM_CRE_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 17)
+#define CAM_TPG_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 18)
 
 /* cam_req_mgr hdl info */
 #define CAM_REQ_MGR_HDL_IDX_POS           8

+ 239 - 0
include/uapi/camera/media/cam_sensor.h

@@ -78,6 +78,13 @@ enum camera_sensor_wait_op_code {
 	CAMERA_SENSOR_WAIT_OP_MAX,
 };
 
+enum cam_tpg_packet_opcodes {
+	CAM_TPG_PACKET_OPCODE_INVALID = 0,
+	CAM_TPG_PACKET_OPCODE_INITIAL_CONFIG,
+	CAM_TPG_PACKET_OPCODE_NOP,
+	CAM_TPG_PACKET_OPCODE_MAX,
+};
+
 enum cam_sensor_packet_opcodes {
 	CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON,
 	CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE,
@@ -91,6 +98,78 @@ enum cam_sensor_packet_opcodes {
 	CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP = 127
 };
 
+enum tpg_command_type_t {
+	TPG_CMD_TYPE_INVALID = 0,
+	TPG_CMD_TYPE_GLOBAL_CONFIG,
+	TPG_CMD_TYPE_STREAM_CONFIG,
+	TPG_CMD_TYPE_ILLUMINATION_CONFIG,
+	TPG_CMD_TYPE_MAX,
+};
+
+enum tpg_pattern_t {
+	TPG_PATTERN_INVALID = 0,
+	TPG_PATTERN_REAL_IMAGE,
+	TPG_PATTERN_RANDOM_PIXL,
+	TPG_PATTERN_RANDOM_INCREMENTING_PIXEL,
+	TPG_PATTERN_COLOR_BAR,
+	TPG_PATTERN_ALTERNATING_55_AA,
+	TPG_PATTERN_ALTERNATING_USER_DEFINED,
+	TPG_PATTERN_MAX,
+};
+
+enum tpg_color_bar_mode_t {
+	TPG_COLOR_BAR_MODE_INVALID = 0,
+	TPG_COLOR_BAR_MODE_NORMAL,
+	TPG_COLOR_BAR_MODE_SPLIT,
+	TPG_COLOR_BAR_MODE_ROTATING,
+	TPG_COLOR_BAR_MODE_MAX,
+};
+
+enum tpg_image_format_t {
+	TPG_IMAGE_FORMAT_INVALID = 0,
+	TPG_IMAGE_FORMAT_BAYER,
+	TPG_IMAGE_FORMAT_QCFA,
+	TPG_IMAGE_FORMAT_YUV,
+	TPG_IMAGE_FORMAT_JPEG,
+	TPG_IMAGE_FORMAT_MAX,
+};
+
+enum tpg_phy_type_t {
+	TPG_PHY_TYPE_INVALID = 0,
+	TPG_PHY_TYPE_DPHY,
+	TPG_PHY_TYPE_CPHY,
+	TPG_PHY_TYPE_MAX,
+};
+
+enum tpg_interleaving_format_t {
+	TPG_INTERLEAVING_FORMAT_INVALID = 0,
+	TPG_INTERLEAVING_FORMAT_FRAME,
+	TPG_INTERLEAVING_FORMAT_LINE,
+	TPG_INTERLEAVING_FORMAT_SHDR,
+	TPG_INTERLEAVING_FORMAT_SPARSE_PD,
+	TPG_INTERLEAVING_FORMAT_MAX,
+};
+
+enum tpg_shutter_t {
+	TPG_SHUTTER_TYPE_INVALID = 0,
+	TPG_SHUTTER_TYPE_ROLLING,
+	TPG_SHUTTER_TYPE_GLOBAL,
+	TPG_SHUTTER_TYPE_MAX,
+};
+
+enum tpg_stream_t {
+	TPG_STREAM_TYPE_INVALID = 0,
+	TPG_STREAM_TYPE_IMAGE,
+	TPG_STREAM_TYPE_PDAF,
+	TPG_STREAM_TYPE_META,
+	TPG_STREAM_TYPE_MAX,
+};
+
+enum tpg_cfa_arrangement_t {
+	TPG_CFA_ARRANGEMENT_TYPE_INVALID = 0,
+	TPG_CFA_ARRANGEMENT_TYPE_MAX,
+};
+
 /**
  * struct cam_sensor_query_cap - capabilities info for sensor
  *
@@ -168,6 +247,24 @@ struct cam_ois_query_cap_t {
 	__u16            reserved;
 } __attribute__((packed));
 
+/**
+ * struct cam_tpg_query_cap - capabilities info for tpg
+ *
+ * @slot_info        :  Indicates about the slotId or cell Index
+ * @version          :  TPG version , in msb
+ * @reserved         :  Reserved for future Use
+ * @secure_camera    :  Camera is in secure/Non-secure mode
+ * @csiphy_slot_id   :  CSIphy slot id which connected to sensor
+ */
+struct cam_tpg_query_cap {
+	__u32        slot_info;
+	__u32        version;
+	__u32        secure_camera;
+	__u32        csiphy_slot_id;
+	__u32        reserved[2];
+} __attribute__((packed));
+
+
 /**
  * struct cam_cmd_i2c_info - Contains slave I2C related info
  *
@@ -486,6 +583,23 @@ struct cam_sensor_acquire_dev {
 	__u64    info_handle;
 } __attribute__((packed));
 
+/**
+ * cam_tpg_acquire_dev : Updates tpg acuire cmd
+ * @device_handle  :    Updates device handle
+ * @session_handle :    Session handle for acquiring device
+ * @handle_type    :    Resource handle type
+ * @reserved
+ * @info_handle    :    Handle to additional info
+ *                      needed for sensor sub modules
+ */
+struct cam_tpg_acquire_dev {
+	__u32    session_handle;
+	__u32    device_handle;
+	__u32    handle_type;
+	__u32    reserved;
+	__u64    info_handle;
+} __attribute__((packed));
+
 /**
  * cam_sensor_streamon_dev : StreamOn command for the sensor
  * @session_handle :    Session handle for acquiring device
@@ -503,6 +617,131 @@ struct cam_sensor_streamon_dev {
 	__u64    info_handle;
 } __attribute__((packed));
 
+
+/**
+ * stream_dimension : Stream dimension
+ *
+ * @left   : left pixel locaiton of stream
+ * @top    : top  pixel location of stream
+ * @width  : width of the image stream
+ * @height : Height of the image stream
+ */
+struct stream_dimension {
+	uint32_t left;
+	uint32_t top;
+	uint32_t width;
+	uint32_t height;
+};
+
+/**
+ * tpg_command_header_t : tpg command common header
+ *
+ * @cmd_type    : command type
+ * @size        : size of the command including header
+ * @cmd_version : version of the command associated
+ */
+struct tpg_command_header_t {
+	__u32 cmd_type;
+	ssize_t  size;
+	uint32_t cmd_version;
+} __attribute__((packed));
+
+/**
+ * tpg_global_config_t : global configuration command structure
+ *
+ * @header              : common header
+ * @phy_type            : phy type , cpy , dphy
+ * @lane_count          : number of lanes used
+ * @interleaving_format : interleaving format used
+ * @phy_mode            : phy mode of operation
+ * @shutter_type        : shutter type
+ * @mode                : if any specific mode needs to configured
+ * @hbi                 : horizontal blanking intervel
+ * @vbi                 : vertical blanking intervel
+ * @skip_pattern        : frame skip pattern
+ * @tpg_clock           : tpg clock
+ * @reserved            : reserved for future use
+ */
+struct tpg_global_config_t {
+	struct tpg_command_header_t header;
+	enum tpg_phy_type_t phy_type;
+	uint8_t lane_count;
+	enum tpg_interleaving_format_t interleaving_format;
+	uint8_t phy_mode;
+	enum tpg_shutter_t shutter_type;
+	uint32_t mode;
+	uint32_t hbi;
+	uint32_t vbi;
+	uint32_t skip_pattern;
+	uint64_t tpg_clock;
+	uint32_t reserved[4];
+} __attribute__((packed));
+
+/**
+ * tpg_stream_config_t : stream configuration command
+ *
+ * @header:  common tpg command header
+ * @pattern_type     : tpg pattern type used in this stream
+ * @cb_mode          : tpg color bar mode used in this stream
+ * @frame_count      : frame count in case of trigger burst mode
+ * @stream_type      : type of stream like image pdaf etc
+ * @stream_dimension : Dimension of the stream
+ * @pixel_depth      : bits per each pixel
+ * @cfa_arrangement  : color filter arragement
+ * @output_format    : output image format
+ * @hbi              : horizontal blanking intervel
+ * @vbi              : vertical   blanking intervel
+ * @vc               : virtual channel of this stream
+ * @dt               : data type of this stream
+ * @skip_pattern     : skip pattern for this stream
+ * @reserved         : reserved for future use
+ */
+struct tpg_stream_config_t {
+	struct tpg_command_header_t header;
+	enum tpg_pattern_t pattern_type;
+	enum tpg_color_bar_mode_t cb_mode;
+	uint32_t frame_count;
+	enum tpg_stream_t stream_type;
+	struct stream_dimension stream_dimension;
+	uint8_t pixel_depth;
+	enum tpg_cfa_arrangement_t cfa_arrangement;
+	enum tpg_image_format_t output_format;
+	uint32_t hbi;
+	uint32_t vbi;
+	uint16_t vc;
+	uint16_t dt;
+	uint32_t skip_pattern;
+	uint32_t rotate_period;
+	uint32_t reserved[4];
+} __attribute__((packed));
+
+/**
+ * tpg_illumination_control : illumianation control command
+ *
+ * @header         : common header for tpg command
+ * @vc             : virtual channel to identify the stream
+ * @dt             : dt to identify the stream
+ * @exposure_short : short exposure time
+ * @exposure_mid   : mid exposure time
+ * @exposure_long  : long exposure time
+ * @r_gain         : r channel gain
+ * @g_gain         : g channel gain
+ * @b_gain         : b channel gain
+ * @reserved       : reserved for future use
+ */
+struct tpg_illumination_control {
+	struct tpg_command_header_t header;
+	uint16_t vc;
+	uint16_t dt;
+	uint32_t exposure_short;
+	uint32_t exposure_mid;
+	uint32_t exposure_long;
+	uint16_t r_gain;
+	uint16_t g_gain;
+	uint16_t b_gain;
+	uint32_t reserved[4];
+} __attribute__((packed));
+
 /**
  * struct cam_flash_init : Init command for the flash
  * @flash_type  :    flash hw type