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