.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2016 MediaTek Inc. |
---|
3 | 4 | * Author: Andrew-CT Chen <andrew-ct.chen@mediatek.com> |
---|
4 | | -* |
---|
5 | | -* This program is free software; you can redistribute it and/or modify |
---|
6 | | -* it under the terms of the GNU General Public License version 2 as |
---|
7 | | -* published by the Free Software Foundation. |
---|
8 | | -* |
---|
9 | | -* This program is distributed in the hope that it will be useful, |
---|
10 | | -* but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
12 | | -* GNU General Public License for more details. |
---|
13 | 5 | */ |
---|
14 | 6 | #include <linux/clk.h> |
---|
15 | 7 | #include <linux/debugfs.h> |
---|
.. | .. |
---|
54 | 46 | /* binary firmware name */ |
---|
55 | 47 | #define VPU_P_FW "vpu_p.bin" |
---|
56 | 48 | #define VPU_D_FW "vpu_d.bin" |
---|
| 49 | +#define VPU_P_FW_NEW "mediatek/mt8173/vpu_p.bin" |
---|
| 50 | +#define VPU_D_FW_NEW "mediatek/mt8173/vpu_d.bin" |
---|
57 | 51 | |
---|
58 | 52 | #define VPU_RESET 0x0 |
---|
59 | 53 | #define VPU_TCM_CFG 0x0008 |
---|
.. | .. |
---|
211 | 205 | struct vpu_run run; |
---|
212 | 206 | struct vpu_wdt wdt; |
---|
213 | 207 | struct vpu_ipi_desc ipi_desc[IPI_MAX]; |
---|
214 | | - struct share_obj *recv_buf; |
---|
215 | | - struct share_obj *send_buf; |
---|
| 208 | + struct share_obj __iomem *recv_buf; |
---|
| 209 | + struct share_obj __iomem *send_buf; |
---|
216 | 210 | struct device *dev; |
---|
217 | 211 | struct clk *clk; |
---|
218 | 212 | bool fw_loaded; |
---|
.. | .. |
---|
281 | 275 | return -EPROBE_DEFER; |
---|
282 | 276 | } |
---|
283 | 277 | |
---|
284 | | - if (id >= 0 && id < IPI_MAX && handler) { |
---|
| 278 | + if (id < IPI_MAX && handler) { |
---|
285 | 279 | ipi_desc = vpu->ipi_desc; |
---|
286 | 280 | ipi_desc[id].name = name; |
---|
287 | 281 | ipi_desc[id].handler = handler; |
---|
.. | .. |
---|
300 | 294 | unsigned int len) |
---|
301 | 295 | { |
---|
302 | 296 | struct mtk_vpu *vpu = platform_get_drvdata(pdev); |
---|
303 | | - struct share_obj *send_obj = vpu->send_buf; |
---|
| 297 | + struct share_obj __iomem *send_obj = vpu->send_buf; |
---|
304 | 298 | unsigned long timeout; |
---|
305 | 299 | int ret = 0; |
---|
306 | 300 | |
---|
.. | .. |
---|
333 | 327 | } |
---|
334 | 328 | } while (vpu_cfg_readl(vpu, HOST_TO_VPU)); |
---|
335 | 329 | |
---|
336 | | - memcpy((void *)send_obj->share_buf, buf, len); |
---|
337 | | - send_obj->len = len; |
---|
338 | | - send_obj->id = id; |
---|
| 330 | + memcpy_toio(send_obj->share_buf, buf, len); |
---|
| 331 | + writel(len, &send_obj->len); |
---|
| 332 | + writel(id, &send_obj->id); |
---|
339 | 333 | |
---|
340 | 334 | vpu->ipi_id_ack[id] = false; |
---|
341 | 335 | /* send the command to VPU */ |
---|
.. | .. |
---|
406 | 400 | |
---|
407 | 401 | handler = vpu->wdt.handler; |
---|
408 | 402 | |
---|
409 | | - if (id >= 0 && id < VPU_RST_MAX && wdt_reset) { |
---|
| 403 | + if (id < VPU_RST_MAX && wdt_reset) { |
---|
410 | 404 | dev_dbg(vpu->dev, "wdt register id %d\n", id); |
---|
411 | 405 | mutex_lock(&vpu->vpu_mutex); |
---|
412 | 406 | handler[id].reset_func = wdt_reset; |
---|
.. | .. |
---|
468 | 462 | } |
---|
469 | 463 | |
---|
470 | 464 | vpu_pdev = of_find_device_by_node(vpu_node); |
---|
| 465 | + of_node_put(vpu_node); |
---|
471 | 466 | if (WARN_ON(!vpu_pdev)) { |
---|
472 | 467 | dev_err(dev, "vpu pdev failed\n"); |
---|
473 | | - of_node_put(vpu_node); |
---|
474 | 468 | return NULL; |
---|
475 | 469 | } |
---|
476 | 470 | |
---|
.. | .. |
---|
480 | 474 | |
---|
481 | 475 | /* load vpu program/data memory */ |
---|
482 | 476 | static int load_requested_vpu(struct mtk_vpu *vpu, |
---|
483 | | - const struct firmware *vpu_fw, |
---|
484 | 477 | u8 fw_type) |
---|
485 | 478 | { |
---|
486 | 479 | size_t tcm_size = fw_type ? VPU_DTCM_SIZE : VPU_PTCM_SIZE; |
---|
487 | 480 | size_t fw_size = fw_type ? VPU_D_FW_SIZE : VPU_P_FW_SIZE; |
---|
488 | 481 | char *fw_name = fw_type ? VPU_D_FW : VPU_P_FW; |
---|
| 482 | + char *fw_new_name = fw_type ? VPU_D_FW_NEW : VPU_P_FW_NEW; |
---|
| 483 | + const struct firmware *vpu_fw; |
---|
489 | 484 | size_t dl_size = 0; |
---|
490 | 485 | size_t extra_fw_size = 0; |
---|
491 | 486 | void *dest; |
---|
492 | 487 | int ret; |
---|
493 | 488 | |
---|
494 | | - ret = request_firmware(&vpu_fw, fw_name, vpu->dev); |
---|
| 489 | + ret = request_firmware(&vpu_fw, fw_new_name, vpu->dev); |
---|
495 | 490 | if (ret < 0) { |
---|
496 | | - dev_err(vpu->dev, "Failed to load %s, %d\n", fw_name, ret); |
---|
497 | | - return ret; |
---|
| 491 | + dev_info(vpu->dev, "Failed to load %s, %d, retry\n", |
---|
| 492 | + fw_new_name, ret); |
---|
| 493 | + |
---|
| 494 | + ret = request_firmware(&vpu_fw, fw_name, vpu->dev); |
---|
| 495 | + if (ret < 0) { |
---|
| 496 | + dev_err(vpu->dev, "Failed to load %s, %d\n", fw_name, |
---|
| 497 | + ret); |
---|
| 498 | + return ret; |
---|
| 499 | + } |
---|
498 | 500 | } |
---|
499 | 501 | dl_size = vpu_fw->size; |
---|
500 | 502 | if (dl_size > fw_size) { |
---|
.. | .. |
---|
537 | 539 | int vpu_load_firmware(struct platform_device *pdev) |
---|
538 | 540 | { |
---|
539 | 541 | struct mtk_vpu *vpu; |
---|
540 | | - struct device *dev = &pdev->dev; |
---|
| 542 | + struct device *dev; |
---|
541 | 543 | struct vpu_run *run; |
---|
542 | | - const struct firmware *vpu_fw = NULL; |
---|
543 | 544 | int ret; |
---|
544 | 545 | |
---|
545 | 546 | if (!pdev) { |
---|
546 | | - dev_err(dev, "VPU platform device is invalid\n"); |
---|
| 547 | + pr_err("VPU platform device is invalid\n"); |
---|
547 | 548 | return -EINVAL; |
---|
548 | 549 | } |
---|
| 550 | + |
---|
| 551 | + dev = &pdev->dev; |
---|
549 | 552 | |
---|
550 | 553 | vpu = platform_get_drvdata(pdev); |
---|
551 | 554 | run = &vpu->run; |
---|
.. | .. |
---|
568 | 571 | run->signaled = false; |
---|
569 | 572 | dev_dbg(vpu->dev, "firmware request\n"); |
---|
570 | 573 | /* Downloading program firmware to device*/ |
---|
571 | | - ret = load_requested_vpu(vpu, vpu_fw, P_FW); |
---|
| 574 | + ret = load_requested_vpu(vpu, P_FW); |
---|
572 | 575 | if (ret < 0) { |
---|
573 | 576 | dev_err(dev, "Failed to request %s, %d\n", VPU_P_FW, ret); |
---|
574 | 577 | goto OUT_LOAD_FW; |
---|
575 | 578 | } |
---|
576 | 579 | |
---|
577 | 580 | /* Downloading data firmware to device */ |
---|
578 | | - ret = load_requested_vpu(vpu, vpu_fw, D_FW); |
---|
| 581 | + ret = load_requested_vpu(vpu, D_FW); |
---|
579 | 582 | if (ret < 0) { |
---|
580 | 583 | dev_err(dev, "Failed to request %s, %d\n", VPU_D_FW, ret); |
---|
581 | 584 | goto OUT_LOAD_FW; |
---|
.. | .. |
---|
609 | 612 | } |
---|
610 | 613 | EXPORT_SYMBOL_GPL(vpu_load_firmware); |
---|
611 | 614 | |
---|
612 | | -static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv) |
---|
| 615 | +static void vpu_init_ipi_handler(const void *data, unsigned int len, void *priv) |
---|
613 | 616 | { |
---|
614 | | - struct mtk_vpu *vpu = (struct mtk_vpu *)priv; |
---|
615 | | - struct vpu_run *run = (struct vpu_run *)data; |
---|
| 617 | + struct mtk_vpu *vpu = priv; |
---|
| 618 | + const struct vpu_run *run = data; |
---|
616 | 619 | |
---|
617 | 620 | vpu->run.signaled = run->signaled; |
---|
618 | | - strncpy(vpu->run.fw_ver, run->fw_ver, VPU_FW_VER_LEN); |
---|
| 621 | + strscpy(vpu->run.fw_ver, run->fw_ver, sizeof(vpu->run.fw_ver)); |
---|
619 | 622 | vpu->run.dec_capability = run->dec_capability; |
---|
620 | 623 | vpu->run.enc_capability = run->enc_capability; |
---|
621 | 624 | wake_up_interruptible(&vpu->run.wq); |
---|
.. | .. |
---|
709 | 712 | |
---|
710 | 713 | static void vpu_ipi_handler(struct mtk_vpu *vpu) |
---|
711 | 714 | { |
---|
712 | | - struct share_obj *rcv_obj = vpu->recv_buf; |
---|
| 715 | + struct share_obj __iomem *rcv_obj = vpu->recv_buf; |
---|
713 | 716 | struct vpu_ipi_desc *ipi_desc = vpu->ipi_desc; |
---|
| 717 | + unsigned char data[SHARE_BUF_SIZE]; |
---|
| 718 | + s32 id = readl(&rcv_obj->id); |
---|
714 | 719 | |
---|
715 | | - if (rcv_obj->id < IPI_MAX && ipi_desc[rcv_obj->id].handler) { |
---|
716 | | - ipi_desc[rcv_obj->id].handler(rcv_obj->share_buf, |
---|
717 | | - rcv_obj->len, |
---|
718 | | - ipi_desc[rcv_obj->id].priv); |
---|
719 | | - if (rcv_obj->id > IPI_VPU_INIT) { |
---|
720 | | - vpu->ipi_id_ack[rcv_obj->id] = true; |
---|
| 720 | + memcpy_fromio(data, rcv_obj->share_buf, sizeof(data)); |
---|
| 721 | + if (id < IPI_MAX && ipi_desc[id].handler) { |
---|
| 722 | + ipi_desc[id].handler(data, readl(&rcv_obj->len), |
---|
| 723 | + ipi_desc[id].priv); |
---|
| 724 | + if (id > IPI_VPU_INIT) { |
---|
| 725 | + vpu->ipi_id_ack[id] = true; |
---|
721 | 726 | wake_up(&vpu->ack_wq); |
---|
722 | 727 | } |
---|
723 | 728 | } else { |
---|
724 | | - dev_err(vpu->dev, "No such ipi id = %d\n", rcv_obj->id); |
---|
| 729 | + dev_err(vpu->dev, "No such ipi id = %d\n", id); |
---|
725 | 730 | } |
---|
726 | 731 | } |
---|
727 | 732 | |
---|
.. | .. |
---|
731 | 736 | vpu_cfg_writel(vpu, 0x0, VPU_TO_HOST); |
---|
732 | 737 | |
---|
733 | 738 | /* shared buffer initialization */ |
---|
734 | | - vpu->recv_buf = (__force struct share_obj *)(vpu->reg.tcm + |
---|
735 | | - VPU_DTCM_OFFSET); |
---|
| 739 | + vpu->recv_buf = vpu->reg.tcm + VPU_DTCM_OFFSET; |
---|
736 | 740 | vpu->send_buf = vpu->recv_buf + 1; |
---|
737 | | - memset(vpu->recv_buf, 0, sizeof(struct share_obj)); |
---|
738 | | - memset(vpu->send_buf, 0, sizeof(struct share_obj)); |
---|
| 741 | + memset_io(vpu->recv_buf, 0, sizeof(struct share_obj)); |
---|
| 742 | + memset_io(vpu->send_buf, 0, sizeof(struct share_obj)); |
---|
739 | 743 | |
---|
740 | 744 | return 0; |
---|
741 | 745 | } |
---|
.. | .. |
---|
848 | 852 | #ifdef CONFIG_DEBUG_FS |
---|
849 | 853 | vpu_debugfs = debugfs_create_file("mtk_vpu", S_IRUGO, NULL, (void *)dev, |
---|
850 | 854 | &vpu_debug_fops); |
---|
851 | | - if (!vpu_debugfs) { |
---|
852 | | - ret = -ENOMEM; |
---|
853 | | - goto cleanup_ipi; |
---|
854 | | - } |
---|
855 | 855 | #endif |
---|
856 | 856 | |
---|
857 | 857 | /* Set PTCM to 96K and DTCM to 32K */ |
---|
858 | 858 | vpu_cfg_writel(vpu, 0x2, VPU_TCM_CFG); |
---|
859 | 859 | |
---|
860 | | - vpu->enable_4GB = !!(totalram_pages > (SZ_2G >> PAGE_SHIFT)); |
---|
| 860 | + vpu->enable_4GB = !!(totalram_pages() > (SZ_2G >> PAGE_SHIFT)); |
---|
861 | 861 | dev_info(dev, "4GB mode %u\n", vpu->enable_4GB); |
---|
862 | 862 | |
---|
863 | 863 | if (vpu->enable_4GB) { |
---|
.. | .. |
---|
909 | 909 | of_reserved_mem_device_release(dev); |
---|
910 | 910 | #ifdef CONFIG_DEBUG_FS |
---|
911 | 911 | debugfs_remove(vpu_debugfs); |
---|
912 | | -cleanup_ipi: |
---|
913 | 912 | #endif |
---|
914 | 913 | memset(vpu->ipi_desc, 0, sizeof(struct vpu_ipi_desc) * IPI_MAX); |
---|
915 | 914 | vpu_mutex_destroy: |
---|