summaryrefslogtreecommitdiff
path: root/drivers/common/firmware/firmware_drv.c (plain)
blob: fa21f0c39dce13e708eabc06ff9a9ff4576211a1
1/*
2 * drivers/amlogic/media/common/firmware/firmware.c
3 *
4 * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/types.h>
20#include <linux/fs.h>
21#include <linux/init.h>
22#include <linux/device.h>
23#include <linux/vmalloc.h>
24#include <linux/mm.h>
25#include <linux/slab.h>
26
27#include <linux/amlogic/media/utils/vformat.h>
28#include <linux/amlogic/cpu_version.h>
29#include "../../stream_input/amports/amports_priv.h"
30#include "../../frame_provider/decoder/utils/vdec.h"
31#include "firmware_priv.h"
32#include "../chips/chips.h"
33#include <linux/string.h>
34#include <linux/amlogic/media/utils/log.h>
35#include <linux/firmware.h>
36#include <linux/amlogic/tee.h>
37#include <linux/amlogic/major.h>
38#include <linux/cdev.h>
39#include <linux/crc32.h>
40#include "../chips/decoder_cpu_ver_info.h"
41
42/* major.minor */
43#define PACK_VERS "v0.2"
44
45#define CLASS_NAME "firmware_codec"
46#define DEV_NAME "firmware_vdec"
47#define DIR "video"
48#define FRIMWARE_SIZE (64 * 1024) /*64k*/
49#define BUFF_SIZE (1024 * 1024 * 2)
50
51#define FW_LOAD_FORCE (0x1)
52#define FW_LOAD_TRY (0X2)
53
54/*the first 256 bytes are signature data*/
55#define SEC_OFFSET (256)
56
57#define TRY_PARSE_MAX (256)
58
59#define PACK ('P' << 24 | 'A' << 16 | 'C' << 8 | 'K')
60#define CODE ('C' << 24 | 'O' << 16 | 'D' << 8 | 'E')
61
62#ifndef FIRMWARE_MAJOR
63#define FIRMWARE_MAJOR AMSTREAM_MAJOR
64#endif
65
66static DEFINE_MUTEX(mutex);
67
68static struct ucode_file_info_s ucode_info[] = {
69#include "firmware_cfg.h"
70};
71
72static const struct file_operations fw_fops = {
73 .owner = THIS_MODULE
74};
75
76struct fw_mgr_s *g_mgr;
77struct fw_dev_s *g_dev;
78
79static u32 debug;
80static u32 detail;
81
82int get_firmware_data(unsigned int format, char *buf)
83{
84 int data_len, ret = -1;
85 struct fw_mgr_s *mgr = g_mgr;
86 struct fw_info_s *info;
87
88 pr_info("[%s], the fw (%s) will be loaded.\n",
89 tee_enabled() ? "TEE" : "LOCAL",
90 get_fw_format_name(format));
91
92 if (tee_enabled())
93 return 0;
94
95 mutex_lock(&mutex);
96
97 if (list_empty(&mgr->fw_head)) {
98 pr_info("the info list is empty.\n");
99 goto out;
100 }
101
102 list_for_each_entry(info, &mgr->fw_head, node) {
103 if (format != info->format)
104 continue;
105
106 data_len = info->data->head.data_size;
107 memcpy(buf, info->data->data, data_len);
108 ret = data_len;
109
110 break;
111 }
112out:
113 mutex_unlock(&mutex);
114
115 return ret;
116}
117EXPORT_SYMBOL(get_firmware_data);
118
119int get_data_from_name(const char *name, char *buf)
120{
121 int data_len, ret = -1;
122 struct fw_mgr_s *mgr = g_mgr;
123 struct fw_info_s *info;
124 char *fw_name = __getname();
125
126 if (fw_name == NULL)
127 return -ENOMEM;
128
129 strcat(fw_name, name);
130 strcat(fw_name, ".bin");
131
132 mutex_lock(&mutex);
133
134 if (list_empty(&mgr->fw_head)) {
135 pr_info("the info list is empty.\n");
136 goto out;
137 }
138
139 list_for_each_entry(info, &mgr->fw_head, node) {
140 if (strcmp(fw_name, info->name))
141 continue;
142
143 data_len = info->data->head.data_size;
144 memcpy(buf, info->data->data, data_len);
145 ret = data_len;
146
147 break;
148 }
149out:
150 mutex_unlock(&mutex);
151
152 __putname(fw_name);
153
154 return ret;
155}
156EXPORT_SYMBOL(get_data_from_name);
157
158static int fw_probe(char *buf)
159{
160 int magic = 0;
161
162 memcpy(&magic, buf, sizeof(int));
163 return magic;
164}
165
166static int request_firmware_from_sys(const char *file_name,
167 char *buf, int size)
168{
169 int ret = -1;
170 const struct firmware *fw;
171 int magic, offset = 0;
172
173 pr_info("Try to load %s ...\n", file_name);
174
175 ret = request_firmware(&fw, file_name, g_dev->dev);
176 if (ret < 0) {
177 pr_info("Error : %d can't load the %s.\n", ret, file_name);
178 goto err;
179 }
180
181 if (fw->size > size) {
182 pr_info("Not enough memory size for ucode.\n");
183 ret = -ENOMEM;
184 goto release;
185 }
186
187 magic = fw_probe((char *)fw->data);
188 if (magic != PACK && magic != CODE) {
189 if (fw->size < SEC_OFFSET) {
190 pr_info("This is an invalid firmware file.\n");
191 goto release;
192 }
193
194 magic = fw_probe((char *)fw->data + SEC_OFFSET);
195 if (magic != PACK) {
196 pr_info("The firmware file is not packet.\n");
197 goto release;
198 }
199
200 offset = SEC_OFFSET;
201 }
202
203 memcpy(buf, (char *)fw->data + offset, fw->size - offset);
204
205 pr_info("load firmware size : %zd, Name : %s.\n",
206 fw->size, file_name);
207 ret = fw->size;
208release:
209 release_firmware(fw);
210err:
211 return ret;
212}
213
214int request_decoder_firmware_on_sys(enum vformat_e format,
215 const char *file_name, char *buf, int size)
216{
217 int ret;
218
219 ret = get_data_from_name(file_name, buf);
220 if (ret < 0)
221 pr_info("Get firmware fail.\n");
222
223 if (ret > size) {
224 pr_info("Not enough memory.\n");
225 return -ENOMEM;
226 }
227
228 return ret;
229}
230int get_decoder_firmware_data(enum vformat_e format,
231 const char *file_name, char *buf, int size)
232{
233 int ret;
234
235 ret = request_decoder_firmware_on_sys(format, file_name, buf, size);
236 if (ret < 0)
237 pr_info("get_decoder_firmware_data %s for format %d failed!\n",
238 file_name, format);
239
240 return ret;
241}
242EXPORT_SYMBOL(get_decoder_firmware_data);
243
244static unsigned long fw_mgr_lock(struct fw_mgr_s *mgr)
245{
246 unsigned long flags;
247
248 spin_lock_irqsave(&mgr->lock, flags);
249 return flags;
250}
251
252static void fw_mgr_unlock(struct fw_mgr_s *mgr, unsigned long flags)
253{
254 spin_unlock_irqrestore(&mgr->lock, flags);
255}
256
257static void fw_add_info(struct fw_info_s *info)
258{
259 unsigned long flags;
260 struct fw_mgr_s *mgr = g_mgr;
261
262 flags = fw_mgr_lock(mgr);
263 list_add(&info->node, &mgr->fw_head);
264 fw_mgr_unlock(mgr, flags);
265}
266
267static void fw_del_info(struct fw_info_s *info)
268{
269 unsigned long flags;
270 struct fw_mgr_s *mgr = g_mgr;
271
272 flags = fw_mgr_lock(mgr);
273 list_del(&info->node);
274 kfree(info);
275 fw_mgr_unlock(mgr, flags);
276}
277
278static void fw_info_walk(void)
279{
280 struct fw_mgr_s *mgr = g_mgr;
281 struct fw_info_s *info;
282
283 if (list_empty(&mgr->fw_head)) {
284 pr_info("the info list is empty.\n");
285 return;
286 }
287
288 list_for_each_entry(info, &mgr->fw_head, node) {
289 if (IS_ERR_OR_NULL(info->data))
290 continue;
291
292 pr_info("name : %s.\n", info->name);
293 pr_info("ver : %s.\n",
294 info->data->head.version);
295 pr_info("crc : 0x%x.\n",
296 info->data->head.checksum);
297 pr_info("size : %d.\n",
298 info->data->head.data_size);
299 pr_info("maker: %s.\n",
300 info->data->head.maker);
301 pr_info("from : %s.\n", info->src_from);
302 pr_info("date : %s.\n",
303 info->data->head.date);
304 if (info->data->head.duplicate)
305 pr_info("NOTE : Dup from %s.\n",
306 info->data->head.dup_from);
307 pr_info("\n");
308 }
309}
310
311static void fw_files_info_walk(void)
312{
313 struct fw_mgr_s *mgr = g_mgr;
314 struct fw_files_s *files;
315
316 if (list_empty(&mgr->files_head)) {
317 pr_info("the file list is empty.\n");
318 return;
319 }
320
321 list_for_each_entry(files, &mgr->files_head, node) {
322 pr_info("type : %s.\n", !files->fw_type ?
323 "VIDEO_DECODE" : files->fw_type == 1 ?
324 "VIDEO_ENCODE" : "VIDEO_MISC");
325 pr_info("from : %s.\n", !files->file_type ?
326 "VIDEO_PACKAGE" : "VIDEO_FW_FILE");
327 pr_info("path : %s.\n", files->path);
328 pr_info("name : %s.\n\n", files->name);
329 }
330}
331
332static ssize_t info_show(struct class *class,
333 struct class_attribute *attr, char *buf)
334{
335 char *pbuf = buf;
336 struct fw_mgr_s *mgr = g_mgr;
337 struct fw_info_s *info;
338 unsigned int secs = 0;
339 struct tm tm;
340
341 mutex_lock(&mutex);
342
343 if (list_empty(&mgr->fw_head)) {
344 pbuf += sprintf(pbuf, "No firmware.\n");
345 goto out;
346 }
347
348 /* shows version of driver. */
349 pr_info("The driver version is %s\n", PACK_VERS);
350
351 list_for_each_entry(info, &mgr->fw_head, node) {
352 if (IS_ERR_OR_NULL(info->data))
353 continue;
354
355 if (detail) {
356 pr_info("%-5s: %s\n", "name", info->name);
357 pr_info("%-5s: %s\n", "ver",
358 info->data->head.version);
359 pr_info("%-5s: 0x%x\n", "sum",
360 info->data->head.checksum);
361 pr_info("%-5s: %d\n", "size",
362 info->data->head.data_size);
363 pr_info("%-5s: %s\n", "maker",
364 info->data->head.maker);
365 pr_info("%-5s: %s\n", "from",
366 info->src_from);
367 pr_info("%-5s: %s\n\n", "date",
368 info->data->head.date);
369 continue;
370 }
371
372 secs = info->data->head.time
373 - sys_tz.tz_minuteswest * 60;
374 time_to_tm(secs, 0, &tm);
375
376 pr_info("%s %-16s, %02d:%02d:%02d %d/%d/%ld, %s %-8s, %s %-8s, %s %s\n",
377 "fmt:", info->data->head.format,
378 tm.tm_hour, tm.tm_min, tm.tm_sec,
379 tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900,
380 "cmtid:", info->data->head.commit,
381 "chgid:", info->data->head.change_id,
382 "mk:", info->data->head.maker);
383 }
384out:
385 mutex_unlock(&mutex);
386
387 return pbuf - buf;
388}
389
390static ssize_t info_store(struct class *cls,
391 struct class_attribute *attr, const char *buf, size_t count)
392{
393 if (kstrtoint(buf, 0, &detail) < 0)
394 return -EINVAL;
395
396 return count;
397}
398
399static int fw_info_fill(void)
400{
401 int ret = 0, i, len;
402 struct fw_mgr_s *mgr = g_mgr;
403 struct fw_files_s *files;
404 int info_size = ARRAY_SIZE(ucode_info);
405 char *path = __getname();
406 const char *name;
407
408 if (path == NULL)
409 return -ENOMEM;
410
411 for (i = 0; i < info_size; i++) {
412 name = ucode_info[i].name;
413 if (IS_ERR_OR_NULL(name))
414 break;
415
416 len = snprintf(path, PATH_MAX, "%s/%s", DIR,
417 ucode_info[i].name);
418 if (len >= PATH_MAX)
419 continue;
420
421 files = kzalloc(sizeof(struct fw_files_s), GFP_KERNEL);
422 if (files == NULL) {
423 __putname(path);
424 return -ENOMEM;
425 }
426
427 files->file_type = ucode_info[i].file_type;
428 files->fw_type = ucode_info[i].fw_type;
429 strncpy(files->path, path, sizeof(files->path));
430 files->path[sizeof(files->path) - 1] = '\0';
431 strncpy(files->name, name, sizeof(files->name));
432 files->name[sizeof(files->name) - 1] = '\0';
433
434 list_add(&files->node, &mgr->files_head);
435 }
436
437 __putname(path);
438
439 if (debug)
440 fw_files_info_walk();
441
442 return ret;
443}
444
445static int fw_data_check_sum(struct firmware_s *fw)
446{
447 unsigned int crc;
448
449 crc = crc32_le(~0U, fw->data, fw->head.data_size);
450
451 /*pr_info("firmware crc result : 0x%x\n", crc ^ ~0U);*/
452
453 return fw->head.checksum != (crc ^ ~0U) ? 0 : 1;
454}
455
456static int fw_data_filter(struct firmware_s *fw,
457 struct fw_info_s *fw_info)
458{
459 struct fw_mgr_s *mgr = g_mgr;
460 struct fw_info_s *info, *tmp;
461 int cpu = fw_get_cpu(fw->head.cpu);
462
463 if (mgr->cur_cpu < cpu) {
464 kfree(fw_info);
465 kfree(fw);
466 return -1;
467 }
468
469 /* the encode fw need to ignoring filtering rules. */
470 if (fw_info->format == FIRMWARE_MAX)
471 return 0;
472
473 list_for_each_entry_safe(info, tmp, &mgr->fw_head, node) {
474 if (info->format != fw_info->format)
475 continue;
476
477 if (IS_ERR_OR_NULL(info->data)) {
478 fw_del_info(info);
479 return 0;
480 }
481
482 /* high priority of VIDEO_FW_FILE */
483 if (info->file_type == VIDEO_FW_FILE) {
484 pr_info("the %s need to priority proc.\n",info->name);
485 kfree(fw_info);
486 kfree(fw);
487 return 1;
488 }
489
490 /* the cpu ver is lower and needs to be filtered */
491 if (cpu < fw_get_cpu(info->data->head.cpu)) {
492 if (debug)
493 pr_info("keep the newer fw (%s) and ignore the older fw (%s).\n",
494 info->name, fw_info->name);
495 kfree(fw_info);
496 kfree(fw);
497 return 1;
498 }
499
500 /* removes not match fw from info list */
501 if (debug)
502 pr_info("drop the old fw (%s) will be load the newer fw (%s).\n",
503 info->name, fw_info->name);
504 kfree(info->data);
505 fw_del_info(info);
506 }
507
508 return 0;
509}
510
511static int fw_replace_dup_data(char *buf)
512{
513 int ret = 0;
514 struct fw_mgr_s *mgr = g_mgr;
515 struct package_s *pkg =
516 (struct package_s *) buf;
517 struct package_info_s *pinfo =
518 (struct package_info_s *) pkg->data;
519 struct fw_info_s *info = NULL;
520 char *pdata = pkg->data;
521 int try_cnt = TRY_PARSE_MAX;
522
523 do {
524 if (!pinfo->head.length)
525 break;
526 list_for_each_entry(info, &mgr->fw_head, node) {
527 struct firmware_s *comp = NULL;
528 struct firmware_s *data = NULL;
529 int len = 0;
530
531 comp = (struct firmware_s *)pinfo->data;
532 if (comp->head.duplicate)
533 break;
534
535 if (!info->data->head.duplicate ||
536 comp->head.checksum !=
537 info->data->head.checksum)
538 continue;
539
540 len = pinfo->head.length;
541 data = kzalloc(len, GFP_KERNEL);
542 if (data == NULL) {
543 ret = -ENOMEM;
544 goto out;
545 }
546
547 memcpy(data, pinfo->data, len);
548 memcpy(data, info->data, sizeof(*data));
549
550 kfree(info->data);
551 info->data = data;
552 }
553 pdata += (pinfo->head.length + sizeof(*pinfo));
554 pinfo = (struct package_info_s *)pdata;
555 } while (try_cnt--);
556out:
557 return ret;
558}
559
560static int fw_check_pack_version(char *buf)
561{
562 struct package_s *pack = NULL;
563 int major, minor, major_fw, minor_fw;
564 int ret;
565
566 pack = (struct package_s *) buf;
567 ret = sscanf(PACK_VERS, "v%x.%x", &major, &minor);
568 if (ret != 2)
569 return -1;
570
571 major_fw = (pack->head.version >> 16) & 0xff;
572 minor_fw = pack->head.version & 0xff;
573
574 if (major < major_fw) {
575 pr_info("the pack ver v%d.%d too higher to unsupport.\n",
576 major_fw, minor_fw);
577 return -1;
578 }
579
580 if (minor < minor_fw) {
581 pr_info("The fw driver version (v%d.%d) is lower than the pkg version (v%d.%d).\n",
582 major, minor, major_fw, minor_fw);
583 pr_info("The driver version is too low that may affect the work please update asap.\n");
584 }
585
586 if (debug) {
587 pr_info("The package has %d fws totally.\n", pack->head.total);
588 pr_info("The driver ver is v%d.%d\n", major, minor);
589 pr_info("The firmware ver is v%d.%d\n", major_fw, minor_fw);
590 }
591
592 return 0;
593}
594
595static int fw_package_parse(struct fw_files_s *files,
596 char *buf, int size)
597{
598 int ret = 0;
599 struct package_info_s *pack_info;
600 struct fw_info_s *info;
601 struct firmware_s *data;
602 char *pack_data;
603 int info_len, len;
604 int try_cnt = TRY_PARSE_MAX;
605 char *path = __getname();
606
607 if (path == NULL)
608 return -ENOMEM;
609
610 pack_data = ((struct package_s *)buf)->data;
611 pack_info = (struct package_info_s *)pack_data;
612 info_len = sizeof(struct package_info_s);
613
614 do {
615 if (!pack_info->head.length)
616 break;
617
618 len = snprintf(path, PATH_MAX, "%s/%s", DIR,
619 pack_info->head.name);
620 if (len >= PATH_MAX)
621 continue;
622
623 info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL);
624 if (info == NULL) {
625 ret = -ENOMEM;
626 goto out;
627 }
628
629 data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL);
630 if (data == NULL) {
631 kfree(info);
632 ret = -ENOMEM;
633 goto out;
634 }
635
636 info->file_type = files->file_type;
637 strncpy(info->src_from, files->name,
638 sizeof(info->src_from));
639 info->src_from[sizeof(info->src_from) - 1] = '\0';
640 strncpy(info->name, pack_info->head.name,
641 sizeof(info->name));
642 info->name[sizeof(info->name) - 1] = '\0';
643 info->format = get_fw_format(pack_info->head.format);
644
645 len = pack_info->head.length;
646 memcpy(data, pack_info->data, len);
647
648 pack_data += (pack_info->head.length + info_len);
649 pack_info = (struct package_info_s *)pack_data;
650
651 if (!data->head.duplicate &&
652 !fw_data_check_sum(data)) {
653 pr_info("check sum fail !\n");
654 kfree(data);
655 kfree(info);
656 goto out;
657 }
658
659 if (fw_data_filter(data, info))
660 continue;
661
662 if (debug)
663 pr_info("adds %s to the fw list.\n", info->name);
664
665 info->data = data;
666 fw_add_info(info);
667 } while (try_cnt--);
668
669 /* process the fw of dup attribute. */
670 ret = fw_replace_dup_data(buf);
671 if (ret)
672 pr_err("replace dup fw failed.\n");
673out:
674 __putname(path);
675
676 return ret;
677}
678
679static int fw_code_parse(struct fw_files_s *files,
680 char *buf, int size)
681{
682 struct fw_info_s *info;
683
684 info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL);
685 if (info == NULL)
686 return -ENOMEM;
687
688 info->data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL);
689 if (info->data == NULL) {
690 kfree(info);
691 return -ENOMEM;
692 }
693
694 info->file_type = files->file_type;
695 strncpy(info->src_from, files->name,
696 sizeof(info->src_from));
697 info->src_from[sizeof(info->src_from) - 1] = '\0';
698 memcpy(info->data, buf, size);
699
700 if (!fw_data_check_sum(info->data)) {
701 pr_info("check sum fail !\n");
702 kfree(info->data);
703 kfree(info);
704 return -1;
705 }
706
707 if (debug)
708 pr_info("adds %s to the fw list.\n", info->name);
709
710 fw_add_info(info);
711
712 return 0;
713}
714
715static int get_firmware_from_sys(const char *path,
716 char *buf, int size)
717{
718 int len = 0;
719
720 len = request_firmware_from_sys(path, buf, size);
721 if (len < 0)
722 pr_info("get data from fsys fail.\n");
723
724 return len;
725}
726
727static int fw_data_binding(void)
728{
729 int ret = 0, magic = 0;
730 struct fw_mgr_s *mgr = g_mgr;
731 struct fw_files_s *files, *tmp;
732 char *buf = NULL;
733 int size;
734
735 if (list_empty(&mgr->files_head)) {
736 pr_info("the file list is empty.\n");
737 return 0;
738 }
739
740 buf = vmalloc(BUFF_SIZE);
741 if (IS_ERR_OR_NULL(buf))
742 return -ENOMEM;
743
744 memset(buf, 0, BUFF_SIZE);
745
746 list_for_each_entry_safe(files, tmp, &mgr->files_head, node) {
747 size = get_firmware_from_sys(files->path, buf, BUFF_SIZE);
748 magic = fw_probe(buf);
749
750 if (files->file_type == VIDEO_PACKAGE && magic == PACK) {
751 if (!fw_check_pack_version(buf))
752 ret = fw_package_parse(files, buf, size);
753 } else if (files->file_type == VIDEO_FW_FILE && magic == CODE) {
754 ret = fw_code_parse(files, buf, size);
755 } else {
756 list_del(&files->node);
757 kfree(files);
758 pr_info("invaild file type.\n");
759 }
760
761 memset(buf, 0, BUFF_SIZE);
762 }
763
764 if (debug)
765 fw_info_walk();
766
767 vfree(buf);
768
769 return ret;
770}
771
772static int fw_pre_load(void)
773{
774 if (fw_info_fill() < 0) {
775 pr_info("Get path fail.\n");
776 return -1;
777 }
778
779 if (fw_data_binding() < 0) {
780 pr_info("Set data fail.\n");
781 return -1;
782 }
783
784 return 0;
785}
786
787static int fw_mgr_init(void)
788{
789 g_mgr = kzalloc(sizeof(struct fw_mgr_s), GFP_KERNEL);
790 if (IS_ERR_OR_NULL(g_mgr))
791 return -ENOMEM;
792
793 g_mgr->cur_cpu = get_cpu_major_id();
794 INIT_LIST_HEAD(&g_mgr->files_head);
795 INIT_LIST_HEAD(&g_mgr->fw_head);
796 spin_lock_init(&g_mgr->lock);
797
798 return 0;
799}
800
801static void fw_ctx_clean(void)
802{
803 struct fw_mgr_s *mgr = g_mgr;
804 struct fw_files_s *files;
805 struct fw_info_s *info;
806 unsigned long flags;
807
808 flags = fw_mgr_lock(mgr);
809 while (!list_empty(&mgr->files_head)) {
810 files = list_entry(mgr->files_head.next,
811 struct fw_files_s, node);
812 list_del(&files->node);
813 kfree(files);
814 }
815
816 while (!list_empty(&mgr->fw_head)) {
817 info = list_entry(mgr->fw_head.next,
818 struct fw_info_s, node);
819 list_del(&info->node);
820 kfree(info->data);
821 kfree(info);
822 }
823 fw_mgr_unlock(mgr, flags);
824}
825
826int video_fw_reload(int mode)
827{
828 int ret = 0;
829 struct fw_mgr_s *mgr = g_mgr;
830
831 if (tee_enabled())
832 return 0;
833
834 mutex_lock(&mutex);
835
836 if (mode & FW_LOAD_FORCE) {
837 fw_ctx_clean();
838
839 ret = fw_pre_load();
840 if (ret < 0)
841 pr_err("The fw reload fail.\n");
842 } else if (mode & FW_LOAD_TRY) {
843 if (!list_empty(&mgr->fw_head)) {
844 pr_info("The fw has been loaded.\n");
845 goto out;
846 }
847
848 ret = fw_pre_load();
849 if (ret < 0)
850 pr_err("The fw try to reload fail.\n");
851 }
852out:
853 mutex_unlock(&mutex);
854
855 return ret;
856}
857EXPORT_SYMBOL(video_fw_reload);
858
859static ssize_t reload_show(struct class *class,
860 struct class_attribute *attr, char *buf)
861{
862 char *pbuf = buf;
863
864 pbuf += sprintf(pbuf, "The fw reload usage.\n");
865 pbuf += sprintf(pbuf, "> set 1 means that the fw is forced to update\n");
866 pbuf += sprintf(pbuf, "> set 2 means that the fw is try to reload\n");
867
868 return pbuf - buf;
869}
870
871static ssize_t reload_store(struct class *class,
872 struct class_attribute *attr,
873 const char *buf, size_t size)
874{
875 int ret = -1;
876 unsigned int val;
877
878 ret = kstrtoint(buf, 0, &val);
879 if (ret != 0)
880 return -EINVAL;
881
882 ret = video_fw_reload(val);
883 if (ret < 0)
884 pr_err("fw reload fail.\n");
885
886 return size;
887}
888
889static ssize_t debug_show(struct class *cls,
890 struct class_attribute *attr, char *buf)
891{
892 return sprintf(buf, "%x\n", debug);
893}
894
895static ssize_t debug_store(struct class *cls,
896 struct class_attribute *attr, const char *buf, size_t count)
897{
898 if (kstrtoint(buf, 0, &debug) < 0)
899 return -EINVAL;
900
901 return count;
902}
903
904static struct class_attribute fw_class_attrs[] = {
905 __ATTR(info, 0664, info_show, info_store),
906 __ATTR(reload, 0664, reload_show, reload_store),
907 __ATTR(debug, 0664, debug_show, debug_store),
908 __ATTR_NULL
909};
910
911static struct class fw_class = {
912 .name = CLASS_NAME,
913 .class_attrs = fw_class_attrs,
914};
915
916static int fw_driver_init(void)
917{
918 int ret = -1;
919
920 g_dev = kzalloc(sizeof(struct fw_dev_s), GFP_KERNEL);
921 if (IS_ERR_OR_NULL(g_dev))
922 return -ENOMEM;
923
924 g_dev->dev_no = MKDEV(FIRMWARE_MAJOR, 100);
925
926 ret = register_chrdev_region(g_dev->dev_no, 1, DEV_NAME);
927 if (ret < 0) {
928 pr_info("Can't get major number %d.\n", FIRMWARE_MAJOR);
929 goto err;
930 }
931
932 cdev_init(&g_dev->cdev, &fw_fops);
933 g_dev->cdev.owner = THIS_MODULE;
934
935 ret = cdev_add(&g_dev->cdev, g_dev->dev_no, 1);
936 if (ret) {
937 pr_info("Error %d adding cdev fail.\n", ret);
938 goto err;
939 }
940
941 ret = class_register(&fw_class);
942 if (ret < 0) {
943 pr_info("Failed in creating class.\n");
944 goto err;
945 }
946
947 g_dev->dev = device_create(&fw_class, NULL,
948 g_dev->dev_no, NULL, DEV_NAME);
949 if (IS_ERR_OR_NULL(g_dev->dev)) {
950 pr_info("Create device failed.\n");
951 ret = -ENODEV;
952 goto err;
953 }
954
955 pr_info("Registered firmware driver success.\n");
956err:
957 return ret;
958}
959
960static void fw_driver_exit(void)
961{
962 cdev_del(&g_dev->cdev);
963 device_destroy(&fw_class, g_dev->dev_no);
964 class_unregister(&fw_class);
965 unregister_chrdev_region(g_dev->dev_no, 1);
966 kfree(g_dev);
967 kfree(g_mgr);
968}
969
970static int __init fw_module_init(void)
971{
972 int ret = -1;
973
974 ret = fw_driver_init();
975 if (ret) {
976 pr_info("Error %d firmware driver init fail.\n", ret);
977 goto err;
978 }
979
980 ret = fw_mgr_init();
981 if (ret) {
982 pr_info("Error %d firmware mgr init fail.\n", ret);
983 goto err;
984 }
985
986 ret = fw_pre_load();
987 if (ret) {
988 pr_info("Error %d firmware pre load fail.\n", ret);
989 goto err;
990 }
991err:
992 return ret;
993}
994
995static void __exit fw_module_exit(void)
996{
997 fw_ctx_clean();
998 fw_driver_exit();
999 pr_info("Firmware driver cleaned up.\n");
1000}
1001
1002module_init(fw_module_init);
1003module_exit(fw_module_exit);
1004
1005MODULE_LICENSE("GPL");
1006MODULE_AUTHOR("Nanxin Qin <nanxin.qin@amlogic.com>");
1007