diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-22 12:56:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-22 12:56:33 -0700 |
commit | 1553d96854b47953e41e7f66b2bdbc1c0d13a3e5 (patch) | |
tree | 7f6dc7da750e8e8c8f18ca3dd95eecf004033036 /drivers/remoteproc/mtk_scp.c | |
parent | 3fec0eaaf04adf5e23b2704f5490d5943fb8b0b1 (diff) | |
parent | 141bc97c1bfe31397b2a12e5676d0c2692c8e07e (diff) | |
download | linux-1553d96854b47953e41e7f66b2bdbc1c0d13a3e5.tar.bz2 |
Merge tag 'rproc-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc
Pull remoteproc updates from Bjorn Andersson:
"This introduces support for the Mediatek MT9182 SCP and controlling
the Cortex R5F processors found in TI K3 platforms. It clones the
longstanding debugfs interface for controlling crash handling to
sysfs. Lastly it solves a bug where after a warm reset of Qualcomm
platforms the modem would crash upon first boot"
* tag 'rproc-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc:
remoteproc/mediatek: Remove non-standard dsb()
remoteproc: Add recovery configuration to the sysfs interface
remoteproc: Add coredump as part of sysfs interface
remoteproc: Change default dump configuration to "disabled"
remoteproc: k3-r5: Add loading support for on-chip SRAM regions
remoteproc: k3-r5: Initialize TCM memories for ECC
remoteproc: k3-r5: Add a remoteproc driver for R5F subsystem
dt-bindings: remoteproc: Add bindings for R5F subsystem on TI K3 SoCs
remoteproc/mediatek: Add support for mt8192 SCP
remoteproc: Fixup coredump debugfs disable request
remoteproc: qcom_q6v5: Assign mpss region to Q6 before MBA boot
remoteproc/mediatek: fix null pointer dereference on null scp pointer
remoteproc: stm32: Fix pointer assignement
remoteproc: scp: add COMPILE_TEST dependency
Diffstat (limited to 'drivers/remoteproc/mtk_scp.c')
-rw-r--r-- | drivers/remoteproc/mtk_scp.c | 199 |
1 files changed, 165 insertions, 34 deletions
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index ac13e7b046a6..577cbd5d421e 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -124,9 +124,6 @@ static int scp_ipi_init(struct mtk_scp *scp) size_t send_offset = SCP_FW_END - sizeof(struct mtk_share_obj); size_t recv_offset = send_offset - sizeof(struct mtk_share_obj); - /* Disable SCP to host interrupt */ - writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); - /* shared buffer initialization */ scp->recv_buf = (struct mtk_share_obj __iomem *)(scp->sram_base + recv_offset); @@ -138,7 +135,7 @@ static int scp_ipi_init(struct mtk_scp *scp) return 0; } -static void scp_reset_assert(const struct mtk_scp *scp) +static void mt8183_scp_reset_assert(struct mtk_scp *scp) { u32 val; @@ -147,7 +144,7 @@ static void scp_reset_assert(const struct mtk_scp *scp) writel(val, scp->reg_base + MT8183_SW_RSTN); } -static void scp_reset_deassert(const struct mtk_scp *scp) +static void mt8183_scp_reset_deassert(struct mtk_scp *scp) { u32 val; @@ -156,17 +153,19 @@ static void scp_reset_deassert(const struct mtk_scp *scp) writel(val, scp->reg_base + MT8183_SW_RSTN); } -static irqreturn_t scp_irq_handler(int irq, void *priv) +static void mt8192_scp_reset_assert(struct mtk_scp *scp) { - struct mtk_scp *scp = priv; - u32 scp_to_host; - int ret; + writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); +} - ret = clk_prepare_enable(scp->clk); - if (ret) { - dev_err(scp->dev, "failed to enable clocks\n"); - return IRQ_NONE; - } +static void mt8192_scp_reset_deassert(struct mtk_scp *scp) +{ + writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_CLR); +} + +static void mt8183_scp_irq_handler(struct mtk_scp *scp) +{ + u32 scp_to_host; scp_to_host = readl(scp->reg_base + MT8183_SCP_TO_HOST); if (scp_to_host & MT8183_SCP_IPC_INT_BIT) @@ -177,6 +176,40 @@ static irqreturn_t scp_irq_handler(int irq, void *priv) /* SCP won't send another interrupt until we set SCP_TO_HOST to 0. */ writel(MT8183_SCP_IPC_INT_BIT | MT8183_SCP_WDT_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); +} + +static void mt8192_scp_irq_handler(struct mtk_scp *scp) +{ + u32 scp_to_host; + + scp_to_host = readl(scp->reg_base + MT8192_SCP2APMCU_IPC_SET); + + if (scp_to_host & MT8192_SCP_IPC_INT_BIT) + scp_ipi_handler(scp); + else + scp_wdt_handler(scp, scp_to_host); + + /* + * SCP won't send another interrupt until we clear + * MT8192_SCP2APMCU_IPC. + */ + writel(MT8192_SCP_IPC_INT_BIT, + scp->reg_base + MT8192_SCP2APMCU_IPC_CLR); +} + +static irqreturn_t scp_irq_handler(int irq, void *priv) +{ + struct mtk_scp *scp = priv; + int ret; + + ret = clk_prepare_enable(scp->clk); + if (ret) { + dev_err(scp->dev, "failed to enable clocks\n"); + return IRQ_NONE; + } + + scp->data->scp_irq_handler(scp); + clk_disable_unprepare(scp->clk); return IRQ_HANDLED; @@ -238,20 +271,10 @@ static int scp_elf_load_segments(struct rproc *rproc, const struct firmware *fw) return ret; } -static int scp_load(struct rproc *rproc, const struct firmware *fw) +static int mt8183_scp_before_load(struct mtk_scp *scp) { - const struct mtk_scp *scp = rproc->priv; - struct device *dev = scp->dev; - int ret; - - ret = clk_prepare_enable(scp->clk); - if (ret) { - dev_err(dev, "failed to enable clocks\n"); - return ret; - } - - /* Hold SCP in reset while loading FW. */ - scp_reset_assert(scp); + /* Clear SCP to host interrupt */ + writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); /* Reset clocks before loading FW */ writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL); @@ -272,6 +295,63 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw) scp->reg_base + MT8183_SCP_CACHE_CON); writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON); + return 0; +} + +static void mt8192_power_on_sram(void *addr) +{ + int i; + + for (i = 31; i >= 0; i--) + writel(GENMASK(i, 0), addr); + writel(0, addr); +} + +static void mt8192_power_off_sram(void *addr) +{ + int i; + + writel(0, addr); + for (i = 0; i < 32; i++) + writel(GENMASK(i, 0), addr); +} + +static int mt8192_scp_before_load(struct mtk_scp *scp) +{ + /* clear SPM interrupt, SCP2SPM_IPC_CLR */ + writel(0xff, scp->reg_base + MT8192_SCP2SPM_IPC_CLR); + + writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); + + /* enable SRAM clock */ + mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_0); + mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_1); + mt8192_power_on_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_2); + mt8192_power_on_sram(scp->reg_base + MT8192_L1TCM_SRAM_PDN); + mt8192_power_on_sram(scp->reg_base + MT8192_CPU0_SRAM_PD); + + return 0; +} + +static int scp_load(struct rproc *rproc, const struct firmware *fw) +{ + struct mtk_scp *scp = rproc->priv; + struct device *dev = scp->dev; + int ret; + + ret = clk_prepare_enable(scp->clk); + if (ret) { + dev_err(dev, "failed to enable clocks\n"); + return ret; + } + + /* Hold SCP in reset while loading FW. */ + scp->data->scp_reset_assert(scp); + + ret = scp->data->scp_before_load(scp); + if (ret < 0) + return ret; + ret = scp_elf_load_segments(rproc, fw); clk_disable_unprepare(scp->clk); @@ -293,7 +373,7 @@ static int scp_start(struct rproc *rproc) run->signaled = false; - scp_reset_deassert(scp); + scp->data->scp_reset_deassert(scp); ret = wait_event_interruptible_timeout( run->wq, @@ -309,13 +389,14 @@ static int scp_start(struct rproc *rproc) dev_err(dev, "wait SCP interrupted by a signal!\n"); goto stop; } + clk_disable_unprepare(scp->clk); dev_info(dev, "SCP is ready. FW version %s\n", run->fw_ver); return 0; stop: - scp_reset_assert(scp); + scp->data->scp_reset_assert(scp); clk_disable_unprepare(scp->clk); return ret; } @@ -329,7 +410,7 @@ static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len) offset = da; if (offset >= 0 && (offset + len) < scp->sram_size) return (void __force *)scp->sram_base + offset; - } else { + } else if (scp->dram_size) { offset = da - scp->dma_addr; if (offset >= 0 && (offset + len) < scp->dram_size) return (void __force *)scp->cpu_addr + offset; @@ -338,6 +419,25 @@ static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len) return NULL; } +static void mt8183_scp_stop(struct mtk_scp *scp) +{ + /* Disable SCP watchdog */ + writel(0, scp->reg_base + MT8183_WDT_CFG); +} + +static void mt8192_scp_stop(struct mtk_scp *scp) +{ + /* Disable SRAM clock */ + mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_0); + mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_1); + mt8192_power_off_sram(scp->reg_base + MT8192_L2TCM_SRAM_PD_2); + mt8192_power_off_sram(scp->reg_base + MT8192_L1TCM_SRAM_PDN); + mt8192_power_off_sram(scp->reg_base + MT8192_CPU0_SRAM_PD); + + /* Disable SCP watchdog */ + writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG); +} + static int scp_stop(struct rproc *rproc) { struct mtk_scp *scp = (struct mtk_scp *)rproc->priv; @@ -349,9 +449,8 @@ static int scp_stop(struct rproc *rproc) return ret; } - scp_reset_assert(scp); - /* Disable SCP watchdog */ - writel(0, scp->reg_base + MT8183_WDT_CFG); + scp->data->scp_reset_assert(scp); + scp->data->scp_stop(scp); clk_disable_unprepare(scp->clk); return 0; @@ -443,6 +542,13 @@ static int scp_map_memory_region(struct mtk_scp *scp) int ret; ret = of_reserved_mem_device_init(scp->dev); + + /* reserved memory is optional. */ + if (ret == -ENODEV) { + dev_info(scp->dev, "skipping reserved memory initialization."); + return 0; + } + if (ret) { dev_err(scp->dev, "failed to assign memory-region: %d\n", ret); return -ENOMEM; @@ -460,6 +566,9 @@ static int scp_map_memory_region(struct mtk_scp *scp) static void scp_unmap_memory_region(struct mtk_scp *scp) { + if (scp->dram_size == 0) + return; + dma_free_coherent(scp->dev, scp->dram_size, scp->cpu_addr, scp->dma_addr); of_reserved_mem_device_release(scp->dev); @@ -536,6 +645,7 @@ static int scp_probe(struct platform_device *pdev) scp = (struct mtk_scp *)rproc->priv; scp->rproc = rproc; scp->dev = dev; + scp->data = of_device_get_match_data(dev); platform_set_drvdata(pdev, scp); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); @@ -642,8 +752,29 @@ static int scp_remove(struct platform_device *pdev) return 0; } +static const struct mtk_scp_of_data mt8183_of_data = { + .scp_before_load = mt8183_scp_before_load, + .scp_irq_handler = mt8183_scp_irq_handler, + .scp_reset_assert = mt8183_scp_reset_assert, + .scp_reset_deassert = mt8183_scp_reset_deassert, + .scp_stop = mt8183_scp_stop, + .host_to_scp_reg = MT8183_HOST_TO_SCP, + .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT, +}; + +static const struct mtk_scp_of_data mt8192_of_data = { + .scp_before_load = mt8192_scp_before_load, + .scp_irq_handler = mt8192_scp_irq_handler, + .scp_reset_assert = mt8192_scp_reset_assert, + .scp_reset_deassert = mt8192_scp_reset_deassert, + .scp_stop = mt8192_scp_stop, + .host_to_scp_reg = MT8192_GIPC_IN_SET, + .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, +}; + static const struct of_device_id mtk_scp_of_match[] = { - { .compatible = "mediatek,mt8183-scp"}, + { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, + { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, {}, }; MODULE_DEVICE_TABLE(of, mtk_scp_of_match); |