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