blob: 646212f7b05b9114105c0f536ba48ca7f3386edf [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
developer0b3c7712023-08-24 16:23:03 +0800380 for (i = TOPS_PART_TYPE_IRAM0; i < TOPS_PART_TYPE_METADATA; i++) {
developere5e687d2023-08-08 16:05:33 +0800381 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;
developer0b3c7712023-08-24 16:23:03 +0800568 int i;
developere5e687d2023-08-08 16:05:33 +0800569
570 if (!tfw || !part)
571 return -EINVAL;
572
developer0b3c7712023-08-24 16:23:03 +0800573 if (FW_ROLE(tfw) >= __TOPS_ROLE_TYPE_MAX)
developere5e687d2023-08-08 16:05:33 +0800574 return -EINVAL;
575
576 phdr = part->hdr[TOPS_PART_TYPE_METADATA];
577 payload = part->payload[TOPS_PART_TYPE_METADATA];
developer0b3c7712023-08-24 16:23:03 +0800578 if (!phdr || !payload)
579 return 0;
developere5e687d2023-08-08 16:05:33 +0800580
developer0b3c7712023-08-24 16:23:03 +0800581 meta_len = le32_to_cpu(phdr->size);
582 if (!meta_len)
developere5e687d2023-08-08 16:05:33 +0800583 return 0;
584
585 fw_info = &npu.fw_info[FW_ROLE(tfw)];
586 fw_info->nattr = nattr = le32_to_cpu(*((u32 *)payload));
587 ofs += 0x4;
588
589 fw_info->attrs = devm_kcalloc(tops_dev,
590 nattr * 2,
591 sizeof(char *),
592 GFP_KERNEL);
593 if (!fw_info->attrs) {
594 fw_info->nattr = 0;
595 return -ENOMEM;
596 }
597 attrs = fw_info->attrs;
598
599 for (i = 0; i < nattr; i++) {
600 struct tops_fw_attr *attr = &attrs[i];
601
602 /* get property offset */
603 if (ofs + (i * 2) * 0x4 >= meta_len)
604 break;
605 kofs = le32_to_cpu(*((u32 *)(payload + ofs + (i * 2) * 0x4)));
606
607 /* get value offset */
608 if (ofs + (i * 2 + 1) * 0x4 >= meta_len)
609 break;
610 vofs = le32_to_cpu(*((u32 *)(payload + ofs + (i * 2 + 1) * 0x4)));
611
612 klen = strlen(payload + kofs);
613 vlen = strlen(payload + vofs);
614 if (!kofs || !vofs || !klen || !vlen) {
615 TOPS_ERR("invalid attribute property value pair, kofs: %u, klen: %u, vofs: %u, vlen: %u\n",
616 kofs, klen, vofs, vlen);
617 break;
618 }
619
620 attr->property = devm_kzalloc(tops_dev,
621 sizeof(char) * klen + 1,
622 GFP_KERNEL);
623 if (!attr->property)
624 goto err_out;
625
626 attr->value = devm_kzalloc(tops_dev,
627 sizeof(char) * vlen + 1,
628 GFP_KERNEL);
629 if (!attr->value) {
630 devm_kfree(tops_dev, attr->property);
631 goto err_out;
632 }
633
634 strncpy(attr->property, payload + kofs, klen);
635 strncpy(attr->value, payload + vofs, vlen);
636 }
637
638 fw_info->git_commit_id = le64_to_cpu(FW_GIT_ID(tfw));
639 fw_info->build_ts = le32_to_cpu(FW_BUILD_TS(tfw));
640
641 return 0;
642
643err_out:
644 fw_info->git_commit_id = 0;
645 fw_info->build_ts = 0;
646
647 for (i = i - 1; i >= 0; i--) {
648 devm_kfree(tops_dev, attrs[i].property);
649 devm_kfree(tops_dev, attrs[i].value);
650 }
651
652 devm_kfree(tops_dev, attrs);
653
654 return -ENOMEM;
655}
656
657static void mtk_tops_fw_put_info(void)
658{
659 enum tops_role_type rtype;
660 struct tops_fw_attr *attrs;
661 u32 nattr;
662 u32 i;
663
664 for (rtype = TOPS_ROLE_TYPE_MGMT; rtype < __TOPS_ROLE_TYPE_MAX; rtype++) {
665 nattr = npu.fw_info[rtype].nattr;
666 attrs = npu.fw_info[rtype].attrs;
667
668 npu.fw_info[rtype].git_commit_id = 0;
669 npu.fw_info[rtype].build_ts = 0;
670
671 if (!nattr)
672 continue;
673
674 for (i = 0; i < nattr; i++) {
675 devm_kfree(tops_dev, attrs[i].property);
676 devm_kfree(tops_dev, attrs[i].value);
677 }
678
679 devm_kfree(tops_dev, attrs);
680
681 npu.fw_info[rtype].nattr = 0;
682 npu.fw_info[rtype].attrs = NULL;
683 }
684}
685
686int mtk_tops_fw_bring_up_core(const char *fw_path)
687{
688 const struct firmware *fw;
689 const struct tops_fw *tfw;
690 struct tops_fw_part part;
691 struct tm tm = {0};
692 int ret;
693
694 ret = request_firmware(&fw, fw_path, tops_dev);
695 if (ret) {
696 TOPS_ERR("request %s firmware failed\n", fw_path);
697 return ret;
698 }
699
700 tfw = (const void *)fw->data;
701
702 ret = mtk_tops_fw_valid_hdr(tfw, fw->size);
703 if (ret) {
704 TOPS_ERR("valid fw: %s image failed: %d\n", fw_path, ret);
705 goto err_out;
706 }
707
708 ret = mtk_tops_fw_init_part_data(tfw, &part);
709 if (ret) {
710 TOPS_ERR("init fw part data failed: %d\n", ret);
711 goto err_out;
712 }
713
714 ret = mtk_tops_fw_get_info(tfw, &part);
715 if (ret) {
716 TOPS_ERR("meta data initialize failed: %d\n", ret);
717 goto err_out;
718 }
719
720 ret = __mtk_tops_fw_bring_up_core(tfw, &part);
721 if (ret) {
722 TOPS_ERR("bring up core %s failed\n", fw_path);
723 mtk_tops_fw_put_info();
724 goto err_out;
725 }
726
727 mtk_tops_fw_get_built_date(FW_ROLE(tfw), &tm);
728
729 TOPS_NOTICE("TOPS Load Firmware: %s\n", fw_path);
730 TOPS_NOTICE("\tFirmware version:\t%s\n",
731 mtk_tops_fw_attr_get_value(FW_ROLE(tfw), "version"));
732 TOPS_NOTICE("\tGit revision:\t\t%llx\n",
733 mtk_tops_fw_get_git_commit_id(FW_ROLE(tfw)));
734 TOPS_NOTICE("\tBuilt date:\t\t%04ld/%02d/%02d %02d:%02d:%02d\n",
735 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
736 tm.tm_hour, tm.tm_min, tm.tm_sec);
737
738err_out:
739 release_firmware(fw);
740
741 return ret;
742}
743#if defined(CONFIG_MTK_TOPS_EVALUATION)
744EXPORT_SYMBOL(mtk_tops_fw_bring_up_core);
745#endif /* defined(CONFIG_MTK_TOPS_EVALUATION) */
746
747int mtk_tops_fw_bring_up_default_cores(void)
748{
749 int ret;
750
751 ret = mtk_tops_fw_bring_up_core(TOPS_MGMT_IMG);
752 if (ret)
753 return ret;
754
755 ret = mtk_tops_fw_bring_up_core(TOPS_OFFLOAD_IMG);
756
757 return ret;
758}
759
760#if defined(CONFIG_MTK_TOPS_CORE_DEBUG)
761static void mtk_tops_fw_enable_core_debug(void)
762{
763 u32 i;
764
765 npu_write(TOP_CORE_DBG_CTRL, 0x3F);
766 npu_write(CLUST_CORE_DBG_CTRL, 0x1F);
767
768 npu_write(TOP_CORE_OCD_CTRL, 0x1);
769
770 for (i = 0; i < CORE_OFFLOAD_NUM; i++)
771 npu_write(CLUST_CORE_OCD_CTRL(i), 0x1);
772}
773#endif /* defined(CONFIG_MTK_TOPS_CORE_DEBUG) */
774
775void mtk_tops_fw_clean_up(void)
776{
777 mtk_tops_fw_put_info();
778}
779
780int mtk_tops_fw_init(struct platform_device *pdev)
781{
782 struct resource *res;
783
784 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
785 if (!res)
786 return -ENXIO;
787
788 npu.base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
789 if (!npu.base)
790 return -ENOMEM;
791
792/* TODO: move to somewhere else */
793#if defined(CONFIG_MTK_TOPS_CORE_DEBUG)
794 mtk_tops_enable_core_debug();
795#endif /* defined(CONFIG_MTK_TOPS_CORE_DEBUG) */
796
797 return 0;
798}