1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2023, Intel Corporation.
4 * Intel Visual Sensing Controller Transport Layer Linux driver
5 */
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 <asm-generic/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 0xE0030000
27#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 0
32
33#define VSC_SUBSTEPPING_VERSION_MASK GENMASK(3, 0)
34#define VSC_SUBSTEPPING_VERSION_0 0
35#define VSC_SUBSTEPPING_VERSION_1 2
36
37#define VSC_BOOT_IMG_OPTION_MASK GENMASK(15, 0)
38
39#define VSC_SKU_CFG_LOCATION 0x5001A000
40#define VSC_SKU_MAX_SIZE 4100u
41
42#define VSC_ACE_IMG_CNT 2
43#define VSC_CSI_IMG_CNT 4
44#define VSC_IMG_CNT_MAX 6
45
46#define VSC_ROM_PKG_SIZE 256u
47#define VSC_FW_PKG_SIZE 512u
48
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 64
56
57#define VSC_SENSOR_NAME_MAX_LEN 16
58
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_MAX
98};
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 loader
207 * @dev: device used to request fimware
208 * @tp: transport layer used with the firmware loader
209 * @csi: CSI image
210 * @ace: ACE image
211 * @cfg: config image
212 * @tx_buf: tx buffer
213 * @rx_buf: rx buffer
214 * @option: command option
215 * @count: total image count
216 * @sensor_name: camera sensor name
217 * @frags: image fragments
218 */
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 .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(object: handle, pathname: "SID", parameter_objects: &arg_list, return_object_buffer: &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(dst: fw_loader->sensor_name, src: 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(tp: fw_loader->tp, obuf: cmd, ibuf: 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(tp: fw_loader->tp, obuf: cmd, ibuf: 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(tp: fw_loader->tp, obuf: cmd, ibuf: 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(tp: fw_loader->tp, obuf: cmd, ibuf: 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(fw: &image, VSC_CSI_IMAGE_NAME, device: 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(fw: 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(buf: path, size: sizeof(path), VSC_ACE_IMAGE_NAME_FMT,
459 fw_loader->sensor_name);
460
461 ret = request_firmware(fw: &image, name: path, device: 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(fw: 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(buf: path, size: sizeof(path), VSC_CFG_IMAGE_NAME_FMT,
541 fw_loader->sensor_name);
542
543 ret = request_firmware(fw: &image, name: path, device: 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(fw: 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(tp: fw_loader->tp, obuf: cmd, ibuf: 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(tp: fw_loader->tp, obuf: 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(tp: fw_loader->tp, obuf: 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(val: fw_loader->option, p: &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(tp: fw_loader->tp, obuf: 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(val: fw_loader->option, p: &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(tp: fw_loader->tp, obuf: 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(tp: fw_loader->tp, obuf: 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(tp: fw_loader->tp, obuf: cmd, NULL, VSC_FW_PKG_SIZE);
703}
704
705/**
706 * vsc_tp_init - init vsc_tp
707 * @tp: vsc_tp device handle
708 * @dev: device node for mei vsc device
709 * Return: 0 in case of success, negative value in case of error
710 */
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(size: 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: fw_loader->cfg);
761
762err_release_ace:
763 release_firmware(fw: fw_loader->ace);
764
765err_release_csi:
766 release_firmware(fw: fw_loader->csi);
767
768 return ret;
769}
770EXPORT_SYMBOL_NS_GPL(vsc_tp_init, VSC_TP);
771

source code of linux/drivers/misc/mei/vsc-fw-loader.c