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 dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", 23863c13d61SErin Lo phdr->p_type, da, memsz, filesz); 23963c13d61SErin Lo 24048cb5b68STzung-Bi Shih if (phdr->p_type != PT_LOAD) 24148cb5b68STzung-Bi Shih continue; 24248cb5b68STzung-Bi Shih if (!filesz) 24348cb5b68STzung-Bi Shih continue; 24448cb5b68STzung-Bi Shih 24563c13d61SErin Lo if (filesz > memsz) { 24663c13d61SErin Lo dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", 24763c13d61SErin Lo filesz, memsz); 24863c13d61SErin Lo ret = -EINVAL; 24963c13d61SErin Lo break; 25063c13d61SErin Lo } 25163c13d61SErin Lo 25263c13d61SErin Lo if (offset + filesz > fw->size) { 25363c13d61SErin Lo dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", 25463c13d61SErin Lo offset + filesz, fw->size); 25563c13d61SErin Lo ret = -EINVAL; 25663c13d61SErin Lo break; 25763c13d61SErin Lo } 25863c13d61SErin Lo 25963c13d61SErin Lo /* grab the kernel address for this device address */ 26063c13d61SErin Lo ptr = (void __iomem *)rproc_da_to_va(rproc, da, memsz); 26163c13d61SErin Lo if (!ptr) { 26263c13d61SErin Lo dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); 26363c13d61SErin Lo ret = -EINVAL; 26463c13d61SErin Lo break; 26563c13d61SErin Lo } 26663c13d61SErin Lo 26763c13d61SErin Lo /* put the segment where the remote processor expects it */ 26848cb5b68STzung-Bi Shih scp_memcpy_aligned(ptr, elf_data + phdr->p_offset, 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 301778f2664STzung-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 310778f2664STzung-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) 353*22c3df6fSTzung-Bi Shih goto leave; 354fd0b6c1fSPi-Hsun Shih 35563c13d61SErin Lo ret = scp_elf_load_segments(rproc, fw); 356*22c3df6fSTzung-Bi Shih leave: 35763c13d61SErin Lo clk_disable_unprepare(scp->clk); 35863c13d61SErin Lo 35963c13d61SErin Lo return ret; 36063c13d61SErin Lo } 36163c13d61SErin Lo 36263c13d61SErin Lo static int scp_start(struct rproc *rproc) 36363c13d61SErin Lo { 36463c13d61SErin Lo struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 36563c13d61SErin Lo struct device *dev = scp->dev; 36663c13d61SErin Lo struct scp_run *run = &scp->run; 36763c13d61SErin Lo int ret; 36863c13d61SErin Lo 36963c13d61SErin Lo ret = clk_prepare_enable(scp->clk); 37063c13d61SErin Lo if (ret) { 37163c13d61SErin Lo dev_err(dev, "failed to enable clocks\n"); 37263c13d61SErin Lo return ret; 37363c13d61SErin Lo } 37463c13d61SErin Lo 37563c13d61SErin Lo run->signaled = false; 37663c13d61SErin Lo 377fd0b6c1fSPi-Hsun Shih scp->data->scp_reset_deassert(scp); 37863c13d61SErin Lo 37963c13d61SErin Lo ret = wait_event_interruptible_timeout( 38063c13d61SErin Lo run->wq, 38163c13d61SErin Lo run->signaled, 38263c13d61SErin Lo msecs_to_jiffies(2000)); 38363c13d61SErin Lo 38463c13d61SErin Lo if (ret == 0) { 38563c13d61SErin Lo dev_err(dev, "wait SCP initialization timeout!\n"); 38663c13d61SErin Lo ret = -ETIME; 38763c13d61SErin Lo goto stop; 38863c13d61SErin Lo } 38963c13d61SErin Lo if (ret == -ERESTARTSYS) { 39063c13d61SErin Lo dev_err(dev, "wait SCP interrupted by a signal!\n"); 39163c13d61SErin Lo goto stop; 39263c13d61SErin Lo } 393fd0b6c1fSPi-Hsun Shih 39463c13d61SErin Lo clk_disable_unprepare(scp->clk); 39563c13d61SErin Lo dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver); 39663c13d61SErin Lo 39763c13d61SErin Lo return 0; 39863c13d61SErin Lo 39963c13d61SErin Lo stop: 400fd0b6c1fSPi-Hsun Shih scp->data->scp_reset_assert(scp); 40163c13d61SErin Lo clk_disable_unprepare(scp->clk); 40263c13d61SErin Lo return ret; 40363c13d61SErin Lo } 40463c13d61SErin Lo 405e1833b9eSNathan Chancellor static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len) 40663c13d61SErin Lo { 40763c13d61SErin Lo struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 40863c13d61SErin Lo int offset; 40963c13d61SErin Lo 41063c13d61SErin Lo if (da < scp->sram_size) { 41163c13d61SErin Lo offset = da; 41271ffb5a2STzung-Bi Shih if (offset >= 0 && (offset + len) <= scp->sram_size) 41363c13d61SErin Lo return (void __force *)scp->sram_base + offset; 414fd0b6c1fSPi-Hsun Shih } else if (scp->dram_size) { 415c2781e4dSArnd Bergmann offset = da - scp->dma_addr; 41671ffb5a2STzung-Bi Shih if (offset >= 0 && (offset + len) <= scp->dram_size) 417903635cbSTzung-Bi Shih return scp->cpu_addr + offset; 41863c13d61SErin Lo } 41963c13d61SErin Lo 42063c13d61SErin Lo return NULL; 42163c13d61SErin Lo } 42263c13d61SErin Lo 423fd0b6c1fSPi-Hsun Shih static void mt8183_scp_stop(struct mtk_scp *scp) 424fd0b6c1fSPi-Hsun Shih { 425fd0b6c1fSPi-Hsun Shih /* Disable SCP watchdog */ 426fd0b6c1fSPi-Hsun Shih writel(0, scp->reg_base + MT8183_WDT_CFG); 427fd0b6c1fSPi-Hsun Shih } 428fd0b6c1fSPi-Hsun Shih 429fd0b6c1fSPi-Hsun Shih static void mt8192_scp_stop(struct mtk_scp *scp) 430fd0b6c1fSPi-Hsun Shih { 431fd0b6c1fSPi-Hsun Shih /* Disable SRAM clock */ 432fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_0); 433fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_1); 434fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_2); 435fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_L1TCM_SRAM_PDN); 436fd0b6c1fSPi-Hsun Shih mt8192_power_off_sram(scp->reg_base + MT8192_CPU0_SRAM_PD); 437fd0b6c1fSPi-Hsun Shih 438fd0b6c1fSPi-Hsun Shih /* Disable SCP watchdog */ 439fd0b6c1fSPi-Hsun Shih writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG); 440fd0b6c1fSPi-Hsun Shih } 441fd0b6c1fSPi-Hsun Shih 44263c13d61SErin Lo static int scp_stop(struct rproc *rproc) 44363c13d61SErin Lo { 44463c13d61SErin Lo struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; 44563c13d61SErin Lo int ret; 44663c13d61SErin Lo 44763c13d61SErin Lo ret = clk_prepare_enable(scp->clk); 44863c13d61SErin Lo if (ret) { 44963c13d61SErin Lo dev_err(scp->dev, "failed to enable clocks\n"); 45063c13d61SErin Lo return ret; 45163c13d61SErin Lo } 45263c13d61SErin Lo 453fd0b6c1fSPi-Hsun Shih scp->data->scp_reset_assert(scp); 454fd0b6c1fSPi-Hsun Shih scp->data->scp_stop(scp); 45563c13d61SErin Lo clk_disable_unprepare(scp->clk); 45663c13d61SErin Lo 45763c13d61SErin Lo return 0; 45863c13d61SErin Lo } 45963c13d61SErin Lo 46063c13d61SErin Lo static const struct rproc_ops scp_ops = { 46163c13d61SErin Lo .start = scp_start, 46263c13d61SErin Lo .stop = scp_stop, 46363c13d61SErin Lo .load = scp_load, 46463c13d61SErin Lo .da_to_va = scp_da_to_va, 46563c13d61SErin Lo }; 46663c13d61SErin Lo 46763c13d61SErin Lo /** 46863c13d61SErin Lo * scp_get_device() - get device struct of SCP 46963c13d61SErin Lo * 47063c13d61SErin Lo * @scp: mtk_scp structure 47163c13d61SErin Lo **/ 47263c13d61SErin Lo struct device *scp_get_device(struct mtk_scp *scp) 47363c13d61SErin Lo { 47463c13d61SErin Lo return scp->dev; 47563c13d61SErin Lo } 47663c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_device); 47763c13d61SErin Lo 47863c13d61SErin Lo /** 47963c13d61SErin Lo * scp_get_rproc() - get rproc struct of SCP 48063c13d61SErin Lo * 48163c13d61SErin Lo * @scp: mtk_scp structure 48263c13d61SErin Lo **/ 48363c13d61SErin Lo struct rproc *scp_get_rproc(struct mtk_scp *scp) 48463c13d61SErin Lo { 48563c13d61SErin Lo return scp->rproc; 48663c13d61SErin Lo } 48763c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_rproc); 48863c13d61SErin Lo 48963c13d61SErin Lo /** 49063c13d61SErin Lo * scp_get_vdec_hw_capa() - get video decoder hardware capability 49163c13d61SErin Lo * 49263c13d61SErin Lo * @scp: mtk_scp structure 49363c13d61SErin Lo * 49463c13d61SErin Lo * Return: video decoder hardware capability 49563c13d61SErin Lo **/ 49663c13d61SErin Lo unsigned int scp_get_vdec_hw_capa(struct mtk_scp *scp) 49763c13d61SErin Lo { 49863c13d61SErin Lo return scp->run.dec_capability; 49963c13d61SErin Lo } 50063c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_vdec_hw_capa); 50163c13d61SErin Lo 50263c13d61SErin Lo /** 50363c13d61SErin Lo * scp_get_venc_hw_capa() - get video encoder hardware capability 50463c13d61SErin Lo * 50563c13d61SErin Lo * @scp: mtk_scp structure 50663c13d61SErin Lo * 50763c13d61SErin Lo * Return: video encoder hardware capability 50863c13d61SErin Lo **/ 50963c13d61SErin Lo unsigned int scp_get_venc_hw_capa(struct mtk_scp *scp) 51063c13d61SErin Lo { 51163c13d61SErin Lo return scp->run.enc_capability; 51263c13d61SErin Lo } 51363c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_get_venc_hw_capa); 51463c13d61SErin Lo 51563c13d61SErin Lo /** 51663c13d61SErin Lo * scp_mapping_dm_addr() - Mapping SRAM/DRAM to kernel virtual address 51763c13d61SErin Lo * 51863c13d61SErin Lo * @scp: mtk_scp structure 51963c13d61SErin Lo * @mem_addr: SCP views memory address 52063c13d61SErin Lo * 52163c13d61SErin Lo * Mapping the SCP's SRAM address / 52263c13d61SErin Lo * DMEM (Data Extended Memory) memory address / 52363c13d61SErin Lo * Working buffer memory address to 52463c13d61SErin Lo * kernel virtual address. 52563c13d61SErin Lo * 52663c13d61SErin Lo * Return: Return ERR_PTR(-EINVAL) if mapping failed, 52763c13d61SErin Lo * otherwise the mapped kernel virtual address 52863c13d61SErin Lo **/ 52963c13d61SErin Lo void *scp_mapping_dm_addr(struct mtk_scp *scp, u32 mem_addr) 53063c13d61SErin Lo { 53163c13d61SErin Lo void *ptr; 53263c13d61SErin Lo 53363c13d61SErin Lo ptr = scp_da_to_va(scp->rproc, mem_addr, 0); 53463c13d61SErin Lo if (!ptr) 53563c13d61SErin Lo return ERR_PTR(-EINVAL); 53663c13d61SErin Lo 53763c13d61SErin Lo return ptr; 53863c13d61SErin Lo } 53963c13d61SErin Lo EXPORT_SYMBOL_GPL(scp_mapping_dm_addr); 54063c13d61SErin Lo 54163c13d61SErin Lo static int scp_map_memory_region(struct mtk_scp *scp) 54263c13d61SErin Lo { 54363c13d61SErin Lo int ret; 54463c13d61SErin Lo 54563c13d61SErin Lo ret = of_reserved_mem_device_init(scp->dev); 546fd0b6c1fSPi-Hsun Shih 547fd0b6c1fSPi-Hsun Shih /* reserved memory is optional. */ 548fd0b6c1fSPi-Hsun Shih if (ret == -ENODEV) { 549fd0b6c1fSPi-Hsun Shih dev_info(scp->dev, "skipping reserved memory initialization."); 550fd0b6c1fSPi-Hsun Shih return 0; 551fd0b6c1fSPi-Hsun Shih } 552fd0b6c1fSPi-Hsun Shih 55363c13d61SErin Lo if (ret) { 55463c13d61SErin Lo dev_err(scp->dev, "failed to assign memory-region: %d\n", ret); 55563c13d61SErin Lo return -ENOMEM; 55663c13d61SErin Lo } 55763c13d61SErin Lo 55863c13d61SErin Lo /* Reserved SCP code size */ 55963c13d61SErin Lo scp->dram_size = MAX_CODE_SIZE; 56063c13d61SErin Lo scp->cpu_addr = dma_alloc_coherent(scp->dev, scp->dram_size, 561c2781e4dSArnd Bergmann &scp->dma_addr, GFP_KERNEL); 56263c13d61SErin Lo if (!scp->cpu_addr) 56363c13d61SErin Lo return -ENOMEM; 56463c13d61SErin Lo 56563c13d61SErin Lo return 0; 56663c13d61SErin Lo } 56763c13d61SErin Lo 56863c13d61SErin Lo static void scp_unmap_memory_region(struct mtk_scp *scp) 56963c13d61SErin Lo { 570fd0b6c1fSPi-Hsun Shih if (scp->dram_size == 0) 571fd0b6c1fSPi-Hsun Shih return; 572fd0b6c1fSPi-Hsun Shih 57363c13d61SErin Lo dma_free_coherent(scp->dev, scp->dram_size, scp->cpu_addr, 574c2781e4dSArnd Bergmann scp->dma_addr); 57563c13d61SErin Lo of_reserved_mem_device_release(scp->dev); 57663c13d61SErin Lo } 57763c13d61SErin Lo 57870179969SPi-Hsun Shih static int scp_register_ipi(struct platform_device *pdev, u32 id, 57970179969SPi-Hsun Shih ipi_handler_t handler, void *priv) 58070179969SPi-Hsun Shih { 58170179969SPi-Hsun Shih struct mtk_scp *scp = platform_get_drvdata(pdev); 58270179969SPi-Hsun Shih 58370179969SPi-Hsun Shih return scp_ipi_register(scp, id, handler, priv); 58470179969SPi-Hsun Shih } 58570179969SPi-Hsun Shih 58670179969SPi-Hsun Shih static void scp_unregister_ipi(struct platform_device *pdev, u32 id) 58770179969SPi-Hsun Shih { 58870179969SPi-Hsun Shih struct mtk_scp *scp = platform_get_drvdata(pdev); 58970179969SPi-Hsun Shih 59070179969SPi-Hsun Shih scp_ipi_unregister(scp, id); 59170179969SPi-Hsun Shih } 59270179969SPi-Hsun Shih 59370179969SPi-Hsun Shih static int scp_send_ipi(struct platform_device *pdev, u32 id, void *buf, 59470179969SPi-Hsun Shih unsigned int len, unsigned int wait) 59570179969SPi-Hsun Shih { 59670179969SPi-Hsun Shih struct mtk_scp *scp = platform_get_drvdata(pdev); 59770179969SPi-Hsun Shih 59870179969SPi-Hsun Shih return scp_ipi_send(scp, id, buf, len, wait); 59970179969SPi-Hsun Shih } 60070179969SPi-Hsun Shih 60170179969SPi-Hsun Shih static struct mtk_rpmsg_info mtk_scp_rpmsg_info = { 60270179969SPi-Hsun Shih .send_ipi = scp_send_ipi, 60370179969SPi-Hsun Shih .register_ipi = scp_register_ipi, 60470179969SPi-Hsun Shih .unregister_ipi = scp_unregister_ipi, 60570179969SPi-Hsun Shih .ns_ipi_id = SCP_IPI_NS_SERVICE, 60670179969SPi-Hsun Shih }; 60770179969SPi-Hsun Shih 60870179969SPi-Hsun Shih static void scp_add_rpmsg_subdev(struct mtk_scp *scp) 60970179969SPi-Hsun Shih { 61070179969SPi-Hsun Shih scp->rpmsg_subdev = 61170179969SPi-Hsun Shih mtk_rpmsg_create_rproc_subdev(to_platform_device(scp->dev), 61270179969SPi-Hsun Shih &mtk_scp_rpmsg_info); 61370179969SPi-Hsun Shih if (scp->rpmsg_subdev) 61470179969SPi-Hsun Shih rproc_add_subdev(scp->rproc, scp->rpmsg_subdev); 61570179969SPi-Hsun Shih } 61670179969SPi-Hsun Shih 61770179969SPi-Hsun Shih static void scp_remove_rpmsg_subdev(struct mtk_scp *scp) 61870179969SPi-Hsun Shih { 61970179969SPi-Hsun Shih if (scp->rpmsg_subdev) { 62070179969SPi-Hsun Shih rproc_remove_subdev(scp->rproc, scp->rpmsg_subdev); 62170179969SPi-Hsun Shih mtk_rpmsg_destroy_rproc_subdev(scp->rpmsg_subdev); 62270179969SPi-Hsun Shih scp->rpmsg_subdev = NULL; 62370179969SPi-Hsun Shih } 62470179969SPi-Hsun Shih } 62570179969SPi-Hsun Shih 62663c13d61SErin Lo static int scp_probe(struct platform_device *pdev) 62763c13d61SErin Lo { 62863c13d61SErin Lo struct device *dev = &pdev->dev; 62963c13d61SErin Lo struct device_node *np = dev->of_node; 63063c13d61SErin Lo struct mtk_scp *scp; 63163c13d61SErin Lo struct rproc *rproc; 63263c13d61SErin Lo struct resource *res; 63363c13d61SErin Lo char *fw_name = "scp.img"; 63463c13d61SErin Lo int ret, i; 63563c13d61SErin Lo 63663c13d61SErin Lo rproc = rproc_alloc(dev, 63763c13d61SErin Lo np->name, 63863c13d61SErin Lo &scp_ops, 63963c13d61SErin Lo fw_name, 64063c13d61SErin Lo sizeof(*scp)); 64163c13d61SErin Lo if (!rproc) { 64263c13d61SErin Lo dev_err(dev, "unable to allocate remoteproc\n"); 64363c13d61SErin Lo return -ENOMEM; 64463c13d61SErin Lo } 64563c13d61SErin Lo 64663c13d61SErin Lo scp = (struct mtk_scp *)rproc->priv; 64763c13d61SErin Lo scp->rproc = rproc; 64863c13d61SErin Lo scp->dev = dev; 649fd0b6c1fSPi-Hsun Shih scp->data = of_device_get_match_data(dev); 65063c13d61SErin Lo platform_set_drvdata(pdev, scp); 65163c13d61SErin Lo 65263c13d61SErin Lo res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); 65363c13d61SErin Lo scp->sram_base = devm_ioremap_resource(dev, res); 65463c13d61SErin Lo if (IS_ERR((__force void *)scp->sram_base)) { 65563c13d61SErin Lo dev_err(dev, "Failed to parse and map sram memory\n"); 65663c13d61SErin Lo ret = PTR_ERR((__force void *)scp->sram_base); 65763c13d61SErin Lo goto free_rproc; 65863c13d61SErin Lo } 65963c13d61SErin Lo scp->sram_size = resource_size(res); 66063c13d61SErin Lo 66163c13d61SErin Lo mutex_init(&scp->send_lock); 66263c13d61SErin Lo for (i = 0; i < SCP_IPI_MAX; i++) 66363c13d61SErin Lo mutex_init(&scp->ipi_desc[i].lock); 66463c13d61SErin Lo 66563c13d61SErin Lo res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); 66663c13d61SErin Lo scp->reg_base = devm_ioremap_resource(dev, res); 66763c13d61SErin Lo if (IS_ERR((__force void *)scp->reg_base)) { 66863c13d61SErin Lo dev_err(dev, "Failed to parse and map cfg memory\n"); 66963c13d61SErin Lo ret = PTR_ERR((__force void *)scp->reg_base); 67063c13d61SErin Lo goto destroy_mutex; 67163c13d61SErin Lo } 67263c13d61SErin Lo 67363c13d61SErin Lo ret = scp_map_memory_region(scp); 67463c13d61SErin Lo if (ret) 67563c13d61SErin Lo goto destroy_mutex; 67663c13d61SErin Lo 67763c13d61SErin Lo scp->clk = devm_clk_get(dev, "main"); 67863c13d61SErin Lo if (IS_ERR(scp->clk)) { 67963c13d61SErin Lo dev_err(dev, "Failed to get clock\n"); 68063c13d61SErin Lo ret = PTR_ERR(scp->clk); 68163c13d61SErin Lo goto release_dev_mem; 68263c13d61SErin Lo } 68363c13d61SErin Lo 68463c13d61SErin Lo ret = clk_prepare_enable(scp->clk); 68563c13d61SErin Lo if (ret) { 68663c13d61SErin Lo dev_err(dev, "failed to enable clocks\n"); 68763c13d61SErin Lo goto release_dev_mem; 68863c13d61SErin Lo } 68963c13d61SErin Lo 69063c13d61SErin Lo ret = scp_ipi_init(scp); 69163c13d61SErin Lo clk_disable_unprepare(scp->clk); 69263c13d61SErin Lo if (ret) { 69363c13d61SErin Lo dev_err(dev, "Failed to init ipi\n"); 69463c13d61SErin Lo goto release_dev_mem; 69563c13d61SErin Lo } 69663c13d61SErin Lo 69763c13d61SErin Lo /* register SCP initialization IPI */ 69863c13d61SErin Lo ret = scp_ipi_register(scp, SCP_IPI_INIT, scp_init_ipi_handler, scp); 69963c13d61SErin Lo if (ret) { 70063c13d61SErin Lo dev_err(dev, "Failed to register IPI_SCP_INIT\n"); 70163c13d61SErin Lo goto release_dev_mem; 70263c13d61SErin Lo } 70363c13d61SErin Lo 70463c13d61SErin Lo init_waitqueue_head(&scp->run.wq); 70563c13d61SErin Lo init_waitqueue_head(&scp->ack_wq); 70663c13d61SErin Lo 70770179969SPi-Hsun Shih scp_add_rpmsg_subdev(scp); 70870179969SPi-Hsun Shih 70963c13d61SErin Lo ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), NULL, 71063c13d61SErin Lo scp_irq_handler, IRQF_ONESHOT, 71163c13d61SErin Lo pdev->name, scp); 71263c13d61SErin Lo 71363c13d61SErin Lo if (ret) { 71463c13d61SErin Lo dev_err(dev, "failed to request irq\n"); 71570179969SPi-Hsun Shih goto remove_subdev; 71663c13d61SErin Lo } 71763c13d61SErin Lo 71863c13d61SErin Lo ret = rproc_add(rproc); 71963c13d61SErin Lo if (ret) 72070179969SPi-Hsun Shih goto remove_subdev; 72163c13d61SErin Lo 72270179969SPi-Hsun Shih return 0; 72363c13d61SErin Lo 72470179969SPi-Hsun Shih remove_subdev: 72570179969SPi-Hsun Shih scp_remove_rpmsg_subdev(scp); 72663c13d61SErin Lo scp_ipi_unregister(scp, SCP_IPI_INIT); 72763c13d61SErin Lo release_dev_mem: 72863c13d61SErin Lo scp_unmap_memory_region(scp); 72963c13d61SErin Lo destroy_mutex: 73063c13d61SErin Lo for (i = 0; i < SCP_IPI_MAX; i++) 73163c13d61SErin Lo mutex_destroy(&scp->ipi_desc[i].lock); 73263c13d61SErin Lo mutex_destroy(&scp->send_lock); 73363c13d61SErin Lo free_rproc: 73463c13d61SErin Lo rproc_free(rproc); 73563c13d61SErin Lo 73663c13d61SErin Lo return ret; 73763c13d61SErin Lo } 73863c13d61SErin Lo 73963c13d61SErin Lo static int scp_remove(struct platform_device *pdev) 74063c13d61SErin Lo { 74163c13d61SErin Lo struct mtk_scp *scp = platform_get_drvdata(pdev); 74263c13d61SErin Lo int i; 74363c13d61SErin Lo 74463c13d61SErin Lo rproc_del(scp->rproc); 74570179969SPi-Hsun Shih scp_remove_rpmsg_subdev(scp); 74663c13d61SErin Lo scp_ipi_unregister(scp, SCP_IPI_INIT); 74763c13d61SErin Lo scp_unmap_memory_region(scp); 74863c13d61SErin Lo for (i = 0; i < SCP_IPI_MAX; i++) 74963c13d61SErin Lo mutex_destroy(&scp->ipi_desc[i].lock); 75063c13d61SErin Lo mutex_destroy(&scp->send_lock); 75163c13d61SErin Lo rproc_free(scp->rproc); 75263c13d61SErin Lo 75363c13d61SErin Lo return 0; 75463c13d61SErin Lo } 75563c13d61SErin Lo 756fd0b6c1fSPi-Hsun Shih static const struct mtk_scp_of_data mt8183_of_data = { 757fd0b6c1fSPi-Hsun Shih .scp_before_load = mt8183_scp_before_load, 758fd0b6c1fSPi-Hsun Shih .scp_irq_handler = mt8183_scp_irq_handler, 759fd0b6c1fSPi-Hsun Shih .scp_reset_assert = mt8183_scp_reset_assert, 760fd0b6c1fSPi-Hsun Shih .scp_reset_deassert = mt8183_scp_reset_deassert, 761fd0b6c1fSPi-Hsun Shih .scp_stop = mt8183_scp_stop, 762fd0b6c1fSPi-Hsun Shih .host_to_scp_reg = MT8183_HOST_TO_SCP, 763fd0b6c1fSPi-Hsun Shih .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT, 764fd0b6c1fSPi-Hsun Shih }; 765fd0b6c1fSPi-Hsun Shih 766fd0b6c1fSPi-Hsun Shih static const struct mtk_scp_of_data mt8192_of_data = { 767fd0b6c1fSPi-Hsun Shih .scp_before_load = mt8192_scp_before_load, 768fd0b6c1fSPi-Hsun Shih .scp_irq_handler = mt8192_scp_irq_handler, 769fd0b6c1fSPi-Hsun Shih .scp_reset_assert = mt8192_scp_reset_assert, 770fd0b6c1fSPi-Hsun Shih .scp_reset_deassert = mt8192_scp_reset_deassert, 771fd0b6c1fSPi-Hsun Shih .scp_stop = mt8192_scp_stop, 772fd0b6c1fSPi-Hsun Shih .host_to_scp_reg = MT8192_GIPC_IN_SET, 773fd0b6c1fSPi-Hsun Shih .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, 774fd0b6c1fSPi-Hsun Shih }; 775fd0b6c1fSPi-Hsun Shih 77663c13d61SErin Lo static const struct of_device_id mtk_scp_of_match[] = { 777fd0b6c1fSPi-Hsun Shih { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, 778fd0b6c1fSPi-Hsun Shih { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, 77963c13d61SErin Lo {}, 78063c13d61SErin Lo }; 78163c13d61SErin Lo MODULE_DEVICE_TABLE(of, mtk_scp_of_match); 78263c13d61SErin Lo 78363c13d61SErin Lo static struct platform_driver mtk_scp_driver = { 78463c13d61SErin Lo .probe = scp_probe, 78563c13d61SErin Lo .remove = scp_remove, 78663c13d61SErin Lo .driver = { 78763c13d61SErin Lo .name = "mtk-scp", 788cca21000SSouptick Joarder .of_match_table = mtk_scp_of_match, 78963c13d61SErin Lo }, 79063c13d61SErin Lo }; 79163c13d61SErin Lo 79263c13d61SErin Lo module_platform_driver(mtk_scp_driver); 79363c13d61SErin Lo 79463c13d61SErin Lo MODULE_LICENSE("GPL v2"); 79563c13d61SErin Lo MODULE_DESCRIPTION("MediaTek SCP control driver"); 796