| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2023, Intel Corporation.
- * Intel Visual Sensing Controller Transport Layer Linux driver
- */
- #include <linux/acpi.h>
- #include <linux/align.h>
- #include <linux/bitfield.h>
- #include <linux/bits.h>
- #include <linux/cleanup.h>
- #include <linux/firmware.h>
- #include <linux/sizes.h>
- #include <linux/slab.h>
- #include <linux/string_helpers.h>
- #include <linux/types.h>
- #include <linux/unaligned.h>
- #include "vsc-tp.h"
- #define VSC_MAGIC_NUM 0x49505343 /* IPSC */
- #define VSC_MAGIC_FW 0x49574653 /* IWFS */
- #define VSC_MAGIC_FILE 0x46564353 /* FVCS */
- #define VSC_ADDR_BASE 0xE0030000
- #define VSC_EFUSE_ADDR (VSC_ADDR_BASE + 0x038)
- #define VSC_STRAP_ADDR (VSC_ADDR_BASE + 0x100)
- #define VSC_MAINSTEPPING_VERSION_MASK GENMASK(7, 4)
- #define VSC_MAINSTEPPING_VERSION_A 0
- #define VSC_SUBSTEPPING_VERSION_MASK GENMASK(3, 0)
- #define VSC_SUBSTEPPING_VERSION_0 0
- #define VSC_SUBSTEPPING_VERSION_1 2
- #define VSC_BOOT_IMG_OPTION_MASK GENMASK(15, 0)
- #define VSC_SKU_CFG_LOCATION 0x5001A000
- #define VSC_SKU_MAX_SIZE 4100u
- #define VSC_ACE_IMG_CNT 2
- #define VSC_CSI_IMG_CNT 4
- #define VSC_IMG_CNT_MAX 6
- #define VSC_ROM_PKG_SIZE 256u
- #define VSC_FW_PKG_SIZE 512u
- #define VSC_IMAGE_DIR "intel/vsc/"
- #define VSC_CSI_IMAGE_NAME VSC_IMAGE_DIR "ivsc_fw.bin"
- #define VSC_ACE_IMAGE_NAME_FMT VSC_IMAGE_DIR "ivsc_pkg_%s_0.bin"
- #define VSC_CFG_IMAGE_NAME_FMT VSC_IMAGE_DIR "ivsc_skucfg_%s_0_1.bin"
- #define VSC_IMAGE_PATH_MAX_LEN 64
- #define VSC_SENSOR_NAME_MAX_LEN 16
- /* command id */
- enum {
- VSC_CMD_QUERY = 0,
- VSC_CMD_DL_SET = 1,
- VSC_CMD_DL_START = 2,
- VSC_CMD_DL_CONT = 3,
- VSC_CMD_DUMP_MEM = 4,
- VSC_CMD_GET_CONT = 8,
- VSC_CMD_CAM_BOOT = 10,
- };
- /* command ack token */
- enum {
- VSC_TOKEN_BOOTLOADER_REQ = 1,
- VSC_TOKEN_DUMP_RESP = 4,
- VSC_TOKEN_ERROR = 7,
- };
- /* image type */
- enum {
- VSC_IMG_BOOTLOADER_TYPE = 1,
- VSC_IMG_CSI_EM7D_TYPE,
- VSC_IMG_CSI_SEM_TYPE,
- VSC_IMG_CSI_RUNTIME_TYPE,
- VSC_IMG_ACE_VISION_TYPE,
- VSC_IMG_ACE_CFG_TYPE,
- VSC_IMG_SKU_CFG_TYPE,
- };
- /* image fragments */
- enum {
- VSC_IMG_BOOTLOADER_FRAG,
- VSC_IMG_CSI_SEM_FRAG,
- VSC_IMG_CSI_RUNTIME_FRAG,
- VSC_IMG_ACE_VISION_FRAG,
- VSC_IMG_ACE_CFG_FRAG,
- VSC_IMG_CSI_EM7D_FRAG,
- VSC_IMG_SKU_CFG_FRAG,
- VSC_IMG_FRAG_MAX
- };
- struct vsc_rom_cmd {
- __le32 magic;
- __u8 cmd_id;
- union {
- /* download start */
- struct {
- __u8 img_type;
- __le16 option;
- __le32 img_len;
- __le32 img_loc;
- __le32 crc;
- DECLARE_FLEX_ARRAY(__u8, res);
- } __packed dl_start;
- /* download set */
- struct {
- __u8 option;
- __le16 img_cnt;
- DECLARE_FLEX_ARRAY(__le32, payload);
- } __packed dl_set;
- /* download continue */
- struct {
- __u8 end_flag;
- __le16 len;
- /* 8 is the offset of payload */
- __u8 payload[VSC_ROM_PKG_SIZE - 8];
- } __packed dl_cont;
- /* dump memory */
- struct {
- __u8 res;
- __le16 len;
- __le32 addr;
- DECLARE_FLEX_ARRAY(__u8, payload);
- } __packed dump_mem;
- /* 5 is the offset of padding */
- __u8 padding[VSC_ROM_PKG_SIZE - 5];
- } data;
- };
- struct vsc_rom_cmd_ack {
- __le32 magic;
- __u8 token;
- __u8 type;
- __u8 res[2];
- __u8 payload[];
- };
- struct vsc_fw_cmd {
- __le32 magic;
- __u8 cmd_id;
- union {
- struct {
- __le16 option;
- __u8 img_type;
- __le32 img_len;
- __le32 img_loc;
- __le32 crc;
- DECLARE_FLEX_ARRAY(__u8, res);
- } __packed dl_start;
- struct {
- __le16 option;
- __u8 img_cnt;
- DECLARE_FLEX_ARRAY(__le32, payload);
- } __packed dl_set;
- struct {
- __le32 addr;
- __u8 len;
- DECLARE_FLEX_ARRAY(__u8, payload);
- } __packed dump_mem;
- struct {
- __u8 resv[3];
- __le32 crc;
- DECLARE_FLEX_ARRAY(__u8, payload);
- } __packed boot;
- /* 5 is the offset of padding */
- __u8 padding[VSC_FW_PKG_SIZE - 5];
- } data;
- };
- struct vsc_img {
- __le32 magic;
- __le32 option;
- __le32 image_count;
- __le32 image_location[VSC_IMG_CNT_MAX];
- };
- struct vsc_fw_sign {
- __le32 magic;
- __le32 image_size;
- __u8 image[];
- };
- struct vsc_image_code_data {
- /* fragment index */
- u8 frag_index;
- /* image type */
- u8 image_type;
- };
- struct vsc_img_frag {
- u8 type;
- u32 location;
- const u8 *data;
- u32 size;
- };
- /**
- * struct vsc_fw_loader - represent vsc firmware loader
- * @dev: device used to request firmware
- * @tp: transport layer used with the firmware loader
- * @csi: CSI image
- * @ace: ACE image
- * @cfg: config image
- * @tx_buf: tx buffer
- * @rx_buf: rx buffer
- * @option: command option
- * @count: total image count
- * @sensor_name: camera sensor name
- * @frags: image fragments
- */
- struct vsc_fw_loader {
- struct device *dev;
- struct vsc_tp *tp;
- const struct firmware *csi;
- const struct firmware *ace;
- const struct firmware *cfg;
- void *tx_buf;
- void *rx_buf;
- u16 option;
- u16 count;
- char sensor_name[VSC_SENSOR_NAME_MAX_LEN];
- struct vsc_img_frag frags[VSC_IMG_FRAG_MAX];
- };
- static inline u32 vsc_sum_crc(void *data, size_t size)
- {
- u32 crc = 0;
- size_t i;
- for (i = 0; i < size; i++)
- crc += *((u8 *)data + i);
- return crc;
- }
- /* get sensor name to construct image name */
- static int vsc_get_sensor_name(struct vsc_fw_loader *fw_loader,
- struct device *dev)
- {
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
- union acpi_object obj = {
- .integer.type = ACPI_TYPE_INTEGER,
- .integer.value = 1,
- };
- struct acpi_object_list arg_list = {
- .count = 1,
- .pointer = &obj,
- };
- union acpi_object *ret_obj;
- acpi_handle handle;
- acpi_status status;
- int ret = 0;
- handle = ACPI_HANDLE(dev);
- if (!handle)
- return -EINVAL;
- status = acpi_evaluate_object(handle, "SID", &arg_list, &buffer);
- if (ACPI_FAILURE(status)) {
- dev_err(dev, "can't evaluate SID method: %d\n", status);
- return -ENODEV;
- }
- ret_obj = buffer.pointer;
- if (!ret_obj) {
- dev_err(dev, "can't locate ACPI buffer\n");
- return -ENODEV;
- }
- if (ret_obj->type != ACPI_TYPE_STRING) {
- dev_err(dev, "found non-string entry\n");
- ret = -ENODEV;
- goto out_free_buff;
- }
- /* string length excludes trailing NUL */
- if (ret_obj->string.length >= sizeof(fw_loader->sensor_name)) {
- dev_err(dev, "sensor name buffer too small\n");
- ret = -EINVAL;
- goto out_free_buff;
- }
- memcpy(fw_loader->sensor_name, ret_obj->string.pointer,
- ret_obj->string.length);
- string_lower(fw_loader->sensor_name, fw_loader->sensor_name);
- out_free_buff:
- ACPI_FREE(buffer.pointer);
- return ret;
- }
- static int vsc_identify_silicon(struct vsc_fw_loader *fw_loader)
- {
- struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;
- struct vsc_rom_cmd *cmd = fw_loader->tx_buf;
- u8 version, sub_version;
- int ret;
- /* identify stepping information */
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_DUMP_MEM;
- cmd->data.dump_mem.addr = cpu_to_le32(VSC_EFUSE_ADDR);
- cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
- if (ret)
- return ret;
- if (ack->token == VSC_TOKEN_ERROR)
- return -EINVAL;
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_GET_CONT;
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
- if (ret)
- return ret;
- if (ack->token != VSC_TOKEN_DUMP_RESP)
- return -EINVAL;
- version = FIELD_GET(VSC_MAINSTEPPING_VERSION_MASK, ack->payload[0]);
- sub_version = FIELD_GET(VSC_SUBSTEPPING_VERSION_MASK, ack->payload[0]);
- if (version != VSC_MAINSTEPPING_VERSION_A)
- return -EINVAL;
- if (sub_version != VSC_SUBSTEPPING_VERSION_0 &&
- sub_version != VSC_SUBSTEPPING_VERSION_1)
- return -EINVAL;
- dev_info(fw_loader->dev, "silicon stepping version is %u:%u\n",
- version, sub_version);
- /* identify strap information */
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_DUMP_MEM;
- cmd->data.dump_mem.addr = cpu_to_le32(VSC_STRAP_ADDR);
- cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
- if (ret)
- return ret;
- if (ack->token == VSC_TOKEN_ERROR)
- return -EINVAL;
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_GET_CONT;
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
- if (ret)
- return ret;
- if (ack->token != VSC_TOKEN_DUMP_RESP)
- return -EINVAL;
- return 0;
- }
- static int vsc_identify_csi_image(struct vsc_fw_loader *fw_loader)
- {
- const struct firmware *image;
- struct vsc_fw_sign *sign;
- struct vsc_img *img;
- unsigned int i;
- int ret;
- ret = request_firmware(&image, VSC_CSI_IMAGE_NAME, fw_loader->dev);
- if (ret)
- return ret;
- img = (struct vsc_img *)image->data;
- if (!img) {
- ret = -ENOENT;
- goto err_release_image;
- }
- if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {
- ret = -EINVAL;
- goto err_release_image;
- }
- if (le32_to_cpu(img->image_count) != VSC_CSI_IMG_CNT) {
- ret = -EINVAL;
- goto err_release_image;
- }
- fw_loader->count += le32_to_cpu(img->image_count) - 1;
- fw_loader->option =
- FIELD_GET(VSC_BOOT_IMG_OPTION_MASK, le32_to_cpu(img->option));
- sign = (struct vsc_fw_sign *)
- (img->image_location + le32_to_cpu(img->image_count));
- for (i = 0; i < VSC_CSI_IMG_CNT; i++) {
- /* mapping from CSI image index to image code data */
- static const struct vsc_image_code_data csi_image_map[] = {
- { VSC_IMG_BOOTLOADER_FRAG, VSC_IMG_BOOTLOADER_TYPE },
- { VSC_IMG_CSI_SEM_FRAG, VSC_IMG_CSI_SEM_TYPE },
- { VSC_IMG_CSI_RUNTIME_FRAG, VSC_IMG_CSI_RUNTIME_TYPE },
- { VSC_IMG_CSI_EM7D_FRAG, VSC_IMG_CSI_EM7D_TYPE },
- };
- struct vsc_img_frag *frag;
- if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {
- ret = -EINVAL;
- goto err_release_image;
- }
- if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {
- ret = -EINVAL;
- goto err_release_image;
- }
- if (!le32_to_cpu(img->image_location[i])) {
- ret = -EINVAL;
- goto err_release_image;
- }
- frag = &fw_loader->frags[csi_image_map[i].frag_index];
- frag->data = sign->image;
- frag->size = le32_to_cpu(sign->image_size);
- frag->location = le32_to_cpu(img->image_location[i]);
- frag->type = csi_image_map[i].image_type;
- sign = (struct vsc_fw_sign *)
- (sign->image + le32_to_cpu(sign->image_size));
- }
- fw_loader->csi = image;
- return 0;
- err_release_image:
- release_firmware(image);
- return ret;
- }
- static int vsc_identify_ace_image(struct vsc_fw_loader *fw_loader)
- {
- char path[VSC_IMAGE_PATH_MAX_LEN];
- const struct firmware *image;
- struct vsc_fw_sign *sign;
- struct vsc_img *img;
- unsigned int i;
- int ret;
- snprintf(path, sizeof(path), VSC_ACE_IMAGE_NAME_FMT,
- fw_loader->sensor_name);
- ret = request_firmware(&image, path, fw_loader->dev);
- if (ret)
- return ret;
- img = (struct vsc_img *)image->data;
- if (!img) {
- ret = -ENOENT;
- goto err_release_image;
- }
- if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {
- ret = -EINVAL;
- goto err_release_image;
- }
- if (le32_to_cpu(img->image_count) != VSC_ACE_IMG_CNT) {
- ret = -EINVAL;
- goto err_release_image;
- }
- fw_loader->count += le32_to_cpu(img->image_count);
- sign = (struct vsc_fw_sign *)
- (img->image_location + le32_to_cpu(img->image_count));
- for (i = 0; i < VSC_ACE_IMG_CNT; i++) {
- /* mapping from ACE image index to image code data */
- static const struct vsc_image_code_data ace_image_map[] = {
- { VSC_IMG_ACE_VISION_FRAG, VSC_IMG_ACE_VISION_TYPE },
- { VSC_IMG_ACE_CFG_FRAG, VSC_IMG_ACE_CFG_TYPE },
- };
- struct vsc_img_frag *frag, *last_frag;
- u8 frag_index;
- if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {
- ret = -EINVAL;
- goto err_release_image;
- }
- if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {
- ret = -EINVAL;
- goto err_release_image;
- }
- frag_index = ace_image_map[i].frag_index;
- frag = &fw_loader->frags[frag_index];
- frag->data = sign->image;
- frag->size = le32_to_cpu(sign->image_size);
- frag->location = le32_to_cpu(img->image_location[i]);
- frag->type = ace_image_map[i].image_type;
- if (!frag->location) {
- last_frag = &fw_loader->frags[frag_index - 1];
- frag->location =
- ALIGN(last_frag->location + last_frag->size, SZ_4K);
- }
- sign = (struct vsc_fw_sign *)
- (sign->image + le32_to_cpu(sign->image_size));
- }
- fw_loader->ace = image;
- return 0;
- err_release_image:
- release_firmware(image);
- return ret;
- }
- static int vsc_identify_cfg_image(struct vsc_fw_loader *fw_loader)
- {
- struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_SKU_CFG_FRAG];
- char path[VSC_IMAGE_PATH_MAX_LEN];
- const struct firmware *image;
- u32 size;
- int ret;
- snprintf(path, sizeof(path), VSC_CFG_IMAGE_NAME_FMT,
- fw_loader->sensor_name);
- ret = request_firmware(&image, path, fw_loader->dev);
- if (ret)
- return ret;
- /* identify image size */
- if (image->size <= sizeof(u32) || image->size > VSC_SKU_MAX_SIZE) {
- ret = -EINVAL;
- goto err_release_image;
- }
- size = le32_to_cpu(*((__le32 *)image->data)) + sizeof(u32);
- if (image->size != size) {
- ret = -EINVAL;
- goto err_release_image;
- }
- frag->data = image->data;
- frag->size = image->size;
- frag->type = VSC_IMG_SKU_CFG_TYPE;
- frag->location = VSC_SKU_CFG_LOCATION;
- fw_loader->cfg = image;
- return 0;
- err_release_image:
- release_firmware(image);
- return ret;
- }
- static int vsc_download_bootloader(struct vsc_fw_loader *fw_loader)
- {
- struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_BOOTLOADER_FRAG];
- struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;
- struct vsc_rom_cmd *cmd = fw_loader->tx_buf;
- u32 len, c_len;
- size_t remain;
- const u8 *p;
- int ret;
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_QUERY;
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
- if (ret)
- return ret;
- if (ack->token != VSC_TOKEN_DUMP_RESP &&
- ack->token != VSC_TOKEN_BOOTLOADER_REQ)
- return -EINVAL;
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_DL_START;
- cmd->data.dl_start.option = cpu_to_le16(fw_loader->option);
- cmd->data.dl_start.img_type = frag->type;
- cmd->data.dl_start.img_len = cpu_to_le32(frag->size);
- cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);
- c_len = offsetof(struct vsc_rom_cmd, data.dl_start.crc);
- cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);
- if (ret)
- return ret;
- p = frag->data;
- remain = frag->size;
- /* download image data */
- while (remain > 0) {
- len = min(remain, sizeof(cmd->data.dl_cont.payload));
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_DL_CONT;
- cmd->data.dl_cont.len = cpu_to_le16(len);
- cmd->data.dl_cont.end_flag = remain == len;
- memcpy(cmd->data.dl_cont.payload, p, len);
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);
- if (ret)
- return ret;
- p += len;
- remain -= len;
- }
- return 0;
- }
- static int vsc_download_firmware(struct vsc_fw_loader *fw_loader)
- {
- struct vsc_fw_cmd *cmd = fw_loader->tx_buf;
- unsigned int i, index = 0;
- u32 c_len;
- int ret;
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_DL_SET;
- cmd->data.dl_set.img_cnt = cpu_to_le16(fw_loader->count);
- put_unaligned_le16(fw_loader->option, &cmd->data.dl_set.option);
- for (i = VSC_IMG_CSI_SEM_FRAG; i <= VSC_IMG_CSI_EM7D_FRAG; i++) {
- struct vsc_img_frag *frag = &fw_loader->frags[i];
- cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->location);
- cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->size);
- }
- c_len = offsetof(struct vsc_fw_cmd, data.dl_set.payload[index]);
- cmd->data.dl_set.payload[index] = cpu_to_le32(vsc_sum_crc(cmd, c_len));
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
- if (ret)
- return ret;
- for (i = VSC_IMG_CSI_SEM_FRAG; i < VSC_IMG_FRAG_MAX; i++) {
- struct vsc_img_frag *frag = &fw_loader->frags[i];
- const u8 *p;
- u32 remain;
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_DL_START;
- cmd->data.dl_start.img_type = frag->type;
- cmd->data.dl_start.img_len = cpu_to_le32(frag->size);
- cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);
- put_unaligned_le16(fw_loader->option, &cmd->data.dl_start.option);
- c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);
- cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));
- ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
- if (ret)
- return ret;
- p = frag->data;
- remain = frag->size;
- /* download image data */
- while (remain > 0) {
- u32 len = min(remain, VSC_FW_PKG_SIZE);
- memcpy(fw_loader->tx_buf, p, len);
- memset(fw_loader->tx_buf + len, 0, VSC_FW_PKG_SIZE - len);
- ret = vsc_tp_rom_xfer(fw_loader->tp, fw_loader->tx_buf,
- NULL, VSC_FW_PKG_SIZE);
- if (ret)
- break;
- p += len;
- remain -= len;
- }
- }
- cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
- cmd->cmd_id = VSC_CMD_CAM_BOOT;
- c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);
- cmd->data.boot.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));
- return vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
- }
- /**
- * vsc_tp_init - init vsc_tp
- * @tp: vsc_tp device handle
- * @dev: device node for mei vsc device
- * Return: 0 in case of success, negative value in case of error
- */
- int vsc_tp_init(struct vsc_tp *tp, struct device *dev)
- {
- struct vsc_fw_loader *fw_loader __free(kfree) = NULL;
- void *tx_buf __free(kfree) = NULL;
- void *rx_buf __free(kfree) = NULL;
- int ret;
- fw_loader = kzalloc(sizeof(*fw_loader), GFP_KERNEL);
- if (!fw_loader)
- return -ENOMEM;
- tx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);
- if (!tx_buf)
- return -ENOMEM;
- rx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);
- if (!rx_buf)
- return -ENOMEM;
- fw_loader->tx_buf = tx_buf;
- fw_loader->rx_buf = rx_buf;
- fw_loader->tp = tp;
- fw_loader->dev = dev;
- ret = vsc_get_sensor_name(fw_loader, dev);
- if (ret)
- return ret;
- ret = vsc_identify_silicon(fw_loader);
- if (ret)
- return ret;
- ret = vsc_identify_csi_image(fw_loader);
- if (ret)
- return ret;
- ret = vsc_identify_ace_image(fw_loader);
- if (ret)
- goto err_release_csi;
- ret = vsc_identify_cfg_image(fw_loader);
- if (ret)
- goto err_release_ace;
- ret = vsc_download_bootloader(fw_loader);
- if (!ret)
- ret = vsc_download_firmware(fw_loader);
- release_firmware(fw_loader->cfg);
- err_release_ace:
- release_firmware(fw_loader->ace);
- err_release_csi:
- release_firmware(fw_loader->csi);
- return ret;
- }
- EXPORT_SYMBOL_NS_GPL(vsc_tp_init, VSC_TP);
|