18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (c) 2019 MediaTek Inc. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <asm/barrier.h> 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of_address.h> 138c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 148c2ecf20Sopenharmony_ci#include <linux/of_reserved_mem.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/remoteproc.h> 178c2ecf20Sopenharmony_ci#include <linux/remoteproc/mtk_scp.h> 188c2ecf20Sopenharmony_ci#include <linux/rpmsg/mtk_rpmsg.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "mtk_common.h" 218c2ecf20Sopenharmony_ci#include "remoteproc_internal.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define MAX_CODE_SIZE 0x500000 248c2ecf20Sopenharmony_ci#define SCP_FW_END 0x7C000 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * scp_get() - get a reference to SCP. 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * @pdev: the platform device of the module requesting SCP platform 308c2ecf20Sopenharmony_ci * device for using SCP API. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Return: Return NULL if failed. otherwise reference to SCP. 338c2ecf20Sopenharmony_ci **/ 348c2ecf20Sopenharmony_cistruct mtk_scp *scp_get(struct platform_device *pdev) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 378c2ecf20Sopenharmony_ci struct device_node *scp_node; 388c2ecf20Sopenharmony_ci struct platform_device *scp_pdev; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci scp_node = of_parse_phandle(dev->of_node, "mediatek,scp", 0); 418c2ecf20Sopenharmony_ci if (!scp_node) { 428c2ecf20Sopenharmony_ci dev_err(dev, "can't get SCP node\n"); 438c2ecf20Sopenharmony_ci return NULL; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci scp_pdev = of_find_device_by_node(scp_node); 478c2ecf20Sopenharmony_ci of_node_put(scp_node); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (WARN_ON(!scp_pdev)) { 508c2ecf20Sopenharmony_ci dev_err(dev, "SCP pdev failed\n"); 518c2ecf20Sopenharmony_ci return NULL; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return platform_get_drvdata(scp_pdev); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scp_get); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * scp_put() - "free" the SCP 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * @scp: mtk_scp structure from scp_get(). 628c2ecf20Sopenharmony_ci **/ 638c2ecf20Sopenharmony_civoid scp_put(struct mtk_scp *scp) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci put_device(scp->dev); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scp_put); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void scp_wdt_handler(struct mtk_scp *scp, u32 scp_to_host) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci dev_err(scp->dev, "SCP watchdog timeout! 0x%x", scp_to_host); 728c2ecf20Sopenharmony_ci rproc_report_crash(scp->rproc, RPROC_WATCHDOG); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void scp_init_ipi_handler(void *data, unsigned int len, void *priv) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct mtk_scp *scp = (struct mtk_scp *)priv; 788c2ecf20Sopenharmony_ci struct scp_run *run = (struct scp_run *)data; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci scp->run.signaled = run->signaled; 818c2ecf20Sopenharmony_ci strscpy(scp->run.fw_ver, run->fw_ver, SCP_FW_VER_LEN); 828c2ecf20Sopenharmony_ci scp->run.dec_capability = run->dec_capability; 838c2ecf20Sopenharmony_ci scp->run.enc_capability = run->enc_capability; 848c2ecf20Sopenharmony_ci wake_up_interruptible(&scp->run.wq); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void scp_ipi_handler(struct mtk_scp *scp) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct mtk_share_obj __iomem *rcv_obj = scp->recv_buf; 908c2ecf20Sopenharmony_ci struct scp_ipi_desc *ipi_desc = scp->ipi_desc; 918c2ecf20Sopenharmony_ci u8 tmp_data[SCP_SHARE_BUFFER_SIZE]; 928c2ecf20Sopenharmony_ci scp_ipi_handler_t handler; 938c2ecf20Sopenharmony_ci u32 id = readl(&rcv_obj->id); 948c2ecf20Sopenharmony_ci u32 len = readl(&rcv_obj->len); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (len > SCP_SHARE_BUFFER_SIZE) { 978c2ecf20Sopenharmony_ci dev_err(scp->dev, "ipi message too long (len %d, max %d)", len, 988c2ecf20Sopenharmony_ci SCP_SHARE_BUFFER_SIZE); 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci if (id >= SCP_IPI_MAX) { 1028c2ecf20Sopenharmony_ci dev_err(scp->dev, "No such ipi id = %d\n", id); 1038c2ecf20Sopenharmony_ci return; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci scp_ipi_lock(scp, id); 1078c2ecf20Sopenharmony_ci handler = ipi_desc[id].handler; 1088c2ecf20Sopenharmony_ci if (!handler) { 1098c2ecf20Sopenharmony_ci dev_err(scp->dev, "No such ipi id = %d\n", id); 1108c2ecf20Sopenharmony_ci scp_ipi_unlock(scp, id); 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci memcpy_fromio(tmp_data, &rcv_obj->share_buf, len); 1158c2ecf20Sopenharmony_ci handler(tmp_data, len, ipi_desc[id].priv); 1168c2ecf20Sopenharmony_ci scp_ipi_unlock(scp, id); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci scp->ipi_id_ack[id] = true; 1198c2ecf20Sopenharmony_ci wake_up(&scp->ack_wq); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int scp_ipi_init(struct mtk_scp *scp) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci size_t send_offset = SCP_FW_END - sizeof(struct mtk_share_obj); 1258c2ecf20Sopenharmony_ci size_t recv_offset = send_offset - sizeof(struct mtk_share_obj); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* shared buffer initialization */ 1288c2ecf20Sopenharmony_ci scp->recv_buf = 1298c2ecf20Sopenharmony_ci (struct mtk_share_obj __iomem *)(scp->sram_base + recv_offset); 1308c2ecf20Sopenharmony_ci scp->send_buf = 1318c2ecf20Sopenharmony_ci (struct mtk_share_obj __iomem *)(scp->sram_base + send_offset); 1328c2ecf20Sopenharmony_ci memset_io(scp->recv_buf, 0, sizeof(*scp->recv_buf)); 1338c2ecf20Sopenharmony_ci memset_io(scp->send_buf, 0, sizeof(*scp->send_buf)); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void mt8183_scp_reset_assert(struct mtk_scp *scp) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci u32 val; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci val = readl(scp->reg_base + MT8183_SW_RSTN); 1438c2ecf20Sopenharmony_ci val &= ~MT8183_SW_RSTN_BIT; 1448c2ecf20Sopenharmony_ci writel(val, scp->reg_base + MT8183_SW_RSTN); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void mt8183_scp_reset_deassert(struct mtk_scp *scp) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci u32 val; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci val = readl(scp->reg_base + MT8183_SW_RSTN); 1528c2ecf20Sopenharmony_ci val |= MT8183_SW_RSTN_BIT; 1538c2ecf20Sopenharmony_ci writel(val, scp->reg_base + MT8183_SW_RSTN); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void mt8192_scp_reset_assert(struct mtk_scp *scp) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void mt8192_scp_reset_deassert(struct mtk_scp *scp) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_CLR); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void mt8183_scp_irq_handler(struct mtk_scp *scp) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci u32 scp_to_host; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci scp_to_host = readl(scp->reg_base + MT8183_SCP_TO_HOST); 1718c2ecf20Sopenharmony_ci if (scp_to_host & MT8183_SCP_IPC_INT_BIT) 1728c2ecf20Sopenharmony_ci scp_ipi_handler(scp); 1738c2ecf20Sopenharmony_ci else 1748c2ecf20Sopenharmony_ci scp_wdt_handler(scp, scp_to_host); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* SCP won't send another interrupt until we set SCP_TO_HOST to 0. */ 1778c2ecf20Sopenharmony_ci writel(MT8183_SCP_IPC_INT_BIT | MT8183_SCP_WDT_INT_BIT, 1788c2ecf20Sopenharmony_ci scp->reg_base + MT8183_SCP_TO_HOST); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void mt8192_scp_irq_handler(struct mtk_scp *scp) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci u32 scp_to_host; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci scp_to_host = readl(scp->reg_base + MT8192_SCP2APMCU_IPC_SET); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (scp_to_host & MT8192_SCP_IPC_INT_BIT) { 1888c2ecf20Sopenharmony_ci scp_ipi_handler(scp); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* 1918c2ecf20Sopenharmony_ci * SCP won't send another interrupt until we clear 1928c2ecf20Sopenharmony_ci * MT8192_SCP2APMCU_IPC. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci writel(MT8192_SCP_IPC_INT_BIT, 1958c2ecf20Sopenharmony_ci scp->reg_base + MT8192_SCP2APMCU_IPC_CLR); 1968c2ecf20Sopenharmony_ci } else { 1978c2ecf20Sopenharmony_ci scp_wdt_handler(scp, scp_to_host); 1988c2ecf20Sopenharmony_ci writel(1, scp->reg_base + MT8192_CORE0_WDT_IRQ); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic irqreturn_t scp_irq_handler(int irq, void *priv) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct mtk_scp *scp = priv; 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = clk_prepare_enable(scp->clk); 2088c2ecf20Sopenharmony_ci if (ret) { 2098c2ecf20Sopenharmony_ci dev_err(scp->dev, "failed to enable clocks\n"); 2108c2ecf20Sopenharmony_ci return IRQ_NONE; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci scp->data->scp_irq_handler(scp); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci clk_disable_unprepare(scp->clk); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int scp_elf_load_segments(struct rproc *rproc, const struct firmware *fw) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct device *dev = &rproc->dev; 2238c2ecf20Sopenharmony_ci struct elf32_hdr *ehdr; 2248c2ecf20Sopenharmony_ci struct elf32_phdr *phdr; 2258c2ecf20Sopenharmony_ci int i, ret = 0; 2268c2ecf20Sopenharmony_ci const u8 *elf_data = fw->data; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ehdr = (struct elf32_hdr *)elf_data; 2298c2ecf20Sopenharmony_ci phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* go through the available ELF segments */ 2328c2ecf20Sopenharmony_ci for (i = 0; i < ehdr->e_phnum; i++, phdr++) { 2338c2ecf20Sopenharmony_ci u32 da = phdr->p_paddr; 2348c2ecf20Sopenharmony_ci u32 memsz = phdr->p_memsz; 2358c2ecf20Sopenharmony_ci u32 filesz = phdr->p_filesz; 2368c2ecf20Sopenharmony_ci u32 offset = phdr->p_offset; 2378c2ecf20Sopenharmony_ci void __iomem *ptr; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (phdr->p_type != PT_LOAD) 2408c2ecf20Sopenharmony_ci continue; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", 2438c2ecf20Sopenharmony_ci phdr->p_type, da, memsz, filesz); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (filesz > memsz) { 2468c2ecf20Sopenharmony_ci dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", 2478c2ecf20Sopenharmony_ci filesz, memsz); 2488c2ecf20Sopenharmony_ci ret = -EINVAL; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (offset + filesz > fw->size) { 2538c2ecf20Sopenharmony_ci dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", 2548c2ecf20Sopenharmony_ci offset + filesz, fw->size); 2558c2ecf20Sopenharmony_ci ret = -EINVAL; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* grab the kernel address for this device address */ 2608c2ecf20Sopenharmony_ci ptr = (void __iomem *)rproc_da_to_va(rproc, da, memsz); 2618c2ecf20Sopenharmony_ci if (!ptr) { 2628c2ecf20Sopenharmony_ci dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); 2638c2ecf20Sopenharmony_ci ret = -EINVAL; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* put the segment where the remote processor expects it */ 2688c2ecf20Sopenharmony_ci if (phdr->p_filesz) 2698c2ecf20Sopenharmony_ci scp_memcpy_aligned(ptr, elf_data + phdr->p_offset, 2708c2ecf20Sopenharmony_ci filesz); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int mt8183_scp_before_load(struct mtk_scp *scp) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci /* Clear SCP to host interrupt */ 2798c2ecf20Sopenharmony_ci writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Reset clocks before loading FW */ 2828c2ecf20Sopenharmony_ci writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL); 2838c2ecf20Sopenharmony_ci writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Initialize TCM before loading FW. */ 2868c2ecf20Sopenharmony_ci writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD); 2878c2ecf20Sopenharmony_ci writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Turn on the power of SCP's SRAM before using it. */ 2908c2ecf20Sopenharmony_ci writel(0x0, scp->reg_base + MT8183_SCP_SRAM_PDN); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * Set I-cache and D-cache size before loading SCP FW. 2948c2ecf20Sopenharmony_ci * SCP SRAM logical address may change when cache size setting differs. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB, 2978c2ecf20Sopenharmony_ci scp->reg_base + MT8183_SCP_CACHE_CON); 2988c2ecf20Sopenharmony_ci writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic void mt8192_power_on_sram(void *addr) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci int i; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci for (i = 31; i >= 0; i--) 3088c2ecf20Sopenharmony_ci writel(GENMASK(i, 0), addr); 3098c2ecf20Sopenharmony_ci writel(0, addr); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void mt8192_power_off_sram(void *addr) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci int i; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci writel(0, addr); 3178c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) 3188c2ecf20Sopenharmony_ci writel(GENMASK(i, 0), addr); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int mt8192_scp_before_load(struct mtk_scp *scp) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci /* clear SPM interrupt, SCP2SPM_IPC_CLR */ 3248c2ecf20Sopenharmony_ci writel(0xff, scp->reg_base + MT8192_SCP2SPM_IPC_CLR); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* enable SRAM clock */ 3298c2ecf20Sopenharmony_ci mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_0); 3308c2ecf20Sopenharmony_ci mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_1); 3318c2ecf20Sopenharmony_ci mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_2); 3328c2ecf20Sopenharmony_ci mt8192_power_on_sram(scp->reg_base + MT8192_L1TCM_SRAM_PDN); 3338c2ecf20Sopenharmony_ci mt8192_power_on_sram(scp->reg_base + MT8192_CPU0_SRAM_PD); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int scp_load(struct rproc *rproc, const struct firmware *fw) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct mtk_scp *scp = rproc->priv; 3418c2ecf20Sopenharmony_ci struct device *dev = scp->dev; 3428c2ecf20Sopenharmony_ci int ret; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci ret = clk_prepare_enable(scp->clk); 3458c2ecf20Sopenharmony_ci if (ret) { 3468c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable clocks\n"); 3478c2ecf20Sopenharmony_ci return ret; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Hold SCP in reset while loading FW. */ 3518c2ecf20Sopenharmony_ci scp->data->scp_reset_assert(scp); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci ret = scp->data->scp_before_load(scp); 3548c2ecf20Sopenharmony_ci if (ret < 0) 3558c2ecf20Sopenharmony_ci goto leave; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = scp_elf_load_segments(rproc, fw); 3588c2ecf20Sopenharmony_cileave: 3598c2ecf20Sopenharmony_ci clk_disable_unprepare(scp->clk); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int scp_start(struct rproc *rproc) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 3678c2ecf20Sopenharmony_ci struct device *dev = scp->dev; 3688c2ecf20Sopenharmony_ci struct scp_run *run = &scp->run; 3698c2ecf20Sopenharmony_ci int ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = clk_prepare_enable(scp->clk); 3728c2ecf20Sopenharmony_ci if (ret) { 3738c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable clocks\n"); 3748c2ecf20Sopenharmony_ci return ret; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci run->signaled = false; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci scp->data->scp_reset_deassert(scp); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout( 3828c2ecf20Sopenharmony_ci run->wq, 3838c2ecf20Sopenharmony_ci run->signaled, 3848c2ecf20Sopenharmony_ci msecs_to_jiffies(2000)); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (ret == 0) { 3878c2ecf20Sopenharmony_ci dev_err(dev, "wait SCP initialization timeout!\n"); 3888c2ecf20Sopenharmony_ci ret = -ETIME; 3898c2ecf20Sopenharmony_ci goto stop; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci if (ret == -ERESTARTSYS) { 3928c2ecf20Sopenharmony_ci dev_err(dev, "wait SCP interrupted by a signal!\n"); 3938c2ecf20Sopenharmony_ci goto stop; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci clk_disable_unprepare(scp->clk); 3978c2ecf20Sopenharmony_ci dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistop: 4028c2ecf20Sopenharmony_ci scp->data->scp_reset_assert(scp); 4038c2ecf20Sopenharmony_ci clk_disable_unprepare(scp->clk); 4048c2ecf20Sopenharmony_ci return ret; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 4108c2ecf20Sopenharmony_ci int offset; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (da < scp->sram_size) { 4138c2ecf20Sopenharmony_ci offset = da; 4148c2ecf20Sopenharmony_ci if (offset >= 0 && (offset + len) < scp->sram_size) 4158c2ecf20Sopenharmony_ci return (void __force *)scp->sram_base + offset; 4168c2ecf20Sopenharmony_ci } else if (scp->dram_size) { 4178c2ecf20Sopenharmony_ci offset = da - scp->dma_addr; 4188c2ecf20Sopenharmony_ci if (offset >= 0 && (offset + len) < scp->dram_size) 4198c2ecf20Sopenharmony_ci return (void __force *)scp->cpu_addr + offset; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return NULL; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void mt8183_scp_stop(struct mtk_scp *scp) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci /* Disable SCP watchdog */ 4288c2ecf20Sopenharmony_ci writel(0, scp->reg_base + MT8183_WDT_CFG); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic void mt8192_scp_stop(struct mtk_scp *scp) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci /* Disable SRAM clock */ 4348c2ecf20Sopenharmony_ci mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_0); 4358c2ecf20Sopenharmony_ci mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_1); 4368c2ecf20Sopenharmony_ci mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_2); 4378c2ecf20Sopenharmony_ci mt8192_power_off_sram(scp->reg_base + MT8192_L1TCM_SRAM_PDN); 4388c2ecf20Sopenharmony_ci mt8192_power_off_sram(scp->reg_base + MT8192_CPU0_SRAM_PD); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Disable SCP watchdog */ 4418c2ecf20Sopenharmony_ci writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int scp_stop(struct rproc *rproc) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 4478c2ecf20Sopenharmony_ci int ret; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ret = clk_prepare_enable(scp->clk); 4508c2ecf20Sopenharmony_ci if (ret) { 4518c2ecf20Sopenharmony_ci dev_err(scp->dev, "failed to enable clocks\n"); 4528c2ecf20Sopenharmony_ci return ret; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci scp->data->scp_reset_assert(scp); 4568c2ecf20Sopenharmony_ci scp->data->scp_stop(scp); 4578c2ecf20Sopenharmony_ci clk_disable_unprepare(scp->clk); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic const struct rproc_ops scp_ops = { 4638c2ecf20Sopenharmony_ci .start = scp_start, 4648c2ecf20Sopenharmony_ci .stop = scp_stop, 4658c2ecf20Sopenharmony_ci .load = scp_load, 4668c2ecf20Sopenharmony_ci .da_to_va = scp_da_to_va, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci/** 4708c2ecf20Sopenharmony_ci * scp_get_device() - get device struct of SCP 4718c2ecf20Sopenharmony_ci * 4728c2ecf20Sopenharmony_ci * @scp: mtk_scp structure 4738c2ecf20Sopenharmony_ci **/ 4748c2ecf20Sopenharmony_cistruct device *scp_get_device(struct mtk_scp *scp) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci return scp->dev; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scp_get_device); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci/** 4818c2ecf20Sopenharmony_ci * scp_get_rproc() - get rproc struct of SCP 4828c2ecf20Sopenharmony_ci * 4838c2ecf20Sopenharmony_ci * @scp: mtk_scp structure 4848c2ecf20Sopenharmony_ci **/ 4858c2ecf20Sopenharmony_cistruct rproc *scp_get_rproc(struct mtk_scp *scp) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci return scp->rproc; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scp_get_rproc); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci/** 4928c2ecf20Sopenharmony_ci * scp_get_vdec_hw_capa() - get video decoder hardware capability 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * @scp: mtk_scp structure 4958c2ecf20Sopenharmony_ci * 4968c2ecf20Sopenharmony_ci * Return: video decoder hardware capability 4978c2ecf20Sopenharmony_ci **/ 4988c2ecf20Sopenharmony_ciunsigned int scp_get_vdec_hw_capa(struct mtk_scp *scp) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci return scp->run.dec_capability; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scp_get_vdec_hw_capa); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * scp_get_venc_hw_capa() - get video encoder hardware capability 5068c2ecf20Sopenharmony_ci * 5078c2ecf20Sopenharmony_ci * @scp: mtk_scp structure 5088c2ecf20Sopenharmony_ci * 5098c2ecf20Sopenharmony_ci * Return: video encoder hardware capability 5108c2ecf20Sopenharmony_ci **/ 5118c2ecf20Sopenharmony_ciunsigned int scp_get_venc_hw_capa(struct mtk_scp *scp) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci return scp->run.enc_capability; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scp_get_venc_hw_capa); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/** 5188c2ecf20Sopenharmony_ci * scp_mapping_dm_addr() - Mapping SRAM/DRAM to kernel virtual address 5198c2ecf20Sopenharmony_ci * 5208c2ecf20Sopenharmony_ci * @scp: mtk_scp structure 5218c2ecf20Sopenharmony_ci * @mem_addr: SCP views memory address 5228c2ecf20Sopenharmony_ci * 5238c2ecf20Sopenharmony_ci * Mapping the SCP's SRAM address / 5248c2ecf20Sopenharmony_ci * DMEM (Data Extended Memory) memory address / 5258c2ecf20Sopenharmony_ci * Working buffer memory address to 5268c2ecf20Sopenharmony_ci * kernel virtual address. 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * Return: Return ERR_PTR(-EINVAL) if mapping failed, 5298c2ecf20Sopenharmony_ci * otherwise the mapped kernel virtual address 5308c2ecf20Sopenharmony_ci **/ 5318c2ecf20Sopenharmony_civoid *scp_mapping_dm_addr(struct mtk_scp *scp, u32 mem_addr) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci void *ptr; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ptr = scp_da_to_va(scp->rproc, mem_addr, 0); 5368c2ecf20Sopenharmony_ci if (!ptr) 5378c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return ptr; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scp_mapping_dm_addr); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int scp_map_memory_region(struct mtk_scp *scp) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci int ret; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ret = of_reserved_mem_device_init(scp->dev); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* reserved memory is optional. */ 5508c2ecf20Sopenharmony_ci if (ret == -ENODEV) { 5518c2ecf20Sopenharmony_ci dev_info(scp->dev, "skipping reserved memory initialization."); 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (ret) { 5568c2ecf20Sopenharmony_ci dev_err(scp->dev, "failed to assign memory-region: %d\n", ret); 5578c2ecf20Sopenharmony_ci return -ENOMEM; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Reserved SCP code size */ 5618c2ecf20Sopenharmony_ci scp->dram_size = MAX_CODE_SIZE; 5628c2ecf20Sopenharmony_ci scp->cpu_addr = dma_alloc_coherent(scp->dev, scp->dram_size, 5638c2ecf20Sopenharmony_ci &scp->dma_addr, GFP_KERNEL); 5648c2ecf20Sopenharmony_ci if (!scp->cpu_addr) 5658c2ecf20Sopenharmony_ci return -ENOMEM; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void scp_unmap_memory_region(struct mtk_scp *scp) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci if (scp->dram_size == 0) 5738c2ecf20Sopenharmony_ci return; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci dma_free_coherent(scp->dev, scp->dram_size, scp->cpu_addr, 5768c2ecf20Sopenharmony_ci scp->dma_addr); 5778c2ecf20Sopenharmony_ci of_reserved_mem_device_release(scp->dev); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int scp_register_ipi(struct platform_device *pdev, u32 id, 5818c2ecf20Sopenharmony_ci ipi_handler_t handler, void *priv) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct mtk_scp *scp = platform_get_drvdata(pdev); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return scp_ipi_register(scp, id, handler, priv); 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic void scp_unregister_ipi(struct platform_device *pdev, u32 id) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct mtk_scp *scp = platform_get_drvdata(pdev); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci scp_ipi_unregister(scp, id); 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int scp_send_ipi(struct platform_device *pdev, u32 id, void *buf, 5968c2ecf20Sopenharmony_ci unsigned int len, unsigned int wait) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci struct mtk_scp *scp = platform_get_drvdata(pdev); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return scp_ipi_send(scp, id, buf, len, wait); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic struct mtk_rpmsg_info mtk_scp_rpmsg_info = { 6048c2ecf20Sopenharmony_ci .send_ipi = scp_send_ipi, 6058c2ecf20Sopenharmony_ci .register_ipi = scp_register_ipi, 6068c2ecf20Sopenharmony_ci .unregister_ipi = scp_unregister_ipi, 6078c2ecf20Sopenharmony_ci .ns_ipi_id = SCP_IPI_NS_SERVICE, 6088c2ecf20Sopenharmony_ci}; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic void scp_add_rpmsg_subdev(struct mtk_scp *scp) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci scp->rpmsg_subdev = 6138c2ecf20Sopenharmony_ci mtk_rpmsg_create_rproc_subdev(to_platform_device(scp->dev), 6148c2ecf20Sopenharmony_ci &mtk_scp_rpmsg_info); 6158c2ecf20Sopenharmony_ci if (scp->rpmsg_subdev) 6168c2ecf20Sopenharmony_ci rproc_add_subdev(scp->rproc, scp->rpmsg_subdev); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic void scp_remove_rpmsg_subdev(struct mtk_scp *scp) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci if (scp->rpmsg_subdev) { 6228c2ecf20Sopenharmony_ci rproc_remove_subdev(scp->rproc, scp->rpmsg_subdev); 6238c2ecf20Sopenharmony_ci mtk_rpmsg_destroy_rproc_subdev(scp->rpmsg_subdev); 6248c2ecf20Sopenharmony_ci scp->rpmsg_subdev = NULL; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic int scp_probe(struct platform_device *pdev) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6318c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 6328c2ecf20Sopenharmony_ci struct mtk_scp *scp; 6338c2ecf20Sopenharmony_ci struct rproc *rproc; 6348c2ecf20Sopenharmony_ci struct resource *res; 6358c2ecf20Sopenharmony_ci char *fw_name = "scp.img"; 6368c2ecf20Sopenharmony_ci int ret, i; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci rproc = rproc_alloc(dev, 6398c2ecf20Sopenharmony_ci np->name, 6408c2ecf20Sopenharmony_ci &scp_ops, 6418c2ecf20Sopenharmony_ci fw_name, 6428c2ecf20Sopenharmony_ci sizeof(*scp)); 6438c2ecf20Sopenharmony_ci if (!rproc) { 6448c2ecf20Sopenharmony_ci dev_err(dev, "unable to allocate remoteproc\n"); 6458c2ecf20Sopenharmony_ci return -ENOMEM; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci scp = (struct mtk_scp *)rproc->priv; 6498c2ecf20Sopenharmony_ci scp->rproc = rproc; 6508c2ecf20Sopenharmony_ci scp->dev = dev; 6518c2ecf20Sopenharmony_ci scp->data = of_device_get_match_data(dev); 6528c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, scp); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); 6558c2ecf20Sopenharmony_ci scp->sram_base = devm_ioremap_resource(dev, res); 6568c2ecf20Sopenharmony_ci if (IS_ERR((__force void *)scp->sram_base)) { 6578c2ecf20Sopenharmony_ci dev_err(dev, "Failed to parse and map sram memory\n"); 6588c2ecf20Sopenharmony_ci ret = PTR_ERR((__force void *)scp->sram_base); 6598c2ecf20Sopenharmony_ci goto free_rproc; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci scp->sram_size = resource_size(res); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci mutex_init(&scp->send_lock); 6648c2ecf20Sopenharmony_ci for (i = 0; i < SCP_IPI_MAX; i++) 6658c2ecf20Sopenharmony_ci mutex_init(&scp->ipi_desc[i].lock); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); 6688c2ecf20Sopenharmony_ci scp->reg_base = devm_ioremap_resource(dev, res); 6698c2ecf20Sopenharmony_ci if (IS_ERR((__force void *)scp->reg_base)) { 6708c2ecf20Sopenharmony_ci dev_err(dev, "Failed to parse and map cfg memory\n"); 6718c2ecf20Sopenharmony_ci ret = PTR_ERR((__force void *)scp->reg_base); 6728c2ecf20Sopenharmony_ci goto destroy_mutex; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci ret = scp_map_memory_region(scp); 6768c2ecf20Sopenharmony_ci if (ret) 6778c2ecf20Sopenharmony_ci goto destroy_mutex; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci scp->clk = devm_clk_get(dev, "main"); 6808c2ecf20Sopenharmony_ci if (IS_ERR(scp->clk)) { 6818c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get clock\n"); 6828c2ecf20Sopenharmony_ci ret = PTR_ERR(scp->clk); 6838c2ecf20Sopenharmony_ci goto release_dev_mem; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci ret = clk_prepare_enable(scp->clk); 6878c2ecf20Sopenharmony_ci if (ret) { 6888c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable clocks\n"); 6898c2ecf20Sopenharmony_ci goto release_dev_mem; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ret = scp_ipi_init(scp); 6938c2ecf20Sopenharmony_ci clk_disable_unprepare(scp->clk); 6948c2ecf20Sopenharmony_ci if (ret) { 6958c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init ipi\n"); 6968c2ecf20Sopenharmony_ci goto release_dev_mem; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* register SCP initialization IPI */ 7008c2ecf20Sopenharmony_ci ret = scp_ipi_register(scp, SCP_IPI_INIT, scp_init_ipi_handler, scp); 7018c2ecf20Sopenharmony_ci if (ret) { 7028c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register IPI_SCP_INIT\n"); 7038c2ecf20Sopenharmony_ci goto release_dev_mem; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci init_waitqueue_head(&scp->run.wq); 7078c2ecf20Sopenharmony_ci init_waitqueue_head(&scp->ack_wq); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci scp_add_rpmsg_subdev(scp); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), NULL, 7128c2ecf20Sopenharmony_ci scp_irq_handler, IRQF_ONESHOT, 7138c2ecf20Sopenharmony_ci pdev->name, scp); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (ret) { 7168c2ecf20Sopenharmony_ci dev_err(dev, "failed to request irq\n"); 7178c2ecf20Sopenharmony_ci goto remove_subdev; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci ret = rproc_add(rproc); 7218c2ecf20Sopenharmony_ci if (ret) 7228c2ecf20Sopenharmony_ci goto remove_subdev; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return 0; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ciremove_subdev: 7278c2ecf20Sopenharmony_ci scp_remove_rpmsg_subdev(scp); 7288c2ecf20Sopenharmony_ci scp_ipi_unregister(scp, SCP_IPI_INIT); 7298c2ecf20Sopenharmony_cirelease_dev_mem: 7308c2ecf20Sopenharmony_ci scp_unmap_memory_region(scp); 7318c2ecf20Sopenharmony_cidestroy_mutex: 7328c2ecf20Sopenharmony_ci for (i = 0; i < SCP_IPI_MAX; i++) 7338c2ecf20Sopenharmony_ci mutex_destroy(&scp->ipi_desc[i].lock); 7348c2ecf20Sopenharmony_ci mutex_destroy(&scp->send_lock); 7358c2ecf20Sopenharmony_cifree_rproc: 7368c2ecf20Sopenharmony_ci rproc_free(rproc); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return ret; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic int scp_remove(struct platform_device *pdev) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct mtk_scp *scp = platform_get_drvdata(pdev); 7448c2ecf20Sopenharmony_ci int i; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci rproc_del(scp->rproc); 7478c2ecf20Sopenharmony_ci scp_remove_rpmsg_subdev(scp); 7488c2ecf20Sopenharmony_ci scp_ipi_unregister(scp, SCP_IPI_INIT); 7498c2ecf20Sopenharmony_ci scp_unmap_memory_region(scp); 7508c2ecf20Sopenharmony_ci for (i = 0; i < SCP_IPI_MAX; i++) 7518c2ecf20Sopenharmony_ci mutex_destroy(&scp->ipi_desc[i].lock); 7528c2ecf20Sopenharmony_ci mutex_destroy(&scp->send_lock); 7538c2ecf20Sopenharmony_ci rproc_free(scp->rproc); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic const struct mtk_scp_of_data mt8183_of_data = { 7598c2ecf20Sopenharmony_ci .scp_before_load = mt8183_scp_before_load, 7608c2ecf20Sopenharmony_ci .scp_irq_handler = mt8183_scp_irq_handler, 7618c2ecf20Sopenharmony_ci .scp_reset_assert = mt8183_scp_reset_assert, 7628c2ecf20Sopenharmony_ci .scp_reset_deassert = mt8183_scp_reset_deassert, 7638c2ecf20Sopenharmony_ci .scp_stop = mt8183_scp_stop, 7648c2ecf20Sopenharmony_ci .host_to_scp_reg = MT8183_HOST_TO_SCP, 7658c2ecf20Sopenharmony_ci .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT, 7668c2ecf20Sopenharmony_ci}; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic const struct mtk_scp_of_data mt8192_of_data = { 7698c2ecf20Sopenharmony_ci .scp_before_load = mt8192_scp_before_load, 7708c2ecf20Sopenharmony_ci .scp_irq_handler = mt8192_scp_irq_handler, 7718c2ecf20Sopenharmony_ci .scp_reset_assert = mt8192_scp_reset_assert, 7728c2ecf20Sopenharmony_ci .scp_reset_deassert = mt8192_scp_reset_deassert, 7738c2ecf20Sopenharmony_ci .scp_stop = mt8192_scp_stop, 7748c2ecf20Sopenharmony_ci .host_to_scp_reg = MT8192_GIPC_IN_SET, 7758c2ecf20Sopenharmony_ci .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, 7768c2ecf20Sopenharmony_ci}; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic const struct of_device_id mtk_scp_of_match[] = { 7798c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, 7808c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, 7818c2ecf20Sopenharmony_ci {}, 7828c2ecf20Sopenharmony_ci}; 7838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mtk_scp_of_match); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic struct platform_driver mtk_scp_driver = { 7868c2ecf20Sopenharmony_ci .probe = scp_probe, 7878c2ecf20Sopenharmony_ci .remove = scp_remove, 7888c2ecf20Sopenharmony_ci .driver = { 7898c2ecf20Sopenharmony_ci .name = "mtk-scp", 7908c2ecf20Sopenharmony_ci .of_match_table = mtk_scp_of_match, 7918c2ecf20Sopenharmony_ci }, 7928c2ecf20Sopenharmony_ci}; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cimodule_platform_driver(mtk_scp_driver); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 7978c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MediaTek SCP control driver"); 798