blob: 20a7db19bd8e3aaeeea9108de3d5ed7c8e8a861f [file] [log] [blame]
developere5e687d2023-08-08 16:05:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
6 */
7
8#include <linux/arm-smccc.h>
9#include <linux/device.h>
10#include <linux/dma-mapping.h>
11#include <linux/err.h>
12#include <linux/firmware.h>
13#include <linux/io.h>
14#include <linux/of.h>
15#include <linux/of_device.h>
16#include <linux/of_platform.h>
17#include <linux/platform_device.h>
18
19#include "firmware.h"
20#include "internal.h"
21#include "mcu.h"
22
23#define TOPS_MGMT_IMG "mediatek/tops-mgmt.img"
24#define TOPS_OFFLOAD_IMG "mediatek/tops-offload.img"
25
26#define MTK_SIP_TOPS_LOAD 0xC2000560
27
28#define PAYLOAD_ALIGNMENT (32)
29
30#define TOPS_ITCM_BOOT_ADDR (0x40020000)
31#define TOPS_DTCM_BOOT_ADDR (0x40000000)
32#define TOPS_L2SRAM_BOOT_ADDR (0x4E100000)
33#define TOPS_DEFAULT_BOOT_ADDR (TOPS_ITCM_BOOT_ADDR)
34
35#define TOPS_FW_MAGIC (0x53504f54)
36#define TOPS_FW_HDR_VER (1)
37#define FW_HLEN (sizeof(struct tops_fw_header))
38#define FW_DATA(fw) ((fw)->data)
39#define FW_ROLE(fw) ((fw)->hdr.role)
40#define FW_PART_HLEN(fw) ((fw)->hdr.part_hdr_len)
41#define FW_PART_HDR(fw, idx) (FW_DATA(fw) + FW_PART_HLEN(fw) * (idx))
42#define FW_NUM_PARTS(fw) ((fw)->hdr.num_parts)
43#define FW_GIT_ID(fw) ((fw)->hdr.git_commit_id)
44#define FW_BUILD_TS(fw) ((fw)->hdr.build_ts)
45
46#define FW_PART_LOAD_ADDR_OVERRIDE (BIT(0))
47#define FW_PART_BOOT_OVERRIDE (BIT(1))
48
49enum tops_part_type {
50 TOPS_PART_TYPE_IRAM0,
51 TOPS_PART_TYPE_DRAM0,
52 TOPS_PART_TYPE_L2SRAM,
53 TOPS_PART_TYPE_METADATA,
54
55 __TOPS_PART_TYPE_MAX,
56};
57
58enum tops_plat_id {
59 TOPS_PLAT_MT7988,
60
61 __TOPS_PLAT_MAX,
62};
63
64struct tops_boot_config {
65 enum tops_part_type boot_type;
66 u32 boot_addr;
67};
68
69struct tops_fw_plat {
70 enum tops_plat_id plat;
71 u16 id;
72};
73
74struct tops_fw_header {
75 u32 magic;
76 u8 hdr_ver;
77 u8 api_ver;
78 u16 hdr_len;
79 u32 hdr_crc;
80 u16 plat_id;
81 u16 flags;
82 u64 git_commit_id;
83 u32 build_ts;
84 u8 role;
85 u8 signing_type;
86 u8 num_parts;
87 u8 part_hdr_len;
88 u32 part_hdr_crc;
89 u32 payload_len;
90 u32 payload_crc;
91 u32 sign_body_len;
92} __aligned(4);
93
94struct tops_fw_part_hdr {
95 u8 part_type;
96 u8 resv;
97 u16 flags;
98 u32 size;
99 u32 value[2];
100} __aligned(4);
101
102struct tops_fw_part {
103 const struct tops_fw_part_hdr *hdr[__TOPS_PART_TYPE_MAX];
104 const void *payload[__TOPS_PART_TYPE_MAX];
105};
106
107struct tops_fw {
108 struct tops_fw_header hdr;
109 u8 data[0];
110};
111
112struct tops_fw_attr {
113 char *property;
114 char *value;
115};
116
117struct tops_fw_info {
118 struct tops_fw_attr *attrs;
119 u64 git_commit_id;
120 u32 build_ts;
121 u32 nattr;
122};
123
124struct npu {
125 void __iomem *base;
126 struct device *dev;
127 struct tops_fw_info fw_info[__TOPS_ROLE_TYPE_MAX];
128};
129
130#if !defined(CONFIG_MTK_TOPS_SECURE_FW)
131static struct tops_boot_config tops_boot_configs[] = {
132 { .boot_type = TOPS_PART_TYPE_IRAM0, .boot_addr = TOPS_ITCM_BOOT_ADDR },
133 { .boot_type = TOPS_PART_TYPE_DRAM0, .boot_addr = TOPS_DTCM_BOOT_ADDR },
134 { .boot_type = TOPS_PART_TYPE_L2SRAM, .boot_addr = TOPS_L2SRAM_BOOT_ADDR},
135};
136
137static struct tops_fw_plat tops_plats[] = {
138 { .plat = TOPS_PLAT_MT7988, .id = 0x7988 },
139};
140#endif /* !defined(CONFIG_MTK_TOPS_SECURE_FW) */
141
142static struct npu npu;
143
144static inline void npu_write(u32 reg, u32 val)
145{
146 writel(val, npu.base + reg);
147}
148
149static inline void npu_set(u32 reg, u32 mask)
150{
151 setbits(npu.base + reg, mask);
152}
153
154static inline void npu_clr(u32 reg, u32 mask)
155{
156 clrbits(npu.base + reg, mask);
157}
158
159static inline void npu_rmw(u32 reg, u32 mask, u32 val)
160{
161 clrsetbits(npu.base + reg, mask, val);
162}
163
164static inline u32 npu_read(u32 reg)
165{
166 return readl(npu.base + reg);
167}
168
169u64 mtk_tops_fw_get_git_commit_id(enum tops_role_type rtype)
170{
171 if (rtype >= __TOPS_ROLE_TYPE_MAX)
172 return 0;
173
174 return npu.fw_info[rtype].git_commit_id;
175}
176
177void mtk_tops_fw_get_built_date(enum tops_role_type rtype, struct tm *tm)
178{
179 if (rtype >= __TOPS_ROLE_TYPE_MAX)
180 return;
181
182 time64_to_tm(npu.fw_info[rtype].build_ts, 0, tm);
183}
184
185u32 mtk_tops_fw_attr_get_num(enum tops_role_type rtype)
186{
187 if (rtype >= __TOPS_ROLE_TYPE_MAX)
188 return 0;
189
190 return npu.fw_info[rtype].nattr;
191}
192
193const char *mtk_tops_fw_attr_get_property(enum tops_role_type rtype, u32 idx)
194{
195 if (rtype >= __TOPS_ROLE_TYPE_MAX || idx >= npu.fw_info[rtype].nattr)
196 return NULL;
197
198 return npu.fw_info[rtype].attrs[idx].property;
199}
200
201const char *mtk_tops_fw_attr_get_value(enum tops_role_type rtype,
202 const char *property)
203{
204 u32 plen = strlen(property);
205 u32 nattr;
206 u32 i;
207
208 if (rtype >= __TOPS_ROLE_TYPE_MAX)
209 return NULL;
210
211 nattr = npu.fw_info[rtype].nattr;
212 for (i = 0; i < nattr; i++) {
213 if (!strncmp(property, npu.fw_info[rtype].attrs[i].property, plen))
214 return npu.fw_info[rtype].attrs[i].value;
215 }
216
217 return NULL;
218}
219
220static bool mtk_tops_fw_support_plat(const struct tops_fw_header *fw_hdr)
221{
222 u32 i;
223
224 for (i = 0; i < __TOPS_PLAT_MAX; i++)
225 if (le16_to_cpu(fw_hdr->plat_id) == tops_plats[i].plat)
226 return true;
227
228 return false;
229}
230
231static int mtk_tops_fw_valid_hdr(const struct tops_fw *tfw, uint32_t fw_size)
232{
233 const struct tops_fw_header *fw_hdr = &tfw->hdr;
234 u32 total_size;
235 u32 ph_len;
236
237 if (fw_size < FW_HLEN) {
238 TOPS_ERR("requested fw hlen is less than minimal TOPS fw hlen\n");
239 return -EINVAL;
240 }
241
242 if (le32_to_cpu(fw_hdr->magic) != TOPS_FW_MAGIC) {
243 TOPS_ERR("not a tops fw!\n");
244 return -EBADF;
245 }
246
247 if (le16_to_cpu(fw_hdr->hdr_ver) != TOPS_FW_HDR_VER) {
248 TOPS_ERR("unsupport tops fw header: %u\n",
249 le16_to_cpu(fw_hdr->hdr_ver));
250 return -EBADF;
251 }
252
253 if (le16_to_cpu(fw_hdr->hdr_len) != sizeof(struct tops_fw_header)) {
254 TOPS_ERR("tops fw header length mismatch\n");
255 return -EBADF;
256 }
257
258 if (fw_hdr->part_hdr_len != sizeof(struct tops_fw_part_hdr)) {
259 TOPS_ERR("unsupport tops fw header len: %u\n",
260 fw_hdr->part_hdr_len);
261 return -EBADF;
262 }
263
264 if (!mtk_tops_fw_support_plat(fw_hdr)) {
265 TOPS_ERR("unsupport tops platform fw: %u\n",
266 le16_to_cpu(fw_hdr->plat_id));
267 return -EBADF;
268 }
269
270 if (fw_hdr->role >= __TOPS_ROLE_TYPE_MAX) {
271 TOPS_ERR("unsupport tops role: %u\n", fw_hdr->role);
272 return -EBADF;
273 }
274
275 if (fw_hdr->num_parts > __TOPS_PART_TYPE_MAX) {
276 TOPS_ERR("number of parts exceeds tops' support: %u\n",
277 fw_hdr->num_parts);
278 return -EBADF;
279 }
280
281 ph_len = fw_hdr->part_hdr_len * fw_hdr->num_parts;
282 total_size = fw_hdr->hdr_len + ph_len + fw_hdr->payload_len;
283
284 if (total_size > fw_size) {
285 TOPS_ERR("firmware incomplete\n");
286 return -EBADF;
287 }
288
289 return 0;
290}
291
292static int mtk_tops_fw_init_part_data(const struct tops_fw *fw,
293 struct tops_fw_part *part)
294{
295 const struct tops_fw_part_hdr *phdr;
296 uint32_t part_off = FW_PART_HLEN(fw) * FW_NUM_PARTS(fw);
297 int ret = 0;
298 u8 i;
299
300 for (i = 0; i < FW_NUM_PARTS(fw); i++) {
301 /* get part hdr */
302 phdr = (struct tops_fw_part_hdr *)FW_PART_HDR(fw, i);
303 if (phdr->part_type >= __TOPS_PART_TYPE_MAX) {
304 TOPS_ERR("unknown part type: %u\n", phdr->part_type);
305 return -EBADF;
306 }
307
308 part->hdr[phdr->part_type] = phdr;
309
310 /* get part payload */
311 part->payload[phdr->part_type] = FW_DATA(fw) + part_off;
312
313 part_off += ALIGN(le32_to_cpu(phdr->size), PAYLOAD_ALIGNMENT);
314 }
315
316 return ret;
317}
318
319#if defined(CONFIG_MTK_TOPS_SECURE_FW)
320static int mtk_tops_fw_smc(u32 smc_id,
321 u64 x1,
322 u64 x2,
323 u64 x3,
324 u64 x4,
325 struct arm_smccc_res *res)
326{
327 if (!res)
328 return -EINVAL;
329
330 arm_smccc_smc(smc_id, x1, x2, x3, x4, 0, 0, 0, res);
331
332 return res->a0;
333}
334
335static int __mtk_tops_fw_bring_up_core(const void *fw, u32 fw_size)
336{
337 struct arm_smccc_res res = {0};
338 dma_addr_t fw_paddr;
339 void *fw_vaddr;
340 u32 order = 0;
341 u32 psize;
342 int ret;
343
344 psize = (fw_size / PAGE_SIZE) + 1;
345 while ((1 << order) < psize)
346 order++;
347
348 fw_vaddr = __get_free_pages(GFP_KERNEL, order);
349 if (!fw_vaddr)
350 return -ENOMEM;
351
352 memcpy(fw_vaddr, fw, fw_size);
353
354 fw_paddr = dma_map_single(tops_dev, fw_vaddr, PAGE_SIZE, DMA_TO_DEVICE);
355 if (dma_mapping_error(tops_dev, fw_paddr)) {
356 ret = -ENOMEM;
357 goto dma_map_err;
358 }
359 /* make sure firmware data is written and mapped to buffer */
360 wmb();
361
362 ret = mtk_tops_fw_smc(MTK_SIP_TOPS_LOAD, 0, fw_paddr, fw_size, 0, &res);
363 if (ret)
364 TOPS_ERR("tops secure firmware load failed: %d\n", ret);
365
366 dma_unmap_single(tops_dev, fw_paddr, fw_size, DMA_TO_DEVICE);
367
368dma_map_err:
369 free_pages(fw_vaddr, order);
370
371 return ret;
372}
373#else /* !defined(CONFIG_MTK_TOPS_SECURE_FW) */
374static u32 mtk_tops_fw_get_boot_addr(struct tops_fw_part *part)
375{
376 const struct tops_fw_part_hdr *hdr = NULL;
377 u32 boot_addr = TOPS_DEFAULT_BOOT_ADDR;
378 u32 i;
379
380 for (i = TOPS_PART_TYPE_IRAM0; i < __TOPS_PART_TYPE_MAX; i++) {
381 hdr = part->hdr[i];
382
383 if (le16_to_cpu(hdr->flags) & FW_PART_BOOT_OVERRIDE) {
384 boot_addr = tops_boot_configs[i].boot_addr;
385
386 if (le16_to_cpu(hdr->flags) & FW_PART_LOAD_ADDR_OVERRIDE)
387 boot_addr = le32_to_cpu(hdr->value[0]);
388 }
389 }
390
391 return boot_addr;
392}
393
394static void __mtk_tops_fw_load_data(const struct tops_fw_part_hdr *phdr,
395 const void *payload,
396 u32 addr)
397{
398 int ofs;
399
400 for (ofs = 0; ofs < le32_to_cpu(phdr->size); ofs += 0x4)
401 npu_write(addr + ofs, *(u32 *)(payload + ofs));
402}
403
404static int mtk_tops_fw_load_core_mgmt(struct tops_fw_part *part)
405{
406 if (!part)
407 return -ENODEV;
408
409 __mtk_tops_fw_load_data(part->hdr[TOPS_PART_TYPE_IRAM0],
410 part->payload[TOPS_PART_TYPE_IRAM0],
411 TOP_CORE_M_ITCM);
412
413 __mtk_tops_fw_load_data(part->hdr[TOPS_PART_TYPE_DRAM0],
414 part->payload[TOPS_PART_TYPE_DRAM0],
415 TOP_CORE_M_DTCM);
416
417 __mtk_tops_fw_load_data(part->hdr[TOPS_PART_TYPE_L2SRAM],
418 part->payload[TOPS_PART_TYPE_L2SRAM],
419 TOP_L2SRAM);
420
421 return 0;
422}
423
424static int mtk_tops_fw_bring_up_core_mgmt(struct tops_fw_part *part)
425{
426 int ret = 0;
427
428 /* setup boot address */
429 npu_write(TOP_CORE_M_RESET_VECTOR, mtk_tops_fw_get_boot_addr(part));
430
431 /* de-assert core reset */
432 npu_write(TOP_CORE_NPU_SW_RST, 0);
433
434 /* enable run stall */
435 npu_write(TOP_CORE_NPU_CTRL, 0x1);
436
437 /* enable ext bootup sel */
438 npu_write(TOP_CORE_M_STAT_VECTOR_SEL, 0x1);
439
440 /* toggle reset */
441 npu_write(TOP_CORE_NPU_SW_RST, 0x1);
442 npu_write(TOP_CORE_NPU_SW_RST, 0x0);
443
444 /* load firmware */
445 ret = mtk_tops_fw_load_core_mgmt(part);
446 if (ret) {
447 TOPS_ERR("load core mgmt fw failed: %d\n", ret);
448 return ret;
449 }
450
451 /* release run stall */
452 npu_write(TOP_CORE_NPU_CTRL, 0);
453
454 return ret;
455}
456
457static int mtk_tops_fw_load_core_offload(struct tops_fw_part *part,
458 enum core_id core)
459{
460 if (!part)
461 return -ENODEV;
462
463 if (core >= CORE_OFFLOAD_NUM)
464 return -EPERM;
465
466 __mtk_tops_fw_load_data(part->hdr[TOPS_PART_TYPE_IRAM0],
467 part->payload[TOPS_PART_TYPE_IRAM0],
468 CLUST_CORE_X_ITCM(core));
469
470 __mtk_tops_fw_load_data(part->hdr[TOPS_PART_TYPE_DRAM0],
471 part->payload[TOPS_PART_TYPE_DRAM0],
472 CLUST_CORE_X_DTCM(core));
473
474 return 0;
475}
476
477static int __mtk_tops_fw_bring_up_core_offload(struct tops_fw_part *part,
478 enum core_id core)
479{
480 int ret = 0;
481
482 /* setup boot address */
483 npu_write(CLUST_CORE_X_RESET_VECTOR(core),
484 mtk_tops_fw_get_boot_addr(part));
485
486 /* de-assert core reset */
487 npu_write(CLUST_CORE_NPU_SW_RST(core), 0);
488
489 /* enable run stall */
490 npu_write(CLUST_CORE_NPU_CTRL(core), 0x1);
491
492 /* enable ext bootup sel */
493 npu_write(CLUST_CORE_X_STAT_VECTOR_SEL(core), 0x1);
494
495 /* toggle reset */
496 npu_write(CLUST_CORE_NPU_SW_RST(core), 0x1);
497 npu_write(CLUST_CORE_NPU_SW_RST(core), 0x0);
498
499 /* load firmware */
500 ret = mtk_tops_fw_load_core_offload(part, core);
501 if (ret) {
502 TOPS_ERR("load core offload fw failed: %d\n", ret);
503 return ret;
504 }
505
506 /* release run stall */
507 npu_write(CLUST_CORE_NPU_CTRL(core), 0);
508
509 return ret;
510}
511
512static int mtk_tops_fw_bring_up_core_offload(struct tops_fw_part *part)
513{
514 int ret = 0;
515 u32 i = 0;
516
517 __mtk_tops_fw_load_data(part->hdr[TOPS_PART_TYPE_L2SRAM],
518 part->payload[TOPS_PART_TYPE_L2SRAM],
519 CLUST_L2SRAM);
520
521 for (i = 0; i < CORE_OFFLOAD_NUM; i++) {
522 ret = __mtk_tops_fw_bring_up_core_offload(part, i);
523 if (ret)
524 return ret;
525 }
526
527 return ret;
528}
529
530static int __mtk_tops_fw_bring_up_core(const struct tops_fw *tfw,
531 struct tops_fw_part *part)
532{
533 int ret = 0;
534
535 if (!tfw || !part)
536 return -EINVAL;
537
538 /* bring up core by role */
539 switch (FW_ROLE(tfw)) {
540 case TOPS_ROLE_TYPE_MGMT:
541 ret = mtk_tops_fw_bring_up_core_mgmt(part);
542
543 break;
544 case TOPS_ROLE_TYPE_CLUSTER:
545 ret = mtk_tops_fw_bring_up_core_offload(part);
546
547 break;
548 default:
549 TOPS_ERR("unsupport tops fw role\n");
550
551 return -EBADF;
552 }
553
554 return ret;
555}
556#endif /* defined(CONFIG_MTK_TOPS_SECURE_FW) */
557
558static int mtk_tops_fw_get_info(const struct tops_fw *tfw, struct tops_fw_part *part)
559{
560 const struct tops_fw_part_hdr *phdr;
561 const u8 *payload;
562 struct tops_fw_info *fw_info;
563 struct tops_fw_attr *attrs;
564 u32 kofs, klen, vofs, vlen;
565 u32 meta_len;
566 u32 ofs = 0;
567 u32 nattr;
568 u32 i;
569
570 if (!tfw || !part)
571 return -EINVAL;
572
573 if (FW_ROLE(tfw) > __TOPS_ROLE_TYPE_MAX)
574 return -EINVAL;
575
576 phdr = part->hdr[TOPS_PART_TYPE_METADATA];
577 payload = part->payload[TOPS_PART_TYPE_METADATA];
578 meta_len = le32_to_cpu(phdr->size);
579
580 if (!phdr || !payload || !meta_len)
581 return 0;
582
583 fw_info = &npu.fw_info[FW_ROLE(tfw)];
584 fw_info->nattr = nattr = le32_to_cpu(*((u32 *)payload));
585 ofs += 0x4;
586
587 fw_info->attrs = devm_kcalloc(tops_dev,
588 nattr * 2,
589 sizeof(char *),
590 GFP_KERNEL);
591 if (!fw_info->attrs) {
592 fw_info->nattr = 0;
593 return -ENOMEM;
594 }
595 attrs = fw_info->attrs;
596
597 for (i = 0; i < nattr; i++) {
598 struct tops_fw_attr *attr = &attrs[i];
599
600 /* get property offset */
601 if (ofs + (i * 2) * 0x4 >= meta_len)
602 break;
603 kofs = le32_to_cpu(*((u32 *)(payload + ofs + (i * 2) * 0x4)));
604
605 /* get value offset */
606 if (ofs + (i * 2 + 1) * 0x4 >= meta_len)
607 break;
608 vofs = le32_to_cpu(*((u32 *)(payload + ofs + (i * 2 + 1) * 0x4)));
609
610 klen = strlen(payload + kofs);
611 vlen = strlen(payload + vofs);
612 if (!kofs || !vofs || !klen || !vlen) {
613 TOPS_ERR("invalid attribute property value pair, kofs: %u, klen: %u, vofs: %u, vlen: %u\n",
614 kofs, klen, vofs, vlen);
615 break;
616 }
617
618 attr->property = devm_kzalloc(tops_dev,
619 sizeof(char) * klen + 1,
620 GFP_KERNEL);
621 if (!attr->property)
622 goto err_out;
623
624 attr->value = devm_kzalloc(tops_dev,
625 sizeof(char) * vlen + 1,
626 GFP_KERNEL);
627 if (!attr->value) {
628 devm_kfree(tops_dev, attr->property);
629 goto err_out;
630 }
631
632 strncpy(attr->property, payload + kofs, klen);
633 strncpy(attr->value, payload + vofs, vlen);
634 }
635
636 fw_info->git_commit_id = le64_to_cpu(FW_GIT_ID(tfw));
637 fw_info->build_ts = le32_to_cpu(FW_BUILD_TS(tfw));
638
639 return 0;
640
641err_out:
642 fw_info->git_commit_id = 0;
643 fw_info->build_ts = 0;
644
645 for (i = i - 1; i >= 0; i--) {
646 devm_kfree(tops_dev, attrs[i].property);
647 devm_kfree(tops_dev, attrs[i].value);
648 }
649
650 devm_kfree(tops_dev, attrs);
651
652 return -ENOMEM;
653}
654
655static void mtk_tops_fw_put_info(void)
656{
657 enum tops_role_type rtype;
658 struct tops_fw_attr *attrs;
659 u32 nattr;
660 u32 i;
661
662 for (rtype = TOPS_ROLE_TYPE_MGMT; rtype < __TOPS_ROLE_TYPE_MAX; rtype++) {
663 nattr = npu.fw_info[rtype].nattr;
664 attrs = npu.fw_info[rtype].attrs;
665
666 npu.fw_info[rtype].git_commit_id = 0;
667 npu.fw_info[rtype].build_ts = 0;
668
669 if (!nattr)
670 continue;
671
672 for (i = 0; i < nattr; i++) {
673 devm_kfree(tops_dev, attrs[i].property);
674 devm_kfree(tops_dev, attrs[i].value);
675 }
676
677 devm_kfree(tops_dev, attrs);
678
679 npu.fw_info[rtype].nattr = 0;
680 npu.fw_info[rtype].attrs = NULL;
681 }
682}
683
684int mtk_tops_fw_bring_up_core(const char *fw_path)
685{
686 const struct firmware *fw;
687 const struct tops_fw *tfw;
688 struct tops_fw_part part;
689 struct tm tm = {0};
690 int ret;
691
692 ret = request_firmware(&fw, fw_path, tops_dev);
693 if (ret) {
694 TOPS_ERR("request %s firmware failed\n", fw_path);
695 return ret;
696 }
697
698 tfw = (const void *)fw->data;
699
700 ret = mtk_tops_fw_valid_hdr(tfw, fw->size);
701 if (ret) {
702 TOPS_ERR("valid fw: %s image failed: %d\n", fw_path, ret);
703 goto err_out;
704 }
705
706 ret = mtk_tops_fw_init_part_data(tfw, &part);
707 if (ret) {
708 TOPS_ERR("init fw part data failed: %d\n", ret);
709 goto err_out;
710 }
711
712 ret = mtk_tops_fw_get_info(tfw, &part);
713 if (ret) {
714 TOPS_ERR("meta data initialize failed: %d\n", ret);
715 goto err_out;
716 }
717
718 ret = __mtk_tops_fw_bring_up_core(tfw, &part);
719 if (ret) {
720 TOPS_ERR("bring up core %s failed\n", fw_path);
721 mtk_tops_fw_put_info();
722 goto err_out;
723 }
724
725 mtk_tops_fw_get_built_date(FW_ROLE(tfw), &tm);
726
727 TOPS_NOTICE("TOPS Load Firmware: %s\n", fw_path);
728 TOPS_NOTICE("\tFirmware version:\t%s\n",
729 mtk_tops_fw_attr_get_value(FW_ROLE(tfw), "version"));
730 TOPS_NOTICE("\tGit revision:\t\t%llx\n",
731 mtk_tops_fw_get_git_commit_id(FW_ROLE(tfw)));
732 TOPS_NOTICE("\tBuilt date:\t\t%04ld/%02d/%02d %02d:%02d:%02d\n",
733 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
734 tm.tm_hour, tm.tm_min, tm.tm_sec);
735
736err_out:
737 release_firmware(fw);
738
739 return ret;
740}
741#if defined(CONFIG_MTK_TOPS_EVALUATION)
742EXPORT_SYMBOL(mtk_tops_fw_bring_up_core);
743#endif /* defined(CONFIG_MTK_TOPS_EVALUATION) */
744
745int mtk_tops_fw_bring_up_default_cores(void)
746{
747 int ret;
748
749 ret = mtk_tops_fw_bring_up_core(TOPS_MGMT_IMG);
750 if (ret)
751 return ret;
752
753 ret = mtk_tops_fw_bring_up_core(TOPS_OFFLOAD_IMG);
754
755 return ret;
756}
757
758#if defined(CONFIG_MTK_TOPS_CORE_DEBUG)
759static void mtk_tops_fw_enable_core_debug(void)
760{
761 u32 i;
762
763 npu_write(TOP_CORE_DBG_CTRL, 0x3F);
764 npu_write(CLUST_CORE_DBG_CTRL, 0x1F);
765
766 npu_write(TOP_CORE_OCD_CTRL, 0x1);
767
768 for (i = 0; i < CORE_OFFLOAD_NUM; i++)
769 npu_write(CLUST_CORE_OCD_CTRL(i), 0x1);
770}
771#endif /* defined(CONFIG_MTK_TOPS_CORE_DEBUG) */
772
773void mtk_tops_fw_clean_up(void)
774{
775 mtk_tops_fw_put_info();
776}
777
778int mtk_tops_fw_init(struct platform_device *pdev)
779{
780 struct resource *res;
781
782 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
783 if (!res)
784 return -ENXIO;
785
786 npu.base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
787 if (!npu.base)
788 return -ENOMEM;
789
790/* TODO: move to somewhere else */
791#if defined(CONFIG_MTK_TOPS_CORE_DEBUG)
792 mtk_tops_enable_core_debug();
793#endif /* defined(CONFIG_MTK_TOPS_CORE_DEBUG) */
794
795 return 0;
796}