163c13d61SErin Lo // SPDX-License-Identifier: GPL-2.0 263c13d61SErin Lo // 363c13d61SErin Lo // Copyright (c) 2019 MediaTek Inc. 463c13d61SErin Lo 563c13d61SErin Lo #include <asm/barrier.h> 663c13d61SErin Lo #include <linux/clk.h> 763c13d61SErin Lo #include <linux/dma-mapping.h> 863c13d61SErin Lo #include <linux/err.h> 963c13d61SErin Lo #include <linux/interrupt.h> 1063c13d61SErin Lo #include <linux/kernel.h> 1163c13d61SErin Lo #include <linux/module.h> 1263c13d61SErin Lo #include <linux/of_address.h> 1363c13d61SErin Lo #include <linux/of_platform.h> 1463c13d61SErin Lo #include <linux/of_reserved_mem.h> 1563c13d61SErin Lo #include <linux/platform_device.h> 1663c13d61SErin Lo #include <linux/remoteproc.h> 1763c13d61SErin Lo #include <linux/remoteproc/mtk_scp.h> 1870179969SPi-Hsun Shih #include <linux/rpmsg/mtk_rpmsg.h> 1963c13d61SErin Lo 2063c13d61SErin Lo #include "mtk_common.h" 2163c13d61SErin Lo #include "remoteproc_internal.h" 2263c13d61SErin Lo 2363c13d61SErin Lo #define MAX_CODE_SIZE 0x500000 2463c13d61SErin Lo #define SCP_FW_END 0x7C000 2563c13d61SErin Lo 2663c13d61SErin Lo /** 2763c13d61SErin Lo * scp_get() - get a reference to SCP. 2863c13d61SErin Lo * 2963c13d61SErin Lo * @pdev: the platform device of the module requesting SCP platform 3063c13d61SErin Lo * device for using SCP API. 3163c13d61SErin Lo * 3263c13d61SErin Lo * Return: Return NULL if failed. otherwise reference to SCP. 3363c13d61SErin Lo **/ 3463c13d61SErin Lo struct mtk_scp *scp_get(struct platform_device *pdev) 3563c13d61SErin Lo { 3663c13d61SErin Lo struct device *dev = &pdev->dev; 3763c13d61SErin Lo struct device_node *scp_node; 3863c13d61SErin Lo struct platform_device *scp_pdev; 3963c13d61SErin Lo 4063c13d61SErin Lo scp_node = of_parse_phandle(dev->of_node, "mediatek,scp", 0); 4163c13d61SErin Lo if (!scp_node) { 4263c13d61SErin Lo dev_err(dev, "can't get SCP node\n"); 4363c13d61SErin Lo return NULL; 4463c13d61SErin Lo } 4563c13d61SErin Lo 4663c13d61SErin Lo scp_pdev = of_find_device_by_node(scp_node); 4763c13d61SErin Lo of_node_put(scp_node); 4863c13d61SErin Lo 4963c13d61SErin Lo if (WARN_ON(!scp_pdev)) { 5063c13d61SErin Lo dev_err(dev, "SCP pdev failed\n"); 5163c13d61SErin Lo return NULL; 5263c13d61SErin Lo } 5363c13d61SErin Lo 5463c13d61SErin Lo return platform_get_drvdata(scp_pdev); 5563c13d61SErin Lo } 5663c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get); 5763c13d61SErin Lo 5863c13d61SErin Lo /** 5963c13d61SErin Lo * scp_put() - "free" the SCP 6063c13d61SErin Lo * 6163c13d61SErin Lo * @scp: mtk_scp structure from scp_get(). 6263c13d61SErin Lo **/ 6363c13d61SErin Lo void scp_put(struct mtk_scp *scp) 6463c13d61SErin Lo { 6563c13d61SErin Lo put_device(scp->dev); 6663c13d61SErin Lo } 6763c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_put); 6863c13d61SErin Lo 6963c13d61SErin Lo static void scp_wdt_handler(struct mtk_scp *scp, u32 scp_to_host) 7063c13d61SErin Lo { 7163c13d61SErin Lo dev_err(scp->dev, "SCP watchdog timeout! 0x%x", scp_to_host); 7263c13d61SErin Lo rproc_report_crash(scp->rproc, RPROC_WATCHDOG); 7363c13d61SErin Lo } 7463c13d61SErin Lo 7563c13d61SErin Lo static void scp_init_ipi_handler(void *data, unsigned int len, void *priv) 7663c13d61SErin Lo { 7763c13d61SErin Lo struct mtk_scp *scp = (struct mtk_scp *)priv; 7863c13d61SErin Lo struct scp_run *run = (struct scp_run *)data; 7963c13d61SErin Lo 8063c13d61SErin Lo scp->run.signaled = run->signaled; 8163c13d61SErin Lo strscpy(scp->run.fw_ver, run->fw_ver, SCP_FW_VER_LEN); 8263c13d61SErin Lo scp->run.dec_capability = run->dec_capability; 8363c13d61SErin Lo scp->run.enc_capability = run->enc_capability; 8463c13d61SErin Lo wake_up_interruptible(&scp->run.wq); 8563c13d61SErin Lo } 8663c13d61SErin Lo 8763c13d61SErin Lo static void scp_ipi_handler(struct mtk_scp *scp) 8863c13d61SErin Lo { 8963c13d61SErin Lo struct mtk_share_obj __iomem *rcv_obj = scp->recv_buf; 9063c13d61SErin Lo struct scp_ipi_desc *ipi_desc = scp->ipi_desc; 9163c13d61SErin Lo u8 tmp_data[SCP_SHARE_BUFFER_SIZE]; 9263c13d61SErin Lo scp_ipi_handler_t handler; 9363c13d61SErin Lo u32 id = readl(&rcv_obj->id); 9463c13d61SErin Lo u32 len = readl(&rcv_obj->len); 9563c13d61SErin Lo 9663c13d61SErin Lo if (len > SCP_SHARE_BUFFER_SIZE) { 9763c13d61SErin Lo dev_err(scp->dev, "ipi message too long (len %d, max %d)", len, 9863c13d61SErin Lo SCP_SHARE_BUFFER_SIZE); 9963c13d61SErin Lo return; 10063c13d61SErin Lo } 10163c13d61SErin Lo if (id >= SCP_IPI_MAX) { 10263c13d61SErin Lo dev_err(scp->dev, "No such ipi id = %d\n", id); 10363c13d61SErin Lo return; 10463c13d61SErin Lo } 10563c13d61SErin Lo 10663c13d61SErin Lo scp_ipi_lock(scp, id); 10763c13d61SErin Lo handler = ipi_desc[id].handler; 10863c13d61SErin Lo if (!handler) { 10963c13d61SErin Lo dev_err(scp->dev, "No such ipi id = %d\n", id); 11063c13d61SErin Lo scp_ipi_unlock(scp, id); 11163c13d61SErin Lo return; 11263c13d61SErin Lo } 11363c13d61SErin Lo 11463c13d61SErin Lo memcpy_fromio(tmp_data, &rcv_obj->share_buf, len); 11563c13d61SErin Lo handler(tmp_data, len, ipi_desc[id].priv); 11663c13d61SErin Lo scp_ipi_unlock(scp, id); 11763c13d61SErin Lo 11863c13d61SErin Lo scp->ipi_id_ack[id] = true; 11963c13d61SErin Lo wake_up(&scp->ack_wq); 12063c13d61SErin Lo } 12163c13d61SErin Lo 12263c13d61SErin Lo static int scp_ipi_init(struct mtk_scp *scp) 12363c13d61SErin Lo { 12463c13d61SErin Lo size_t send_offset = SCP_FW_END - sizeof(struct mtk_share_obj); 12563c13d61SErin Lo size_t recv_offset = send_offset - sizeof(struct mtk_share_obj); 12663c13d61SErin Lo 12763c13d61SErin Lo /* shared buffer initialization */ 12863c13d61SErin Lo scp->recv_buf = 12963c13d61SErin Lo (struct mtk_share_obj __iomem *)(scp->sram_base + recv_offset); 13063c13d61SErin Lo scp->send_buf = 13163c13d61SErin Lo (struct mtk_share_obj __iomem *)(scp->sram_base + send_offset); 1328096f80aSWei Yongjun memset_io(scp->recv_buf, 0, sizeof(*scp->recv_buf)); 1338096f80aSWei Yongjun memset_io(scp->send_buf, 0, sizeof(*scp->send_buf)); 13463c13d61SErin Lo 13563c13d61SErin Lo return 0; 13663c13d61SErin Lo } 13763c13d61SErin Lo 138fd0b6c1fSPi-Hsun Shih static void mt8183_scp_reset_assert(struct mtk_scp *scp) 13963c13d61SErin Lo { 14063c13d61SErin Lo u32 val; 14163c13d61SErin Lo 14263c13d61SErin Lo val = readl(scp->reg_base + MT8183_SW_RSTN); 14363c13d61SErin Lo val &= ~MT8183_SW_RSTN_BIT; 14463c13d61SErin Lo writel(val, scp->reg_base + MT8183_SW_RSTN); 14563c13d61SErin Lo } 14663c13d61SErin Lo 147fd0b6c1fSPi-Hsun Shih static void mt8183_scp_reset_deassert(struct mtk_scp *scp) 14863c13d61SErin Lo { 14963c13d61SErin Lo u32 val; 15063c13d61SErin Lo 15163c13d61SErin Lo val = readl(scp->reg_base + MT8183_SW_RSTN); 15263c13d61SErin Lo val |= MT8183_SW_RSTN_BIT; 15363c13d61SErin Lo writel(val, scp->reg_base + MT8183_SW_RSTN); 15463c13d61SErin Lo } 15563c13d61SErin Lo 156fd0b6c1fSPi-Hsun Shih static void mt8192_scp_reset_assert(struct mtk_scp *scp) 15763c13d61SErin Lo { 158fd0b6c1fSPi-Hsun Shih writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); 15963c13d61SErin Lo } 16063c13d61SErin Lo 161fd0b6c1fSPi-Hsun Shih static void mt8192_scp_reset_deassert(struct mtk_scp *scp) 162fd0b6c1fSPi-Hsun Shih { 163fd0b6c1fSPi-Hsun Shih writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_CLR); 164fd0b6c1fSPi-Hsun Shih } 165fd0b6c1fSPi-Hsun Shih 166fd0b6c1fSPi-Hsun Shih static void mt8183_scp_irq_handler(struct mtk_scp *scp) 167fd0b6c1fSPi-Hsun Shih { 168fd0b6c1fSPi-Hsun Shih u32 scp_to_host; 169fd0b6c1fSPi-Hsun Shih 17063c13d61SErin Lo scp_to_host = readl(scp->reg_base + MT8183_SCP_TO_HOST); 17163c13d61SErin Lo if (scp_to_host & MT8183_SCP_IPC_INT_BIT) 17263c13d61SErin Lo scp_ipi_handler(scp); 17363c13d61SErin Lo else 17463c13d61SErin Lo scp_wdt_handler(scp, scp_to_host); 17563c13d61SErin Lo 17663c13d61SErin Lo /* SCP won't send another interrupt until we set SCP_TO_HOST to 0. */ 17763c13d61SErin Lo writel(MT8183_SCP_IPC_INT_BIT | MT8183_SCP_WDT_INT_BIT, 17863c13d61SErin Lo scp->reg_base + MT8183_SCP_TO_HOST); 179fd0b6c1fSPi-Hsun Shih } 180fd0b6c1fSPi-Hsun Shih 181fd0b6c1fSPi-Hsun Shih static void mt8192_scp_irq_handler(struct mtk_scp *scp) 182fd0b6c1fSPi-Hsun Shih { 183fd0b6c1fSPi-Hsun Shih u32 scp_to_host; 184fd0b6c1fSPi-Hsun Shih 185fd0b6c1fSPi-Hsun Shih scp_to_host = readl(scp->reg_base + MT8192_SCP2APMCU_IPC_SET); 186fd0b6c1fSPi-Hsun Shih 187fd0b6c1fSPi-Hsun Shih if (scp_to_host & MT8192_SCP_IPC_INT_BIT) 188fd0b6c1fSPi-Hsun Shih scp_ipi_handler(scp); 189fd0b6c1fSPi-Hsun Shih else 190fd0b6c1fSPi-Hsun Shih scp_wdt_handler(scp, scp_to_host); 191fd0b6c1fSPi-Hsun Shih 192fd0b6c1fSPi-Hsun Shih /* 193fd0b6c1fSPi-Hsun Shih * SCP won't send another interrupt until we clear 194fd0b6c1fSPi-Hsun Shih * MT8192_SCP2APMCU_IPC. 195fd0b6c1fSPi-Hsun Shih */ 196fd0b6c1fSPi-Hsun Shih writel(MT8192_SCP_IPC_INT_BIT, 197fd0b6c1fSPi-Hsun Shih scp->reg_base + MT8192_SCP2APMCU_IPC_CLR); 198fd0b6c1fSPi-Hsun Shih } 199fd0b6c1fSPi-Hsun Shih 200fd0b6c1fSPi-Hsun Shih static irqreturn_t scp_irq_handler(int irq, void *priv) 201fd0b6c1fSPi-Hsun Shih { 202fd0b6c1fSPi-Hsun Shih struct mtk_scp *scp = priv; 203fd0b6c1fSPi-Hsun Shih int ret; 204fd0b6c1fSPi-Hsun Shih 205fd0b6c1fSPi-Hsun Shih ret = clk_prepare_enable(scp->clk); 206fd0b6c1fSPi-Hsun Shih if (ret) { 207fd0b6c1fSPi-Hsun Shih dev_err(scp->dev, "failed to enable clocks\n"); 208fd0b6c1fSPi-Hsun Shih return IRQ_NONE; 209fd0b6c1fSPi-Hsun Shih } 210fd0b6c1fSPi-Hsun Shih 211fd0b6c1fSPi-Hsun Shih scp->data->scp_irq_handler(scp); 212fd0b6c1fSPi-Hsun Shih 21363c13d61SErin Lo clk_disable_unprepare(scp->clk); 21463c13d61SErin Lo 21563c13d61SErin Lo return IRQ_HANDLED; 21663c13d61SErin Lo } 21763c13d61SErin Lo 21863c13d61SErin Lo static int scp_elf_load_segments(struct rproc *rproc, const struct firmware *fw) 21963c13d61SErin Lo { 22063c13d61SErin Lo struct device *dev = &rproc->dev; 22163c13d61SErin Lo struct elf32_hdr *ehdr; 22263c13d61SErin Lo struct elf32_phdr *phdr; 22363c13d61SErin Lo int i, ret = 0; 22463c13d61SErin Lo const u8 *elf_data = fw->data; 22563c13d61SErin Lo 22663c13d61SErin Lo ehdr = (struct elf32_hdr *)elf_data; 22763c13d61SErin Lo phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); 22863c13d61SErin Lo 22963c13d61SErin Lo /* go through the available ELF segments */ 23063c13d61SErin Lo for (i = 0; i < ehdr->e_phnum; i++, phdr++) { 23163c13d61SErin Lo u32 da = phdr->p_paddr; 23263c13d61SErin Lo u32 memsz = phdr->p_memsz; 23363c13d61SErin Lo u32 filesz = phdr->p_filesz; 23463c13d61SErin Lo u32 offset = phdr->p_offset; 23563c13d61SErin Lo void __iomem *ptr; 23663c13d61SErin Lo 23763c13d61SErin Lo if (phdr->p_type != PT_LOAD) 23863c13d61SErin Lo continue; 23963c13d61SErin Lo 24063c13d61SErin Lo dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", 24163c13d61SErin Lo phdr->p_type, da, memsz, filesz); 24263c13d61SErin Lo 24363c13d61SErin Lo if (filesz > memsz) { 24463c13d61SErin Lo dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", 24563c13d61SErin Lo filesz, memsz); 24663c13d61SErin Lo ret = -EINVAL; 24763c13d61SErin Lo break; 24863c13d61SErin Lo } 24963c13d61SErin Lo 25063c13d61SErin Lo if (offset + filesz > fw->size) { 25163c13d61SErin Lo dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", 25263c13d61SErin Lo offset + filesz, fw->size); 25363c13d61SErin Lo ret = -EINVAL; 25463c13d61SErin Lo break; 25563c13d61SErin Lo } 25663c13d61SErin Lo 25763c13d61SErin Lo /* grab the kernel address for this device address */ 25863c13d61SErin Lo ptr = (void __iomem *)rproc_da_to_va(rproc, da, memsz); 25963c13d61SErin Lo if (!ptr) { 26063c13d61SErin Lo dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); 26163c13d61SErin Lo ret = -EINVAL; 26263c13d61SErin Lo break; 26363c13d61SErin Lo } 26463c13d61SErin Lo 26563c13d61SErin Lo /* put the segment where the remote processor expects it */ 26663c13d61SErin Lo if (phdr->p_filesz) 26763c13d61SErin Lo scp_memcpy_aligned(ptr, elf_data + phdr->p_offset, 26863c13d61SErin Lo filesz); 26963c13d61SErin Lo } 27063c13d61SErin Lo 27163c13d61SErin Lo return ret; 27263c13d61SErin Lo } 27363c13d61SErin Lo 274fd0b6c1fSPi-Hsun Shih static int mt8183_scp_before_load(struct mtk_scp *scp) 27563c13d61SErin Lo { 276fd0b6c1fSPi-Hsun Shih /* Clear SCP to host interrupt */ 277fd0b6c1fSPi-Hsun Shih writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); 27863c13d61SErin Lo 27963c13d61SErin Lo /* Reset clocks before loading FW */ 28063c13d61SErin Lo writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL); 28163c13d61SErin Lo writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL); 28263c13d61SErin Lo 28363c13d61SErin Lo /* Initialize TCM before loading FW. */ 28463c13d61SErin Lo writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD); 28563c13d61SErin Lo writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD); 28663c13d61SErin Lo 28763c13d61SErin Lo /* Turn on the power of SCP's SRAM before using it. */ 28863c13d61SErin Lo writel(0x0, scp->reg_base + MT8183_SCP_SRAM_PDN); 28963c13d61SErin Lo 29063c13d61SErin Lo /* 29163c13d61SErin Lo * Set I-cache and D-cache size before loading SCP FW. 29263c13d61SErin Lo * SCP SRAM logical address may change when cache size setting differs. 29363c13d61SErin Lo */ 29463c13d61SErin Lo writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB, 29563c13d61SErin Lo scp->reg_base + MT8183_SCP_CACHE_CON); 29663c13d61SErin Lo writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON); 29763c13d61SErin Lo 298fd0b6c1fSPi-Hsun Shih return 0; 299fd0b6c1fSPi-Hsun Shih } 300fd0b6c1fSPi-Hsun Shih 301*778f2664STzung-Bi Shih static void mt8192_power_on_sram(void __iomem *addr) 302fd0b6c1fSPi-Hsun Shih { 303fd0b6c1fSPi-Hsun Shih int i; 304fd0b6c1fSPi-Hsun Shih 305fd0b6c1fSPi-Hsun Shih for (i = 31; i >= 0; i--) 306fd0b6c1fSPi-Hsun Shih writel(GENMASK(i, 0), addr); 307fd0b6c1fSPi-Hsun Shih writel(0, addr); 308fd0b6c1fSPi-Hsun Shih } 309fd0b6c1fSPi-Hsun Shih 310*778f2664STzung-Bi Shih static void mt8192_power_off_sram(void __iomem *addr) 311fd0b6c1fSPi-Hsun Shih { 312fd0b6c1fSPi-Hsun Shih int i; 313fd0b6c1fSPi-Hsun Shih 314fd0b6c1fSPi-Hsun Shih writel(0, addr); 315fd0b6c1fSPi-Hsun Shih for (i = 0; i < 32; i++) 316fd0b6c1fSPi-Hsun Shih writel(GENMASK(i, 0), addr); 317fd0b6c1fSPi-Hsun Shih } 318fd0b6c1fSPi-Hsun Shih 319fd0b6c1fSPi-Hsun Shih static int mt8192_scp_before_load(struct mtk_scp *scp) 320fd0b6c1fSPi-Hsun Shih { 321fd0b6c1fSPi-Hsun Shih /* clear SPM interrupt, SCP2SPM_IPC_CLR */ 322fd0b6c1fSPi-Hsun Shih writel(0xff, scp->reg_base + MT8192_SCP2SPM_IPC_CLR); 323fd0b6c1fSPi-Hsun Shih 324fd0b6c1fSPi-Hsun Shih writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); 325fd0b6c1fSPi-Hsun Shih 326fd0b6c1fSPi-Hsun Shih /* enable SRAM clock */ 327fd0b6c1fSPi-Hsun Shih mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_0); 328fd0b6c1fSPi-Hsun Shih mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_1); 329fd0b6c1fSPi-Hsun Shih mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_2); 330fd0b6c1fSPi-Hsun Shih mt8192_power_on_sram(scp->reg_base + MT8192_L1TCM_SRAM_PDN); 331fd0b6c1fSPi-Hsun Shih mt8192_power_on_sram(scp->reg_base + MT8192_CPU0_SRAM_PD); 332fd0b6c1fSPi-Hsun Shih 333fd0b6c1fSPi-Hsun Shih return 0; 334fd0b6c1fSPi-Hsun Shih } 335fd0b6c1fSPi-Hsun Shih 336fd0b6c1fSPi-Hsun Shih static int scp_load(struct rproc *rproc, const struct firmware *fw) 337fd0b6c1fSPi-Hsun Shih { 338fd0b6c1fSPi-Hsun Shih struct mtk_scp *scp = rproc->priv; 339fd0b6c1fSPi-Hsun Shih struct device *dev = scp->dev; 340fd0b6c1fSPi-Hsun Shih int ret; 341fd0b6c1fSPi-Hsun Shih 342fd0b6c1fSPi-Hsun Shih ret = clk_prepare_enable(scp->clk); 343fd0b6c1fSPi-Hsun Shih if (ret) { 344fd0b6c1fSPi-Hsun Shih dev_err(dev, "failed to enable clocks\n"); 345fd0b6c1fSPi-Hsun Shih return ret; 346fd0b6c1fSPi-Hsun Shih } 347fd0b6c1fSPi-Hsun Shih 348fd0b6c1fSPi-Hsun Shih /* Hold SCP in reset while loading FW. */ 349fd0b6c1fSPi-Hsun Shih scp->data->scp_reset_assert(scp); 350fd0b6c1fSPi-Hsun Shih 351fd0b6c1fSPi-Hsun Shih ret = scp->data->scp_before_load(scp); 352fd0b6c1fSPi-Hsun Shih if (ret < 0) 353fd0b6c1fSPi-Hsun Shih return ret; 354fd0b6c1fSPi-Hsun Shih 35563c13d61SErin Lo ret = scp_elf_load_segments(rproc, fw); 35663c13d61SErin Lo clk_disable_unprepare(scp->clk); 35763c13d61SErin Lo 35863c13d61SErin Lo return ret; 35963c13d61SErin Lo } 36063c13d61SErin Lo 36163c13d61SErin Lo static int scp_start(struct rproc *rproc) 36263c13d61SErin Lo { 36363c13d61SErin Lo struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 36463c13d61SErin Lo struct device *dev = scp->dev; 36563c13d61SErin Lo struct scp_run *run = &scp->run; 36663c13d61SErin Lo int ret; 36763c13d61SErin Lo 36863c13d61SErin Lo ret = clk_prepare_enable(scp->clk); 36963c13d61SErin Lo if (ret) { 37063c13d61SErin Lo dev_err(dev, "failed to enable clocks\n"); 37163c13d61SErin Lo return ret; 37263c13d61SErin Lo } 37363c13d61SErin Lo 37463c13d61SErin Lo run->signaled = false; 37563c13d61SErin Lo 376fd0b6c1fSPi-Hsun Shih scp->data->scp_reset_deassert(scp); 37763c13d61SErin Lo 37863c13d61SErin Lo ret = wait_event_interruptible_timeout( 37963c13d61SErin Lo run->wq, 38063c13d61SErin Lo run->signaled, 38163c13d61SErin Lo msecs_to_jiffies(2000)); 38263c13d61SErin Lo 38363c13d61SErin Lo if (ret == 0) { 38463c13d61SErin Lo dev_err(dev, "wait SCP initialization timeout!\n"); 38563c13d61SErin Lo ret = -ETIME; 38663c13d61SErin Lo goto stop; 38763c13d61SErin Lo } 38863c13d61SErin Lo if (ret == -ERESTARTSYS) { 38963c13d61SErin Lo dev_err(dev, "wait SCP interrupted by a signal!\n"); 39063c13d61SErin Lo goto stop; 39163c13d61SErin Lo } 392fd0b6c1fSPi-Hsun Shih 39363c13d61SErin Lo clk_disable_unprepare(scp->clk); 39463c13d61SErin Lo dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver); 39563c13d61SErin Lo 39663c13d61SErin Lo return 0; 39763c13d61SErin Lo 39863c13d61SErin Lo stop: 399fd0b6c1fSPi-Hsun Shih scp->data->scp_reset_assert(scp); 40063c13d61SErin Lo clk_disable_unprepare(scp->clk); 40163c13d61SErin Lo return ret; 40263c13d61SErin Lo } 40363c13d61SErin Lo 404e1833b9eSNathan Chancellor static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len) 40563c13d61SErin Lo { 40663c13d61SErin Lo struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 40763c13d61SErin Lo int offset; 40863c13d61SErin Lo 40963c13d61SErin Lo if (da < scp->sram_size) { 41063c13d61SErin Lo offset = da; 41163c13d61SErin Lo if (offset >= 0 && (offset + len) < scp->sram_size) 41263c13d61SErin Lo return (void __force *)scp->sram_base + offset; 413fd0b6c1fSPi-Hsun Shih } else if (scp->dram_size) { 414c2781e4dSArnd Bergmann offset = da - scp->dma_addr; 41563c13d61SErin Lo if (offset >= 0 && (offset + len) < scp->dram_size) 41663c13d61SErin Lo return (void __force *)scp->cpu_addr + offset; 41763c13d61SErin Lo } 41863c13d61SErin Lo 41963c13d61SErin Lo return NULL; 42063c13d61SErin Lo } 42163c13d61SErin Lo 422fd0b6c1fSPi-Hsun Shih static void mt8183_scp_stop(struct mtk_scp *scp) 423fd0b6c1fSPi-Hsun Shih { 424fd0b6c1fSPi-Hsun Shih /* Disable SCP watchdog */ 425fd0b6c1fSPi-Hsun Shih writel(0, scp->reg_base + MT8183_WDT_CFG); 426fd0b6c1fSPi-Hsun Shih } 427fd0b6c1fSPi-Hsun Shih 428fd0b6c1fSPi-Hsun Shih static void mt8192_scp_stop(struct mtk_scp *scp) 429fd0b6c1fSPi-Hsun Shih { 430fd0b6c1fSPi-Hsun Shih /* Disable SRAM clock */ 431fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_0); 432fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_1); 433fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_2); 434fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L1TCM_SRAM_PDN); 435fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_CPU0_SRAM_PD); 436fd0b6c1fSPi-Hsun Shih 437fd0b6c1fSPi-Hsun Shih /* Disable SCP watchdog */ 438fd0b6c1fSPi-Hsun Shih writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG); 439fd0b6c1fSPi-Hsun Shih } 440fd0b6c1fSPi-Hsun Shih 44163c13d61SErin Lo static int scp_stop(struct rproc *rproc) 44263c13d61SErin Lo { 44363c13d61SErin Lo struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 44463c13d61SErin Lo int ret; 44563c13d61SErin Lo 44663c13d61SErin Lo ret = clk_prepare_enable(scp->clk); 44763c13d61SErin Lo if (ret) { 44863c13d61SErin Lo dev_err(scp->dev, "failed to enable clocks\n"); 44963c13d61SErin Lo return ret; 45063c13d61SErin Lo } 45163c13d61SErin Lo 452fd0b6c1fSPi-Hsun Shih scp->data->scp_reset_assert(scp); 453fd0b6c1fSPi-Hsun Shih scp->data->scp_stop(scp); 45463c13d61SErin Lo clk_disable_unprepare(scp->clk); 45563c13d61SErin Lo 45663c13d61SErin Lo return 0; 45763c13d61SErin Lo } 45863c13d61SErin Lo 45963c13d61SErin Lo static const struct rproc_ops scp_ops = { 46063c13d61SErin Lo .start = scp_start, 46163c13d61SErin Lo .stop = scp_stop, 46263c13d61SErin Lo .load = scp_load, 46363c13d61SErin Lo .da_to_va = scp_da_to_va, 46463c13d61SErin Lo }; 46563c13d61SErin Lo 46663c13d61SErin Lo /** 46763c13d61SErin Lo * scp_get_device() - get device struct of SCP 46863c13d61SErin Lo * 46963c13d61SErin Lo * @scp: mtk_scp structure 47063c13d61SErin Lo **/ 47163c13d61SErin Lo struct device *scp_get_device(struct mtk_scp *scp) 47263c13d61SErin Lo { 47363c13d61SErin Lo return scp->dev; 47463c13d61SErin Lo } 47563c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_device); 47663c13d61SErin Lo 47763c13d61SErin Lo /** 47863c13d61SErin Lo * scp_get_rproc() - get rproc struct of SCP 47963c13d61SErin Lo * 48063c13d61SErin Lo * @scp: mtk_scp structure 48163c13d61SErin Lo **/ 48263c13d61SErin Lo struct rproc *scp_get_rproc(struct mtk_scp *scp) 48363c13d61SErin Lo { 48463c13d61SErin Lo return scp->rproc; 48563c13d61SErin Lo } 48663c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_rproc); 48763c13d61SErin Lo 48863c13d61SErin Lo /** 48963c13d61SErin Lo * scp_get_vdec_hw_capa() - get video decoder hardware capability 49063c13d61SErin Lo * 49163c13d61SErin Lo * @scp: mtk_scp structure 49263c13d61SErin Lo * 49363c13d61SErin Lo * Return: video decoder hardware capability 49463c13d61SErin Lo **/ 49563c13d61SErin Lo unsigned int scp_get_vdec_hw_capa(struct mtk_scp *scp) 49663c13d61SErin Lo { 49763c13d61SErin Lo return scp->run.dec_capability; 49863c13d61SErin Lo } 49963c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_vdec_hw_capa); 50063c13d61SErin Lo 50163c13d61SErin Lo /** 50263c13d61SErin Lo * scp_get_venc_hw_capa() - get video encoder hardware capability 50363c13d61SErin Lo * 50463c13d61SErin Lo * @scp: mtk_scp structure 50563c13d61SErin Lo * 50663c13d61SErin Lo * Return: video encoder hardware capability 50763c13d61SErin Lo **/ 50863c13d61SErin Lo unsigned int scp_get_venc_hw_capa(struct mtk_scp *scp) 50963c13d61SErin Lo { 51063c13d61SErin Lo return scp->run.enc_capability; 51163c13d61SErin Lo } 51263c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_venc_hw_capa); 51363c13d61SErin Lo 51463c13d61SErin Lo /** 51563c13d61SErin Lo * scp_mapping_dm_addr() - Mapping SRAM/DRAM to kernel virtual address 51663c13d61SErin Lo * 51763c13d61SErin Lo * @scp: mtk_scp structure 51863c13d61SErin Lo * @mem_addr: SCP views memory address 51963c13d61SErin Lo * 52063c13d61SErin Lo * Mapping the SCP's SRAM address / 52163c13d61SErin Lo * DMEM (Data Extended Memory) memory address / 52263c13d61SErin Lo * Working buffer memory address to 52363c13d61SErin Lo * kernel virtual address. 52463c13d61SErin Lo * 52563c13d61SErin Lo * Return: Return ERR_PTR(-EINVAL) if mapping failed, 52663c13d61SErin Lo * otherwise the mapped kernel virtual address 52763c13d61SErin Lo **/ 52863c13d61SErin Lo void *scp_mapping_dm_addr(struct mtk_scp *scp, u32 mem_addr) 52963c13d61SErin Lo { 53063c13d61SErin Lo void *ptr; 53163c13d61SErin Lo 53263c13d61SErin Lo ptr = scp_da_to_va(scp->rproc, mem_addr, 0); 53363c13d61SErin Lo if (!ptr) 53463c13d61SErin Lo return ERR_PTR(-EINVAL); 53563c13d61SErin Lo 53663c13d61SErin Lo return ptr; 53763c13d61SErin Lo } 53863c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_mapping_dm_addr); 53963c13d61SErin Lo 54063c13d61SErin Lo static int scp_map_memory_region(struct mtk_scp *scp) 54163c13d61SErin Lo { 54263c13d61SErin Lo int ret; 54363c13d61SErin Lo 54463c13d61SErin Lo ret = of_reserved_mem_device_init(scp->dev); 545fd0b6c1fSPi-Hsun Shih 546fd0b6c1fSPi-Hsun Shih /* reserved memory is optional. */ 547fd0b6c1fSPi-Hsun Shih if (ret == -ENODEV) { 548fd0b6c1fSPi-Hsun Shih dev_info(scp->dev, "skipping reserved memory initialization."); 549fd0b6c1fSPi-Hsun Shih return 0; 550fd0b6c1fSPi-Hsun Shih } 551fd0b6c1fSPi-Hsun Shih 55263c13d61SErin Lo if (ret) { 55363c13d61SErin Lo dev_err(scp->dev, "failed to assign memory-region: %d\n", ret); 55463c13d61SErin Lo return -ENOMEM; 55563c13d61SErin Lo } 55663c13d61SErin Lo 55763c13d61SErin Lo /* Reserved SCP code size */ 55863c13d61SErin Lo scp->dram_size = MAX_CODE_SIZE; 55963c13d61SErin Lo scp->cpu_addr = dma_alloc_coherent(scp->dev, scp->dram_size, 560c2781e4dSArnd Bergmann &scp->dma_addr, GFP_KERNEL); 56163c13d61SErin Lo if (!scp->cpu_addr) 56263c13d61SErin Lo return -ENOMEM; 56363c13d61SErin Lo 56463c13d61SErin Lo return 0; 56563c13d61SErin Lo } 56663c13d61SErin Lo 56763c13d61SErin Lo static void scp_unmap_memory_region(struct mtk_scp *scp) 56863c13d61SErin Lo { 569fd0b6c1fSPi-Hsun Shih if (scp->dram_size == 0) 570fd0b6c1fSPi-Hsun Shih return; 571fd0b6c1fSPi-Hsun Shih 57263c13d61SErin Lo dma_free_coherent(scp->dev, scp->dram_size, scp->cpu_addr, 573c2781e4dSArnd Bergmann scp->dma_addr); 57463c13d61SErin Lo of_reserved_mem_device_release(scp->dev); 57563c13d61SErin Lo } 57663c13d61SErin Lo 57770179969SPi-Hsun Shih static int scp_register_ipi(struct platform_device *pdev, u32 id, 57870179969SPi-Hsun Shih ipi_handler_t handler, void *priv) 57970179969SPi-Hsun Shih { 58070179969SPi-Hsun Shih struct mtk_scp *scp = platform_get_drvdata(pdev); 58170179969SPi-Hsun Shih 58270179969SPi-Hsun Shih return scp_ipi_register(scp, id, handler, priv); 58370179969SPi-Hsun Shih } 58470179969SPi-Hsun Shih 58570179969SPi-Hsun Shih static void scp_unregister_ipi(struct platform_device *pdev, u32 id) 58670179969SPi-Hsun Shih { 58770179969SPi-Hsun Shih struct mtk_scp *scp = platform_get_drvdata(pdev); 58870179969SPi-Hsun Shih 58970179969SPi-Hsun Shih scp_ipi_unregister(scp, id); 59070179969SPi-Hsun Shih } 59170179969SPi-Hsun Shih 59270179969SPi-Hsun Shih static int scp_send_ipi(struct platform_device *pdev, u32 id, void *buf, 59370179969SPi-Hsun Shih unsigned int len, unsigned int wait) 59470179969SPi-Hsun Shih { 59570179969SPi-Hsun Shih struct mtk_scp *scp = platform_get_drvdata(pdev); 59670179969SPi-Hsun Shih 59770179969SPi-Hsun Shih return scp_ipi_send(scp, id, buf, len, wait); 59870179969SPi-Hsun Shih } 59970179969SPi-Hsun Shih 60070179969SPi-Hsun Shih static struct mtk_rpmsg_info mtk_scp_rpmsg_info = { 60170179969SPi-Hsun Shih .send_ipi = scp_send_ipi, 60270179969SPi-Hsun Shih .register_ipi = scp_register_ipi, 60370179969SPi-Hsun Shih .unregister_ipi = scp_unregister_ipi, 60470179969SPi-Hsun Shih .ns_ipi_id = SCP_IPI_NS_SERVICE, 60570179969SPi-Hsun Shih }; 60670179969SPi-Hsun Shih 60770179969SPi-Hsun Shih static void scp_add_rpmsg_subdev(struct mtk_scp *scp) 60870179969SPi-Hsun Shih { 60970179969SPi-Hsun Shih scp->rpmsg_subdev = 61070179969SPi-Hsun Shih mtk_rpmsg_create_rproc_subdev(to_platform_device(scp->dev), 61170179969SPi-Hsun Shih &mtk_scp_rpmsg_info); 61270179969SPi-Hsun Shih if (scp->rpmsg_subdev) 61370179969SPi-Hsun Shih rproc_add_subdev(scp->rproc, scp->rpmsg_subdev); 61470179969SPi-Hsun Shih } 61570179969SPi-Hsun Shih 61670179969SPi-Hsun Shih static void scp_remove_rpmsg_subdev(struct mtk_scp *scp) 61770179969SPi-Hsun Shih { 61870179969SPi-Hsun Shih if (scp->rpmsg_subdev) { 61970179969SPi-Hsun Shih rproc_remove_subdev(scp->rproc, scp->rpmsg_subdev); 62070179969SPi-Hsun Shih mtk_rpmsg_destroy_rproc_subdev(scp->rpmsg_subdev); 62170179969SPi-Hsun Shih scp->rpmsg_subdev = NULL; 62270179969SPi-Hsun Shih } 62370179969SPi-Hsun Shih } 62470179969SPi-Hsun Shih 62563c13d61SErin Lo static int scp_probe(struct platform_device *pdev) 62663c13d61SErin Lo { 62763c13d61SErin Lo struct device *dev = &pdev->dev; 62863c13d61SErin Lo struct device_node *np = dev->of_node; 62963c13d61SErin Lo struct mtk_scp *scp; 63063c13d61SErin Lo struct rproc *rproc; 63163c13d61SErin Lo struct resource *res; 63263c13d61SErin Lo char *fw_name = "scp.img"; 63363c13d61SErin Lo int ret, i; 63463c13d61SErin Lo 63563c13d61SErin Lo rproc = rproc_alloc(dev, 63663c13d61SErin Lo np->name, 63763c13d61SErin Lo &scp_ops, 63863c13d61SErin Lo fw_name, 63963c13d61SErin Lo sizeof(*scp)); 64063c13d61SErin Lo if (!rproc) { 64163c13d61SErin Lo dev_err(dev, "unable to allocate remoteproc\n"); 64263c13d61SErin Lo return -ENOMEM; 64363c13d61SErin Lo } 64463c13d61SErin Lo 64563c13d61SErin Lo scp = (struct mtk_scp *)rproc->priv; 64663c13d61SErin Lo scp->rproc = rproc; 64763c13d61SErin Lo scp->dev = dev; 648fd0b6c1fSPi-Hsun Shih scp->data = of_device_get_match_data(dev); 64963c13d61SErin Lo platform_set_drvdata(pdev, scp); 65063c13d61SErin Lo 65163c13d61SErin Lo res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); 65263c13d61SErin Lo scp->sram_base = devm_ioremap_resource(dev, res); 65363c13d61SErin Lo if (IS_ERR((__force void *)scp->sram_base)) { 65463c13d61SErin Lo dev_err(dev, "Failed to parse and map sram memory\n"); 65563c13d61SErin Lo ret = PTR_ERR((__force void *)scp->sram_base); 65663c13d61SErin Lo goto free_rproc; 65763c13d61SErin Lo } 65863c13d61SErin Lo scp->sram_size = resource_size(res); 65963c13d61SErin Lo 66063c13d61SErin Lo mutex_init(&scp->send_lock); 66163c13d61SErin Lo for (i = 0; i < SCP_IPI_MAX; i++) 66263c13d61SErin Lo mutex_init(&scp->ipi_desc[i].lock); 66363c13d61SErin Lo 66463c13d61SErin Lo res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); 66563c13d61SErin Lo scp->reg_base = devm_ioremap_resource(dev, res); 66663c13d61SErin Lo if (IS_ERR((__force void *)scp->reg_base)) { 66763c13d61SErin Lo dev_err(dev, "Failed to parse and map cfg memory\n"); 66863c13d61SErin Lo ret = PTR_ERR((__force void *)scp->reg_base); 66963c13d61SErin Lo goto destroy_mutex; 67063c13d61SErin Lo } 67163c13d61SErin Lo 67263c13d61SErin Lo ret = scp_map_memory_region(scp); 67363c13d61SErin Lo if (ret) 67463c13d61SErin Lo goto destroy_mutex; 67563c13d61SErin Lo 67663c13d61SErin Lo scp->clk = devm_clk_get(dev, "main"); 67763c13d61SErin Lo if (IS_ERR(scp->clk)) { 67863c13d61SErin Lo dev_err(dev, "Failed to get clock\n"); 67963c13d61SErin Lo ret = PTR_ERR(scp->clk); 68063c13d61SErin Lo goto release_dev_mem; 68163c13d61SErin Lo } 68263c13d61SErin Lo 68363c13d61SErin Lo ret = clk_prepare_enable(scp->clk); 68463c13d61SErin Lo if (ret) { 68563c13d61SErin Lo dev_err(dev, "failed to enable clocks\n"); 68663c13d61SErin Lo goto release_dev_mem; 68763c13d61SErin Lo } 68863c13d61SErin Lo 68963c13d61SErin Lo ret = scp_ipi_init(scp); 69063c13d61SErin Lo clk_disable_unprepare(scp->clk); 69163c13d61SErin Lo if (ret) { 69263c13d61SErin Lo dev_err(dev, "Failed to init ipi\n"); 69363c13d61SErin Lo goto release_dev_mem; 69463c13d61SErin Lo } 69563c13d61SErin Lo 69663c13d61SErin Lo /* register SCP initialization IPI */ 69763c13d61SErin Lo ret = scp_ipi_register(scp, SCP_IPI_INIT, scp_init_ipi_handler, scp); 69863c13d61SErin Lo if (ret) { 69963c13d61SErin Lo dev_err(dev, "Failed to register IPI_SCP_INIT\n"); 70063c13d61SErin Lo goto release_dev_mem; 70163c13d61SErin Lo } 70263c13d61SErin Lo 70363c13d61SErin Lo init_waitqueue_head(&scp->run.wq); 70463c13d61SErin Lo init_waitqueue_head(&scp->ack_wq); 70563c13d61SErin Lo 70670179969SPi-Hsun Shih scp_add_rpmsg_subdev(scp); 70770179969SPi-Hsun Shih 70863c13d61SErin Lo ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), NULL, 70963c13d61SErin Lo scp_irq_handler, IRQF_ONESHOT, 71063c13d61SErin Lo pdev->name, scp); 71163c13d61SErin Lo 71263c13d61SErin Lo if (ret) { 71363c13d61SErin Lo dev_err(dev, "failed to request irq\n"); 71470179969SPi-Hsun Shih goto remove_subdev; 71563c13d61SErin Lo } 71663c13d61SErin Lo 71763c13d61SErin Lo ret = rproc_add(rproc); 71863c13d61SErin Lo if (ret) 71970179969SPi-Hsun Shih goto remove_subdev; 72063c13d61SErin Lo 72170179969SPi-Hsun Shih return 0; 72263c13d61SErin Lo 72370179969SPi-Hsun Shih remove_subdev: 72470179969SPi-Hsun Shih scp_remove_rpmsg_subdev(scp); 72563c13d61SErin Lo scp_ipi_unregister(scp, SCP_IPI_INIT); 72663c13d61SErin Lo release_dev_mem: 72763c13d61SErin Lo scp_unmap_memory_region(scp); 72863c13d61SErin Lo destroy_mutex: 72963c13d61SErin Lo for (i = 0; i < SCP_IPI_MAX; i++) 73063c13d61SErin Lo mutex_destroy(&scp->ipi_desc[i].lock); 73163c13d61SErin Lo mutex_destroy(&scp->send_lock); 73263c13d61SErin Lo free_rproc: 73363c13d61SErin Lo rproc_free(rproc); 73463c13d61SErin Lo 73563c13d61SErin Lo return ret; 73663c13d61SErin Lo } 73763c13d61SErin Lo 73863c13d61SErin Lo static int scp_remove(struct platform_device *pdev) 73963c13d61SErin Lo { 74063c13d61SErin Lo struct mtk_scp *scp = platform_get_drvdata(pdev); 74163c13d61SErin Lo int i; 74263c13d61SErin Lo 74363c13d61SErin Lo rproc_del(scp->rproc); 74470179969SPi-Hsun Shih scp_remove_rpmsg_subdev(scp); 74563c13d61SErin Lo scp_ipi_unregister(scp, SCP_IPI_INIT); 74663c13d61SErin Lo scp_unmap_memory_region(scp); 74763c13d61SErin Lo for (i = 0; i < SCP_IPI_MAX; i++) 74863c13d61SErin Lo mutex_destroy(&scp->ipi_desc[i].lock); 74963c13d61SErin Lo mutex_destroy(&scp->send_lock); 75063c13d61SErin Lo rproc_free(scp->rproc); 75163c13d61SErin Lo 75263c13d61SErin Lo return 0; 75363c13d61SErin Lo } 75463c13d61SErin Lo 755fd0b6c1fSPi-Hsun Shih static const struct mtk_scp_of_data mt8183_of_data = { 756fd0b6c1fSPi-Hsun Shih .scp_before_load = mt8183_scp_before_load, 757fd0b6c1fSPi-Hsun Shih .scp_irq_handler = mt8183_scp_irq_handler, 758fd0b6c1fSPi-Hsun Shih .scp_reset_assert = mt8183_scp_reset_assert, 759fd0b6c1fSPi-Hsun Shih .scp_reset_deassert = mt8183_scp_reset_deassert, 760fd0b6c1fSPi-Hsun Shih .scp_stop = mt8183_scp_stop, 761fd0b6c1fSPi-Hsun Shih .host_to_scp_reg = MT8183_HOST_TO_SCP, 762fd0b6c1fSPi-Hsun Shih .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT, 763fd0b6c1fSPi-Hsun Shih }; 764fd0b6c1fSPi-Hsun Shih 765fd0b6c1fSPi-Hsun Shih static const struct mtk_scp_of_data mt8192_of_data = { 766fd0b6c1fSPi-Hsun Shih .scp_before_load = mt8192_scp_before_load, 767fd0b6c1fSPi-Hsun Shih .scp_irq_handler = mt8192_scp_irq_handler, 768fd0b6c1fSPi-Hsun Shih .scp_reset_assert = mt8192_scp_reset_assert, 769fd0b6c1fSPi-Hsun Shih .scp_reset_deassert = mt8192_scp_reset_deassert, 770fd0b6c1fSPi-Hsun Shih .scp_stop = mt8192_scp_stop, 771fd0b6c1fSPi-Hsun Shih .host_to_scp_reg = MT8192_GIPC_IN_SET, 772fd0b6c1fSPi-Hsun Shih .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, 773fd0b6c1fSPi-Hsun Shih }; 774fd0b6c1fSPi-Hsun Shih 77563c13d61SErin Lo static const struct of_device_id mtk_scp_of_match[] = { 776fd0b6c1fSPi-Hsun Shih { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, 777fd0b6c1fSPi-Hsun Shih { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, 77863c13d61SErin Lo {}, 77963c13d61SErin Lo }; 78063c13d61SErin Lo MODULE_DEVICE_TABLE(of, mtk_scp_of_match); 78163c13d61SErin Lo 78263c13d61SErin Lo static struct platform_driver mtk_scp_driver = { 78363c13d61SErin Lo .probe = scp_probe, 78463c13d61SErin Lo .remove = scp_remove, 78563c13d61SErin Lo .driver = { 78663c13d61SErin Lo .name = "mtk-scp", 78763c13d61SErin Lo .of_match_table = of_match_ptr(mtk_scp_of_match), 78863c13d61SErin Lo }, 78963c13d61SErin Lo }; 79063c13d61SErin Lo 79163c13d61SErin Lo module_platform_driver(mtk_scp_driver); 79263c13d61SErin Lo 79363c13d61SErin Lo MODULE_LICENSE("GPL v2"); 79463c13d61SErin Lo MODULE_DESCRIPTION("MediaTek SCP control driver"); 795