brintos

brintos / linux-shallow public Read only

0
0
Text · 17.6 KiB · 9f129bc Raw
771 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2023, Intel Corporation.4 * Intel Visual Sensing Controller Transport Layer Linux driver5 */6 7#include <linux/acpi.h>8#include <linux/align.h>9#include <linux/bitfield.h>10#include <linux/bits.h>11#include <linux/cleanup.h>12#include <linux/firmware.h>13#include <linux/sizes.h>14#include <linux/slab.h>15#include <linux/string_helpers.h>16#include <linux/types.h>17 18#include <linux/unaligned.h>19 20#include "vsc-tp.h"21 22#define VSC_MAGIC_NUM			0x49505343 /* IPSC */23#define VSC_MAGIC_FW			0x49574653 /* IWFS */24#define VSC_MAGIC_FILE			0x46564353 /* FVCS */25 26#define VSC_ADDR_BASE			0xE003000027#define VSC_EFUSE_ADDR			(VSC_ADDR_BASE + 0x038)28#define VSC_STRAP_ADDR			(VSC_ADDR_BASE + 0x100)29 30#define VSC_MAINSTEPPING_VERSION_MASK	GENMASK(7, 4)31#define VSC_MAINSTEPPING_VERSION_A	032 33#define VSC_SUBSTEPPING_VERSION_MASK	GENMASK(3, 0)34#define VSC_SUBSTEPPING_VERSION_0	035#define VSC_SUBSTEPPING_VERSION_1	236 37#define VSC_BOOT_IMG_OPTION_MASK	GENMASK(15, 0)38 39#define VSC_SKU_CFG_LOCATION		0x5001A00040#define VSC_SKU_MAX_SIZE		4100u41 42#define VSC_ACE_IMG_CNT			243#define VSC_CSI_IMG_CNT			444#define VSC_IMG_CNT_MAX			645 46#define VSC_ROM_PKG_SIZE		256u47#define VSC_FW_PKG_SIZE			512u48 49#define VSC_IMAGE_DIR			"intel/vsc/"50 51#define VSC_CSI_IMAGE_NAME		VSC_IMAGE_DIR "ivsc_fw.bin"52#define VSC_ACE_IMAGE_NAME_FMT		VSC_IMAGE_DIR "ivsc_pkg_%s_0.bin"53#define VSC_CFG_IMAGE_NAME_FMT		VSC_IMAGE_DIR "ivsc_skucfg_%s_0_1.bin"54 55#define VSC_IMAGE_PATH_MAX_LEN		6456 57#define VSC_SENSOR_NAME_MAX_LEN		1658 59/* command id */60enum {61	VSC_CMD_QUERY = 0,62	VSC_CMD_DL_SET = 1,63	VSC_CMD_DL_START = 2,64	VSC_CMD_DL_CONT = 3,65	VSC_CMD_DUMP_MEM = 4,66	VSC_CMD_GET_CONT = 8,67	VSC_CMD_CAM_BOOT = 10,68};69 70/* command ack token */71enum {72	VSC_TOKEN_BOOTLOADER_REQ = 1,73	VSC_TOKEN_DUMP_RESP = 4,74	VSC_TOKEN_ERROR = 7,75};76 77/* image type */78enum {79	VSC_IMG_BOOTLOADER_TYPE = 1,80	VSC_IMG_CSI_EM7D_TYPE,81	VSC_IMG_CSI_SEM_TYPE,82	VSC_IMG_CSI_RUNTIME_TYPE,83	VSC_IMG_ACE_VISION_TYPE,84	VSC_IMG_ACE_CFG_TYPE,85	VSC_IMG_SKU_CFG_TYPE,86};87 88/* image fragments */89enum {90	VSC_IMG_BOOTLOADER_FRAG,91	VSC_IMG_CSI_SEM_FRAG,92	VSC_IMG_CSI_RUNTIME_FRAG,93	VSC_IMG_ACE_VISION_FRAG,94	VSC_IMG_ACE_CFG_FRAG,95	VSC_IMG_CSI_EM7D_FRAG,96	VSC_IMG_SKU_CFG_FRAG,97	VSC_IMG_FRAG_MAX98};99 100struct vsc_rom_cmd {101	__le32 magic;102	__u8 cmd_id;103	union {104		/* download start */105		struct {106			__u8 img_type;107			__le16 option;108			__le32 img_len;109			__le32 img_loc;110			__le32 crc;111			DECLARE_FLEX_ARRAY(__u8, res);112		} __packed dl_start;113		/* download set */114		struct {115			__u8 option;116			__le16 img_cnt;117			DECLARE_FLEX_ARRAY(__le32, payload);118		} __packed dl_set;119		/* download continue */120		struct {121			__u8 end_flag;122			__le16 len;123			/* 8 is the offset of payload */124			__u8 payload[VSC_ROM_PKG_SIZE - 8];125		} __packed dl_cont;126		/* dump memory */127		struct {128			__u8 res;129			__le16 len;130			__le32 addr;131			DECLARE_FLEX_ARRAY(__u8, payload);132		} __packed dump_mem;133		/* 5 is the offset of padding */134		__u8 padding[VSC_ROM_PKG_SIZE - 5];135	} data;136};137 138struct vsc_rom_cmd_ack {139	__le32 magic;140	__u8 token;141	__u8 type;142	__u8 res[2];143	__u8 payload[];144};145 146struct vsc_fw_cmd {147	__le32 magic;148	__u8 cmd_id;149	union {150		struct {151			__le16 option;152			__u8 img_type;153			__le32 img_len;154			__le32 img_loc;155			__le32 crc;156			DECLARE_FLEX_ARRAY(__u8, res);157		} __packed dl_start;158		struct {159			__le16 option;160			__u8 img_cnt;161			DECLARE_FLEX_ARRAY(__le32, payload);162		} __packed dl_set;163		struct {164			__le32 addr;165			__u8 len;166			DECLARE_FLEX_ARRAY(__u8, payload);167		} __packed dump_mem;168		struct {169			__u8 resv[3];170			__le32 crc;171			DECLARE_FLEX_ARRAY(__u8, payload);172		} __packed boot;173		/* 5 is the offset of padding */174		__u8 padding[VSC_FW_PKG_SIZE - 5];175	} data;176};177 178struct vsc_img {179	__le32 magic;180	__le32 option;181	__le32 image_count;182	__le32 image_location[VSC_IMG_CNT_MAX];183};184 185struct vsc_fw_sign {186	__le32 magic;187	__le32 image_size;188	__u8 image[];189};190 191struct vsc_image_code_data {192	/* fragment index */193	u8 frag_index;194	/* image type */195	u8 image_type;196};197 198struct vsc_img_frag {199	u8 type;200	u32 location;201	const u8 *data;202	u32 size;203};204 205/**206 * struct vsc_fw_loader - represent vsc firmware loader207 * @dev: device used to request firmware208 * @tp: transport layer used with the firmware loader209 * @csi: CSI image210 * @ace: ACE image211 * @cfg: config image212 * @tx_buf: tx buffer213 * @rx_buf: rx buffer214 * @option: command option215 * @count: total image count216 * @sensor_name: camera sensor name217 * @frags: image fragments218 */219struct vsc_fw_loader {220	struct device *dev;221	struct vsc_tp *tp;222 223	const struct firmware *csi;224	const struct firmware *ace;225	const struct firmware *cfg;226 227	void *tx_buf;228	void *rx_buf;229 230	u16 option;231	u16 count;232 233	char sensor_name[VSC_SENSOR_NAME_MAX_LEN];234 235	struct vsc_img_frag frags[VSC_IMG_FRAG_MAX];236};237 238static inline u32 vsc_sum_crc(void *data, size_t size)239{240	u32 crc = 0;241	size_t i;242 243	for (i = 0; i < size; i++)244		crc += *((u8 *)data + i);245 246	return crc;247}248 249/* get sensor name to construct image name */250static int vsc_get_sensor_name(struct vsc_fw_loader *fw_loader,251			       struct device *dev)252{253	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };254	union acpi_object obj = {255		.integer.type = ACPI_TYPE_INTEGER,256		.integer.value = 1,257	};258	struct acpi_object_list arg_list = {259		.count = 1,260		.pointer = &obj,261	};262	union acpi_object *ret_obj;263	acpi_handle handle;264	acpi_status status;265	int ret = 0;266 267	handle = ACPI_HANDLE(dev);268	if (!handle)269		return -EINVAL;270 271	status = acpi_evaluate_object(handle, "SID", &arg_list, &buffer);272	if (ACPI_FAILURE(status)) {273		dev_err(dev, "can't evaluate SID method: %d\n", status);274		return -ENODEV;275	}276 277	ret_obj = buffer.pointer;278	if (!ret_obj) {279		dev_err(dev, "can't locate ACPI buffer\n");280		return -ENODEV;281	}282 283	if (ret_obj->type != ACPI_TYPE_STRING) {284		dev_err(dev, "found non-string entry\n");285		ret = -ENODEV;286		goto out_free_buff;287	}288 289	/* string length excludes trailing NUL */290	if (ret_obj->string.length >= sizeof(fw_loader->sensor_name)) {291		dev_err(dev, "sensor name buffer too small\n");292		ret = -EINVAL;293		goto out_free_buff;294	}295 296	memcpy(fw_loader->sensor_name, ret_obj->string.pointer,297	       ret_obj->string.length);298 299	string_lower(fw_loader->sensor_name, fw_loader->sensor_name);300 301out_free_buff:302	ACPI_FREE(buffer.pointer);303 304	return ret;305}306 307static int vsc_identify_silicon(struct vsc_fw_loader *fw_loader)308{309	struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;310	struct vsc_rom_cmd *cmd = fw_loader->tx_buf;311	u8 version, sub_version;312	int ret;313 314	/* identify stepping information */315	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);316	cmd->cmd_id = VSC_CMD_DUMP_MEM;317	cmd->data.dump_mem.addr = cpu_to_le32(VSC_EFUSE_ADDR);318	cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));319	ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);320	if (ret)321		return ret;322	if (ack->token == VSC_TOKEN_ERROR)323		return -EINVAL;324 325	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);326	cmd->cmd_id = VSC_CMD_GET_CONT;327	ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);328	if (ret)329		return ret;330	if (ack->token != VSC_TOKEN_DUMP_RESP)331		return -EINVAL;332 333	version = FIELD_GET(VSC_MAINSTEPPING_VERSION_MASK, ack->payload[0]);334	sub_version = FIELD_GET(VSC_SUBSTEPPING_VERSION_MASK, ack->payload[0]);335 336	if (version != VSC_MAINSTEPPING_VERSION_A)337		return -EINVAL;338 339	if (sub_version != VSC_SUBSTEPPING_VERSION_0 &&340	    sub_version != VSC_SUBSTEPPING_VERSION_1)341		return -EINVAL;342 343	dev_info(fw_loader->dev, "silicon stepping version is %u:%u\n",344		 version, sub_version);345 346	/* identify strap information */347	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);348	cmd->cmd_id = VSC_CMD_DUMP_MEM;349	cmd->data.dump_mem.addr = cpu_to_le32(VSC_STRAP_ADDR);350	cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));351	ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);352	if (ret)353		return ret;354	if (ack->token == VSC_TOKEN_ERROR)355		return -EINVAL;356 357	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);358	cmd->cmd_id = VSC_CMD_GET_CONT;359	ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);360	if (ret)361		return ret;362	if (ack->token != VSC_TOKEN_DUMP_RESP)363		return -EINVAL;364 365	return 0;366}367 368static int vsc_identify_csi_image(struct vsc_fw_loader *fw_loader)369{370	const struct firmware *image;371	struct vsc_fw_sign *sign;372	struct vsc_img *img;373	unsigned int i;374	int ret;375 376	ret = request_firmware(&image, VSC_CSI_IMAGE_NAME, fw_loader->dev);377	if (ret)378		return ret;379 380	img = (struct vsc_img *)image->data;381	if (!img) {382		ret = -ENOENT;383		goto err_release_image;384	}385 386	if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {387		ret = -EINVAL;388		goto err_release_image;389	}390 391	if (le32_to_cpu(img->image_count) != VSC_CSI_IMG_CNT) {392		ret = -EINVAL;393		goto err_release_image;394	}395	fw_loader->count += le32_to_cpu(img->image_count) - 1;396 397	fw_loader->option =398		FIELD_GET(VSC_BOOT_IMG_OPTION_MASK, le32_to_cpu(img->option));399 400	sign = (struct vsc_fw_sign *)401		(img->image_location + le32_to_cpu(img->image_count));402 403	for (i = 0; i < VSC_CSI_IMG_CNT; i++) {404		/* mapping from CSI image index to image code data */405		static const struct vsc_image_code_data csi_image_map[] = {406			{ VSC_IMG_BOOTLOADER_FRAG, VSC_IMG_BOOTLOADER_TYPE },407			{ VSC_IMG_CSI_SEM_FRAG, VSC_IMG_CSI_SEM_TYPE },408			{ VSC_IMG_CSI_RUNTIME_FRAG, VSC_IMG_CSI_RUNTIME_TYPE },409			{ VSC_IMG_CSI_EM7D_FRAG, VSC_IMG_CSI_EM7D_TYPE },410		};411		struct vsc_img_frag *frag;412 413		if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {414			ret = -EINVAL;415			goto err_release_image;416		}417 418		if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {419			ret = -EINVAL;420			goto err_release_image;421		}422 423		if (!le32_to_cpu(img->image_location[i])) {424			ret = -EINVAL;425			goto err_release_image;426		}427 428		frag = &fw_loader->frags[csi_image_map[i].frag_index];429 430		frag->data = sign->image;431		frag->size = le32_to_cpu(sign->image_size);432		frag->location = le32_to_cpu(img->image_location[i]);433		frag->type = csi_image_map[i].image_type;434 435		sign = (struct vsc_fw_sign *)436			(sign->image + le32_to_cpu(sign->image_size));437	}438 439	fw_loader->csi = image;440 441	return 0;442 443err_release_image:444	release_firmware(image);445 446	return ret;447}448 449static int vsc_identify_ace_image(struct vsc_fw_loader *fw_loader)450{451	char path[VSC_IMAGE_PATH_MAX_LEN];452	const struct firmware *image;453	struct vsc_fw_sign *sign;454	struct vsc_img *img;455	unsigned int i;456	int ret;457 458	snprintf(path, sizeof(path), VSC_ACE_IMAGE_NAME_FMT,459		 fw_loader->sensor_name);460 461	ret = request_firmware(&image, path, fw_loader->dev);462	if (ret)463		return ret;464 465	img = (struct vsc_img *)image->data;466	if (!img) {467		ret = -ENOENT;468		goto err_release_image;469	}470 471	if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {472		ret = -EINVAL;473		goto err_release_image;474	}475 476	if (le32_to_cpu(img->image_count) != VSC_ACE_IMG_CNT) {477		ret = -EINVAL;478		goto err_release_image;479	}480	fw_loader->count += le32_to_cpu(img->image_count);481 482	sign = (struct vsc_fw_sign *)483		(img->image_location + le32_to_cpu(img->image_count));484 485	for (i = 0; i < VSC_ACE_IMG_CNT; i++) {486		/* mapping from ACE image index to image code data */487		static const struct vsc_image_code_data ace_image_map[] = {488			{ VSC_IMG_ACE_VISION_FRAG, VSC_IMG_ACE_VISION_TYPE },489			{ VSC_IMG_ACE_CFG_FRAG, VSC_IMG_ACE_CFG_TYPE },490		};491		struct vsc_img_frag *frag, *last_frag;492		u8 frag_index;493 494		if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {495			ret = -EINVAL;496			goto err_release_image;497		}498 499		if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {500			ret = -EINVAL;501			goto err_release_image;502		}503 504		frag_index = ace_image_map[i].frag_index;505		frag = &fw_loader->frags[frag_index];506 507		frag->data = sign->image;508		frag->size = le32_to_cpu(sign->image_size);509		frag->location = le32_to_cpu(img->image_location[i]);510		frag->type = ace_image_map[i].image_type;511 512		if (!frag->location) {513			last_frag = &fw_loader->frags[frag_index - 1];514			frag->location =515				ALIGN(last_frag->location + last_frag->size, SZ_4K);516		}517 518		sign = (struct vsc_fw_sign *)519			(sign->image + le32_to_cpu(sign->image_size));520	}521 522	fw_loader->ace = image;523 524	return 0;525 526err_release_image:527	release_firmware(image);528 529	return ret;530}531 532static int vsc_identify_cfg_image(struct vsc_fw_loader *fw_loader)533{534	struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_SKU_CFG_FRAG];535	char path[VSC_IMAGE_PATH_MAX_LEN];536	const struct firmware *image;537	u32 size;538	int ret;539 540	snprintf(path, sizeof(path), VSC_CFG_IMAGE_NAME_FMT,541		 fw_loader->sensor_name);542 543	ret = request_firmware(&image, path, fw_loader->dev);544	if (ret)545		return ret;546 547	/* identify image size */548	if (image->size <= sizeof(u32) || image->size > VSC_SKU_MAX_SIZE) {549		ret = -EINVAL;550		goto err_release_image;551	}552 553	size = le32_to_cpu(*((__le32 *)image->data)) + sizeof(u32);554	if (image->size != size) {555		ret = -EINVAL;556		goto err_release_image;557	}558 559	frag->data = image->data;560	frag->size = image->size;561	frag->type = VSC_IMG_SKU_CFG_TYPE;562	frag->location = VSC_SKU_CFG_LOCATION;563 564	fw_loader->cfg = image;565 566	return 0;567 568err_release_image:569	release_firmware(image);570 571	return ret;572}573 574static int vsc_download_bootloader(struct vsc_fw_loader *fw_loader)575{576	struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_BOOTLOADER_FRAG];577	struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;578	struct vsc_rom_cmd *cmd = fw_loader->tx_buf;579	u32 len, c_len;580	size_t remain;581	const u8 *p;582	int ret;583 584	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);585	cmd->cmd_id = VSC_CMD_QUERY;586	ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);587	if (ret)588		return ret;589	if (ack->token != VSC_TOKEN_DUMP_RESP &&590	    ack->token != VSC_TOKEN_BOOTLOADER_REQ)591		return -EINVAL;592 593	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);594	cmd->cmd_id = VSC_CMD_DL_START;595	cmd->data.dl_start.option = cpu_to_le16(fw_loader->option);596	cmd->data.dl_start.img_type = frag->type;597	cmd->data.dl_start.img_len = cpu_to_le32(frag->size);598	cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);599 600	c_len = offsetof(struct vsc_rom_cmd, data.dl_start.crc);601	cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));602 603	ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);604	if (ret)605		return ret;606 607	p = frag->data;608	remain = frag->size;609 610	/* download image data */611	while (remain > 0) {612		len = min(remain, sizeof(cmd->data.dl_cont.payload));613 614		cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);615		cmd->cmd_id = VSC_CMD_DL_CONT;616		cmd->data.dl_cont.len = cpu_to_le16(len);617		cmd->data.dl_cont.end_flag = remain == len;618		memcpy(cmd->data.dl_cont.payload, p, len);619 620		ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);621		if (ret)622			return ret;623 624		p += len;625		remain -= len;626	}627 628	return 0;629}630 631static int vsc_download_firmware(struct vsc_fw_loader *fw_loader)632{633	struct vsc_fw_cmd *cmd = fw_loader->tx_buf;634	unsigned int i, index = 0;635	u32 c_len;636	int ret;637 638	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);639	cmd->cmd_id = VSC_CMD_DL_SET;640	cmd->data.dl_set.img_cnt = cpu_to_le16(fw_loader->count);641	put_unaligned_le16(fw_loader->option, &cmd->data.dl_set.option);642 643	for (i = VSC_IMG_CSI_SEM_FRAG; i <= VSC_IMG_CSI_EM7D_FRAG; i++) {644		struct vsc_img_frag *frag = &fw_loader->frags[i];645 646		cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->location);647		cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->size);648	}649 650	c_len = offsetof(struct vsc_fw_cmd, data.dl_set.payload[index]);651	cmd->data.dl_set.payload[index] = cpu_to_le32(vsc_sum_crc(cmd, c_len));652 653	ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);654	if (ret)655		return ret;656 657	for (i = VSC_IMG_CSI_SEM_FRAG; i < VSC_IMG_FRAG_MAX; i++) {658		struct vsc_img_frag *frag = &fw_loader->frags[i];659		const u8 *p;660		u32 remain;661 662		cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);663		cmd->cmd_id = VSC_CMD_DL_START;664		cmd->data.dl_start.img_type = frag->type;665		cmd->data.dl_start.img_len = cpu_to_le32(frag->size);666		cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);667		put_unaligned_le16(fw_loader->option, &cmd->data.dl_start.option);668 669		c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);670		cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));671 672		ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);673		if (ret)674			return ret;675 676		p = frag->data;677		remain = frag->size;678 679		/* download image data */680		while (remain > 0) {681			u32 len = min(remain, VSC_FW_PKG_SIZE);682 683			memcpy(fw_loader->tx_buf, p, len);684			memset(fw_loader->tx_buf + len, 0, VSC_FW_PKG_SIZE - len);685 686			ret = vsc_tp_rom_xfer(fw_loader->tp, fw_loader->tx_buf,687					      NULL, VSC_FW_PKG_SIZE);688			if (ret)689				break;690 691			p += len;692			remain -= len;693		}694	}695 696	cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);697	cmd->cmd_id = VSC_CMD_CAM_BOOT;698 699	c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);700	cmd->data.boot.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));701 702	return vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);703}704 705/**706 * vsc_tp_init - init vsc_tp707 * @tp: vsc_tp device handle708 * @dev: device node for mei vsc device709 * Return: 0 in case of success, negative value in case of error710 */711int vsc_tp_init(struct vsc_tp *tp, struct device *dev)712{713	struct vsc_fw_loader *fw_loader __free(kfree) = NULL;714	void *tx_buf __free(kfree) = NULL;715	void *rx_buf __free(kfree) = NULL;716	int ret;717 718	fw_loader = kzalloc(sizeof(*fw_loader), GFP_KERNEL);719	if (!fw_loader)720		return -ENOMEM;721 722	tx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);723	if (!tx_buf)724		return -ENOMEM;725 726	rx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);727	if (!rx_buf)728		return -ENOMEM;729 730	fw_loader->tx_buf = tx_buf;731	fw_loader->rx_buf = rx_buf;732 733	fw_loader->tp = tp;734	fw_loader->dev = dev;735 736	ret = vsc_get_sensor_name(fw_loader, dev);737	if (ret)738		return ret;739 740	ret = vsc_identify_silicon(fw_loader);741	if (ret)742		return ret;743 744	ret = vsc_identify_csi_image(fw_loader);745	if (ret)746		return ret;747 748	ret = vsc_identify_ace_image(fw_loader);749	if (ret)750		goto err_release_csi;751 752	ret = vsc_identify_cfg_image(fw_loader);753	if (ret)754		goto err_release_ace;755 756	ret = vsc_download_bootloader(fw_loader);757	if (!ret)758		ret = vsc_download_firmware(fw_loader);759 760	release_firmware(fw_loader->cfg);761 762err_release_ace:763	release_firmware(fw_loader->ace);764 765err_release_csi:766	release_firmware(fw_loader->csi);767 768	return ret;769}770EXPORT_SYMBOL_NS_GPL(vsc_tp_init, VSC_TP);771