Some Mediatek's SoC have an AI Processing Unit.
This adds support of the one available in the mt8183
(aswell some derivative SoC).
This v4 rework again the memory management.
Now, vdev buffer and vring buffer are declared in device tree with a fixed
physical address.
Using a new property named "memory-region-da", the driver can map the vdev and
vring buffers and make them available to the APU.
The physical address must be fixed so the firmware can convert the physical
address into APU device address.
Using fixed address is not flexible but this is acceptable since the buffer
addresses and size are not expected to be changed without a goog reason.
Changes in v4:
- Update the way to allocate and map the vdev and vring buffers
- Simplfy the code
- Add support of a second SoC (mt8365)
- fix the dt bindings error detected by the bot
- still use the threaded irq. calling rproc_vq_interrupt from irq causes
a scheduling while atomic isssue
Changes in v3:
- Remove IOMMU hack. Instead, manage the IOMMU directly from the driver
- Update the device tree bindings: only use reserved memory for virtio.
All the other memory allocation will be done using DMA API.
This sould simplify the memory management.
- Add more comments
Changes in v2:
- Drop the workarounds needed to load bad firmwares
- There are many name for the APU (most common one is VPU).
Rename many functions and dts nodes to be more consistent.
- Use the bulk clock API, and enable / disable clock at a better place
- add few comments explaining how to start the APU
- update the way to use pinctl for JTAG
- fix some minors issues
- fix device tree bindings
Alexandre Bailon (5):
dt bindings: remoteproc: Add bindings for the MT8183 APU
dt-bindings: remoteproc: Add bindings for the MT8365 APU
remoteproc: Add a remoteproc driver for the MT8183's APU
remoteproc: mtk_apu: Add support of JTAG
ARM64: mt8183: Add support of APU to mt8183
Julien STEPHAN (2):
remoteproc: mtk_apu: Use match_data
remoteproc: mtk-apu: Add support of MT8365
.../bindings/remoteproc/mtk,apu.yaml | 155 ++++
.../boot/dts/mediatek/mt8183-pumpkin.dts | 50 ++
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 40 ++
drivers/remoteproc/Kconfig | 19 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/mtk_apu.c | 671 ++++++++++++++++++
6 files changed, 936 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
create mode 100644 drivers/remoteproc/mtk_apu.c
--
2.34.1
This updates the Mediatek APU bindings to support the MT8365.
Signed-off-by: Alexandre Bailon <[email protected]>
---
.../bindings/remoteproc/mtk,apu.yaml | 45 ++++++++++++++++---
1 file changed, 39 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
index b640aa96d678..388352ccb2b5 100644
--- a/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
@@ -16,7 +16,9 @@ maintainers:
properties:
compatible:
- const: mediatek,mt8183-apu
+ enum:
+ - mediatek,mt8183-apu
+ - mediatek,mt8365-apu
reg:
maxItems: 1
@@ -26,13 +28,11 @@ properties:
clocks:
minItems: 3
- maxItems: 3
+ maxItems: 8
clock-names:
- items:
- - const: axi
- - const: ipu
- - const: jtag
+ minItems: 3
+ maxItems: 8
iommus:
maxItems: 3
@@ -69,6 +69,39 @@ required:
additionalProperties: false
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - mediatek,mt8183-apu
+ then:
+ properties:
+ clock-names:
+ items:
+ - const: axi
+ - const: ipu
+ - const: jtag
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - mediatek,mt8365-apu
+ then:
+ properties:
+ clock-names:
+ items:
+ - const: if_ck
+ - const: edma
+ - const: ahb
+ - const: axi
+ - const: ipu
+ - const: jtag
+ - const: smi_cam
+ - const: ifr_apu_axi
+
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
--
2.34.1
From: Julien STEPHAN <[email protected]>
This commits prepare the driver to be more generic in order to support
multiple platform using the compatible property.
To do that, put some register values and the clocks names inside
private data.
Signed-off-by: Julien STEPHAN <[email protected]>
Signed-off-by: Alexandre Bailon <[email protected]>
---
drivers/remoteproc/mtk_apu.c | 35 ++++++++++++++++++++++++++++-------
1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
index 3905eb5b7174..deec51b86ba5 100644
--- a/drivers/remoteproc/mtk_apu.c
+++ b/drivers/remoteproc/mtk_apu.c
@@ -58,12 +58,20 @@
#define APU_RESET_DELAY (27)
+struct mtk_apu_conf {
+ u32 core_default0;
+ u32 core_default1;
+ u32 num_clks;
+ const char * const *clk_names;
+};
+
struct mtk_apu_rproc {
struct device *dev;
void __iomem *base;
int irq;
unsigned int num_clks;
struct clk_bulk_data *clks;
+ struct mtk_apu_conf *conf;
struct iommu_domain *domain;
struct list_head mappings;
@@ -81,6 +89,13 @@ static const char * const mt8183_clk_names[] = {
"jtag"
};
+static const struct mtk_apu_conf mt8183_conf = {
+ .core_default0 = (0x10 << 23) | (0x10 << 18),
+ .core_default1 = (0x10 << 0) | (0x10 << 5),
+ .num_clks = ARRAY_SIZE(mt8183_clk_names),
+ .clk_names = mt8183_clk_names
+};
+
static int mtk_apu_iommu_map(struct rproc *rproc, struct rproc_mem_entry *entry)
{
struct mtk_apu_rproc *apu_rproc = rproc->priv;
@@ -289,10 +304,9 @@ static int mtk_apu_rproc_start(struct rproc *rproc)
writel(core_ctrl, apu_rproc->base + CORE_CTRL);
/* Configure memory accesses to go through the IOMMU */
- writel(CORE_DEFAULT0_AWUSER_USE_IOMMU | CORE_DEFAULT0_ARUSER_USE_IOMMU |
- CORE_DEFAULT0_QOS_SWAP_1, apu_rproc->base + CORE_DEFAULT0);
- writel(CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU |
- CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU,
+ writel(apu_rproc->conf->core_default0 | CORE_DEFAULT0_QOS_SWAP_1,
+ apu_rproc->base + CORE_DEFAULT0);
+ writel(apu_rproc->conf->core_default1,
apu_rproc->base + CORE_DEFAULT1);
/* Release the APU */
@@ -565,11 +579,18 @@ static int mtk_apu_rproc_probe(struct platform_device *pdev)
goto free_rproc;
}
- apu_rproc->num_clks = ARRAY_SIZE(mt8183_clk_names);
+
+ apu_rproc->conf = (struct mtk_apu_conf *)device_get_match_data(dev);
+ if (!apu_rproc->conf) {
+ ret = -ENODEV;
+ goto free_rproc;
+ }
+
+ apu_rproc->num_clks = apu_rproc->conf->num_clks;
apu_rproc->clks = devm_kcalloc(dev, apu_rproc->num_clks,
sizeof(*apu_rproc->clks), GFP_KERNEL);
for (i = 0; i < apu_rproc->num_clks; ++i)
- apu_rproc->clks[i].id = mt8183_clk_names[i];
+ apu_rproc->clks[i].id = apu_rproc->conf->clk_names[i];
ret = devm_clk_bulk_get(dev, apu_rproc->num_clks, apu_rproc->clks);
if (ret) {
@@ -611,7 +632,7 @@ static int mtk_apu_rproc_remove(struct platform_device *pdev)
}
static const struct of_device_id mtk_apu_rproc_of_match[] = {
- { .compatible = "mediatek,mt8183-apu", },
+ { .compatible = "mediatek,mt8183-apu", .data = &mt8183_conf },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mtk_apu_rproc_of_match);
--
2.34.1
This adds a driver to control the APU present in the MT8183.
This loads the firmware and start the DSP.
Signed-off-by: Alexandre Bailon <[email protected]>
---
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/mtk_apu.c | 486 +++++++++++++++++++++++++++++++++++
3 files changed, 497 insertions(+)
create mode 100644 drivers/remoteproc/mtk_apu.c
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 341156e2a29b..959d24e9492c 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -64,6 +64,16 @@ config MTK_SCP
It's safe to say N here.
+config MTK_APU
+ tristate "Mediatek APU remoteproc support"
+ depends on ARCH_MEDIATEK
+ depends on MTK_IOMMU
+ help
+ Say y to support the Mediatek's AI Processing Unit (APU) via
+ the remote processor framework.
+
+ It's safe to say N here.
+
config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 0ac256b6c977..0ab4461c33af 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
obj-$(CONFIG_IMX_DSP_REMOTEPROC) += imx_dsp_rproc.o
obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o
obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o
+obj-$(CONFIG_MTK_APU) += mtk_apu.o
obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
new file mode 100644
index 000000000000..867b4682b507
--- /dev/null
+++ b/drivers/remoteproc/mtk_apu.c
@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 BayLibre SAS
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/iommu.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+#include <linux/string.h>
+
+#include "remoteproc_internal.h"
+
+#define SW_RST (0x0000000C)
+#define SW_RST_OCD_HALT_ON_RST BIT(12)
+#define SW_RST_IPU_D_RST BIT(8)
+#define SW_RST_IPU_B_RST BIT(4)
+#define CORE_CTRL (0x00000110)
+#define CORE_CTRL_PDEBUG_ENABLE BIT(31)
+#define CORE_CTRL_SRAM_64K_iMEM (0x00 << 27)
+#define CORE_CTRL_SRAM_96K_iMEM (0x01 << 27)
+#define CORE_CTRL_SRAM_128K_iMEM (0x02 << 27)
+#define CORE_CTRL_SRAM_192K_iMEM (0x03 << 27)
+#define CORE_CTRL_SRAM_256K_iMEM (0x04 << 27)
+#define CORE_CTRL_PBCLK_ENABLE BIT(26)
+#define CORE_CTRL_RUN_STALL BIT(23)
+#define CORE_CTRL_STATE_VECTOR_SELECT BIT(19)
+#define CORE_CTRL_PIF_GATED BIT(17)
+#define CORE_CTRL_NMI BIT(0)
+#define CORE_XTENSA_INT (0x00000114)
+#define CORE_CTL_XTENSA_INT (0x00000118)
+#define CORE_DEFAULT0 (0x0000013C)
+#define CORE_DEFAULT0_QOS_SWAP_0 (0x00 << 28)
+#define CORE_DEFAULT0_QOS_SWAP_1 (0x01 << 28)
+#define CORE_DEFAULT0_QOS_SWAP_2 (0x02 << 28)
+#define CORE_DEFAULT0_QOS_SWAP_3 (0x03 << 28)
+#define CORE_DEFAULT0_ARUSER_USE_IOMMU (0x10 << 23)
+#define CORE_DEFAULT0_AWUSER_USE_IOMMU (0x10 << 18)
+#define CORE_DEFAULT1 (0x00000140)
+#define CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU (0x10 << 0)
+#define CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU (0x10 << 5)
+#define CORE_XTENSA_ALTRESETVEC (0x000001F8)
+
+#define VDEV_MEM_COUNT (3)
+
+#define APU_RESET_DELAY (27)
+
+struct mtk_apu_rproc {
+ struct device *dev;
+ void __iomem *base;
+ int irq;
+ unsigned int num_clks;
+ struct clk_bulk_data *clks;
+ struct iommu_domain *domain;
+ struct list_head mappings;
+};
+
+static const char * const mt8183_clk_names[] = {
+ "ipu",
+ "axi",
+ "jtag"
+};
+
+static int mtk_apu_iommu_map(struct rproc *rproc, struct rproc_mem_entry *entry)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+ struct device *dev = rproc->dev.parent;
+ struct rproc_mem_entry *mapping;
+ int ret;
+ u64 pa;
+
+ /* vdev buffer and vring are already mapped */
+ if (strstr(entry->name, "vdev"))
+ return 0;
+
+ mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+ if (!mapping)
+ return -ENOMEM;
+
+ if (!entry->va)
+ pa = entry->dma;
+ else
+ pa = rproc_va_to_pa(entry->va);
+
+ ret = iommu_map(apu_rproc->domain, entry->da, pa, entry->len, entry->flags);
+ if (ret) {
+ dev_err(dev, "iommu_map failed: %d\n", ret);
+ goto free_mapping;
+ }
+
+ mapping->da = entry->da;
+ mapping->len = entry->len;
+ list_add_tail(&mapping->node, &apu_rproc->mappings);
+
+ return 0;
+
+free_mapping:
+ kfree(mapping);
+
+ return ret;
+}
+
+static void mtk_apu_iommu_unmap_all(struct rproc *rproc)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+ struct device *dev = rproc->dev.parent;
+ struct rproc_mem_entry *entry, *tmp;
+
+ /* clean up iommu mapping entries */
+ list_for_each_entry_safe(entry, tmp, &apu_rproc->mappings, node) {
+ size_t unmapped;
+
+ unmapped = iommu_unmap(apu_rproc->domain, entry->da, entry->len);
+ if (unmapped != entry->len) {
+ /* nothing much to do besides complaining */
+ dev_err(dev, "failed to unmap %zx/%zu\n", entry->len,
+ unmapped);
+ }
+
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
+static int mtk_apu_rproc_alloc_carveout(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ int flags = IOMMU_READ | IOMMU_READ | IOMMU_NOEXEC;
+ struct device *dev = rproc->dev.parent;
+ int ret;
+
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+
+ mem->va = memremap(mem->dma, mem->len, MEMREMAP_WC);
+ if (IS_ERR_OR_NULL(mem->va)) {
+ dev_err(dev, "Unable to map memory region: %pa+%zu\n",
+ &mem->dma, mem->len);
+ return PTR_ERR(mem->va);
+ }
+
+ ret = iommu_map(domain, mem->da, mem->dma, mem->len, flags);
+ if (ret)
+ memunmap(mem->va);
+
+ return 0;
+}
+
+static int mtk_apu_rproc_release_carveout(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+ struct device *dev = apu_rproc->dev;
+ struct iommu_domain *domain;
+ size_t unmapped;
+
+ domain = iommu_get_domain_for_dev(dev);
+ unmapped = iommu_unmap(domain, mem->da, mem->len);
+ if (unmapped != mem->len) {
+ /* nothing much to do besides complaining */
+ dev_err(dev, "failed to unmap %zx/%zu\n", mem->len, unmapped);
+ }
+ memunmap(mem->va);
+
+ return 0;
+}
+
+static int mtk_apu_rproc_vdev_mem_init(struct rproc *rproc)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+ struct device *dev = apu_rproc->dev;
+ struct device_node *np = dev->of_node;
+ struct reserved_mem *rmem;
+ struct rproc_mem_entry *mem;
+ u32 da[VDEV_MEM_COUNT];
+ int ret;
+ int i;
+
+ ret = of_property_read_u32_array(np, "memory-region-da", da, VDEV_MEM_COUNT);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < VDEV_MEM_COUNT; i++) {
+ struct device_node *target;
+ char *name;
+
+ target = of_parse_phandle(np, "memory-region", i);
+ if (!target)
+ return -EINVAL;
+
+ rmem = of_reserved_mem_lookup(target);
+ of_node_put(target);
+
+ if (!rmem)
+ return -ENOMEM;
+
+ ret = strcspn(rmem->name, "@");
+ if (!ret)
+ return -EINVAL;
+
+ name = kstrndup(rmem->name, ret, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ mem = rproc_mem_entry_init(dev, NULL, rmem->base, rmem->size,
+ da[i],
+ mtk_apu_rproc_alloc_carveout,
+ mtk_apu_rproc_release_carveout,
+ name);
+ kfree(name);
+ if (!mem)
+ return -ENOMEM;
+
+ rproc_add_carveout(rproc, mem);
+ }
+
+ return 0;
+}
+
+static int mtk_apu_rproc_prepare(struct rproc *rproc)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+ int ret;
+
+ ret = clk_bulk_prepare_enable(apu_rproc->num_clks, apu_rproc->clks);
+ if (ret)
+ dev_err(apu_rproc->dev, "Failed to enable clocks\n");
+
+ ret = mtk_apu_rproc_vdev_mem_init(rproc);
+ if (ret) {
+ dev_err(apu_rproc->dev, "Failed to init vdev memory\n");
+ clk_bulk_disable_unprepare(apu_rproc->num_clks, apu_rproc->clks);
+
+ }
+
+ return ret;
+}
+
+static int mtk_apu_rproc_unprepare(struct rproc *rproc)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+
+ clk_bulk_disable_unprepare(apu_rproc->num_clks, apu_rproc->clks);
+
+ return 0;
+}
+
+static int mtk_apu_rproc_start(struct rproc *rproc)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+ u32 core_ctrl;
+
+ /* Set reset vector of APU firmware boot address */
+ writel(rproc->bootaddr, apu_rproc->base + CORE_XTENSA_ALTRESETVEC);
+
+ /* Turn on the clocks and stall the APU */
+ core_ctrl = readl(apu_rproc->base + CORE_CTRL);
+ core_ctrl |= CORE_CTRL_PDEBUG_ENABLE | CORE_CTRL_PBCLK_ENABLE |
+ CORE_CTRL_STATE_VECTOR_SELECT | CORE_CTRL_RUN_STALL |
+ CORE_CTRL_PIF_GATED;
+ writel(core_ctrl, apu_rproc->base + CORE_CTRL);
+
+ /* Reset the APU: this requires 27 ns to be effective on any platform */
+ writel(SW_RST_OCD_HALT_ON_RST | SW_RST_IPU_B_RST | SW_RST_IPU_D_RST,
+ apu_rproc->base + SW_RST);
+ ndelay(APU_RESET_DELAY);
+ writel(0, apu_rproc->base + SW_RST);
+
+ core_ctrl &= ~CORE_CTRL_PIF_GATED;
+ writel(core_ctrl, apu_rproc->base + CORE_CTRL);
+
+ /* Configure memory accesses to go through the IOMMU */
+ writel(CORE_DEFAULT0_AWUSER_USE_IOMMU | CORE_DEFAULT0_ARUSER_USE_IOMMU |
+ CORE_DEFAULT0_QOS_SWAP_1, apu_rproc->base + CORE_DEFAULT0);
+ writel(CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU |
+ CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU,
+ apu_rproc->base + CORE_DEFAULT1);
+
+ /* Release the APU */
+ core_ctrl &= ~CORE_CTRL_RUN_STALL;
+ writel(core_ctrl, apu_rproc->base + CORE_CTRL);
+
+ return 0;
+}
+
+static int mtk_apu_rproc_stop(struct rproc *rproc)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+ u32 core_ctrl;
+
+ core_ctrl = readl(apu_rproc->base + CORE_CTRL);
+ writel(core_ctrl | CORE_CTRL_RUN_STALL, apu_rproc->base + CORE_CTRL);
+
+ mtk_apu_iommu_unmap_all(rproc);
+
+ return 0;
+}
+
+static void mtk_apu_rproc_kick(struct rproc *rproc, int vqid)
+{
+ struct mtk_apu_rproc *apu_rproc = rproc->priv;
+
+ writel(1 << vqid, apu_rproc->base + CORE_CTL_XTENSA_INT);
+}
+
+static int mtk_apu_load(struct rproc *rproc, const struct firmware *fw)
+
+{
+ struct rproc_mem_entry *entry, *tmp;
+ int ret;
+
+ ret = rproc_elf_load_segments(rproc, fw);
+ if (ret)
+ return ret;
+
+ list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
+ ret = mtk_apu_iommu_map(rproc, entry);
+ if (ret)
+ goto err_unmap_all;
+ }
+
+ return 0;
+
+err_unmap_all:
+ mtk_apu_iommu_unmap_all(rproc);
+
+ return ret;
+}
+
+static const struct rproc_ops mtk_apu_rproc_ops = {
+ .prepare = mtk_apu_rproc_prepare,
+ .unprepare = mtk_apu_rproc_unprepare,
+ .start = mtk_apu_rproc_start,
+ .stop = mtk_apu_rproc_stop,
+ .kick = mtk_apu_rproc_kick,
+ .load = mtk_apu_load,
+ .parse_fw = rproc_elf_load_rsc_table,
+ .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
+ .sanity_check = rproc_elf_sanity_check,
+ .get_boot_addr = rproc_elf_get_boot_addr,
+};
+
+static irqreturn_t mtk_apu_rproc_callback(int irq, void *data)
+{
+ struct rproc *rproc = data;
+ struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
+
+ writel(1, apu_rproc->base + CORE_XTENSA_INT);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int mtk_apu_rproc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_apu_rproc *apu_rproc;
+ struct rproc *rproc;
+ struct resource *res;
+ int ret;
+ int i;
+
+ ret = of_property_count_elems_of_size(dev->of_node, "memory-region",
+ sizeof(phandle));
+ if (ret != VDEV_MEM_COUNT)
+ return -EINVAL;
+
+ ret = of_property_count_elems_of_size(dev->of_node, "memory-region-da",
+ sizeof(u32));
+ if (ret != VDEV_MEM_COUNT)
+ return -EINVAL;
+
+ rproc = rproc_alloc(dev, dev_name(dev), &mtk_apu_rproc_ops, NULL,
+ sizeof(*apu_rproc));
+ if (!rproc)
+ return -ENOMEM;
+
+ rproc->recovery_disabled = true;
+ rproc->has_iommu = false;
+ rproc->auto_boot = false;
+
+ apu_rproc = rproc->priv;
+ apu_rproc->dev = dev;
+ INIT_LIST_HEAD(&apu_rproc->mappings);
+
+ platform_set_drvdata(pdev, rproc);
+
+ apu_rproc->domain = iommu_get_domain_for_dev(dev);
+ if (!apu_rproc->domain) {
+ ret = -ENODEV;
+ goto free_rproc;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ apu_rproc->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(apu_rproc->base)) {
+ dev_err(dev, "Failed to map mmio\n");
+ ret = PTR_ERR(apu_rproc->base);
+ goto free_rproc;
+ }
+
+ apu_rproc->irq = platform_get_irq(pdev, 0);
+ if (apu_rproc->irq < 0) {
+ ret = apu_rproc->irq;
+ goto free_rproc;
+ }
+
+ apu_rproc->domain = iommu_get_domain_for_dev(dev);
+ if (!apu_rproc->domain) {
+ ret = -ENODEV;
+ goto free_rproc;
+ }
+
+ ret = devm_request_threaded_irq(dev, apu_rproc->irq,
+ mtk_apu_rproc_callback, handle_event,
+ IRQF_SHARED | IRQF_ONESHOT,
+ NULL, rproc);
+ if (ret) {
+ dev_err(dev, "devm_request_threaded_irq error: %d\n", ret);
+ goto free_rproc;
+ }
+
+ apu_rproc->num_clks = ARRAY_SIZE(mt8183_clk_names);
+ apu_rproc->clks = devm_kcalloc(dev, apu_rproc->num_clks,
+ sizeof(*apu_rproc->clks), GFP_KERNEL);
+ for (i = 0; i < apu_rproc->num_clks; ++i)
+ apu_rproc->clks[i].id = mt8183_clk_names[i];
+
+ ret = devm_clk_bulk_get(dev, apu_rproc->num_clks, apu_rproc->clks);
+ if (ret) {
+ dev_err(dev, "Failed to get clocks\n");
+ goto free_rproc;
+ }
+
+ ret = rproc_add(rproc);
+ if (ret) {
+ dev_err(dev, "rproc_add failed: %d\n", ret);
+ goto free_rproc;
+ }
+
+ return 0;
+
+free_rproc:
+ rproc_free(rproc);
+
+ return ret;
+}
+
+static int mtk_apu_rproc_remove(struct platform_device *pdev)
+{
+ struct rproc *rproc = platform_get_drvdata(pdev);
+ struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
+ struct device *dev = &pdev->dev;
+
+ disable_irq(apu_rproc->irq);
+
+ rproc_del(rproc);
+ of_reserved_mem_device_release(dev);
+ rproc_free(rproc);
+
+ return 0;
+}
+
+static const struct of_device_id mtk_apu_rproc_of_match[] = {
+ { .compatible = "mediatek,mt8183-apu", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_apu_rproc_of_match);
+
+static struct platform_driver mtk_apu_rproc_driver = {
+ .probe = mtk_apu_rproc_probe,
+ .remove = mtk_apu_rproc_remove,
+ .driver = {
+ .name = "mtk_apu-rproc",
+ .of_match_table = of_match_ptr(mtk_apu_rproc_of_match),
+ },
+};
+module_platform_driver(mtk_apu_rproc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alexandre Bailon");
+MODULE_DESCRIPTION("MTK APU Remote Processor control driver");
--
2.34.1
This adds the support of APU to mt8183.
Signed-off-by: Alexandre Bailon <[email protected]>
---
.../boot/dts/mediatek/mt8183-pumpkin.dts | 50 +++++++++++++++++++
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 40 +++++++++++++++
2 files changed, 90 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts
index ee912825cfc6..155c89c998d3 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts
@@ -37,6 +37,42 @@ scp_mem_reserved: scp_mem_region@50000000 {
reg = <0 0x50000000 0 0x2900000>;
no-map;
};
+
+ vdev0buffer: vdev0buffer@52900000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x52900000 0 0x4000>;
+ no-map;
+ };
+
+ vdev0vring0: vdev0vring0@52904000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x52904000 0 0x2000>;
+ no-map;
+ };
+
+ vdev0vring1: vdev0vring1@52906000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x52906000 0 0x2000>;
+ no-map;
+ };
+
+ vdev1buffer: vdev1buffer@52908000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x52908000 0 0x4000>;
+ no-map;
+ };
+
+ vdev1vring0: vdev1vring0@5290C000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x5290C000 0 0x2000>;
+ no-map;
+ };
+
+ vdev1vring1: vdev1vring1@5290E000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x5290E000 0 0x2000>;
+ no-map;
+ };
};
leds {
@@ -381,3 +417,17 @@ &scp {
&dsi0 {
status = "disabled";
};
+
+&apu0 {
+ memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>;
+ memory-region-names = "vdev0buffer", "vdev0vring0", "vdev0vring1";
+ memory-region-da = <0x6fff8000>, <0x6fffc000>, <0x6fffe000>;
+ status = "okay";
+};
+
+&apu1 {
+ memory-region = <&vdev1buffer>, <&vdev1vring0>, <&vdev1vring1>;
+ memory-region-names = "vdev1buffer", "vdev1vring0", "vdev1vring1";
+ memory-region-da = <0x6fff0000>, <0x6fff4000>, <0x6fff6000>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index ba4584faca5a..cb02f57e000d 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -1542,12 +1542,52 @@ ipu_adl: syscon@19010000 {
#clock-cells = <1>;
};
+ apu0: apu@0x19100000 {
+ compatible = "mediatek,mt8183-apu";
+ reg = <0 0x19180000 0 0x14000>;
+ interrupts = <GIC_SPI 292 IRQ_TYPE_LEVEL_LOW>;
+
+ iommus = <&iommu M4U_PORT_IMG_IPUO>,
+ <&iommu M4U_PORT_IMG_IPU3O>,
+ <&iommu M4U_PORT_IMG_IPUI>;
+
+ clocks = <&ipu_core0 CLK_IPU_CORE0_AXI>,
+ <&ipu_core0 CLK_IPU_CORE0_IPU>,
+ <&ipu_core0 CLK_IPU_CORE0_JTAG>;
+
+ clock-names = "axi", "ipu", "jtag";
+
+ power-domains = <&spm MT8183_POWER_DOMAIN_VPU_CORE0>;
+
+ status = "disabled";
+ };
+
ipu_core0: syscon@19180000 {
compatible = "mediatek,mt8183-ipu_core0", "syscon";
reg = <0 0x19180000 0 0x1000>;
#clock-cells = <1>;
};
+ apu1: apu@19200000 {
+ compatible = "mediatek,mt8183-apu";
+ reg = <0 0x19280000 0 0x14000>;
+ interrupts = <GIC_SPI 293 IRQ_TYPE_LEVEL_LOW>;
+
+ iommus = <&iommu M4U_PORT_CAM_IPUO>,
+ <&iommu M4U_PORT_CAM_IPU2O>,
+ <&iommu M4U_PORT_CAM_IPU3O>;
+
+ clocks = <&ipu_core0 CLK_IPU_CORE1_AXI>,
+ <&ipu_core0 CLK_IPU_CORE1_IPU>,
+ <&ipu_core0 CLK_IPU_CORE1_JTAG>;
+
+ clock-names = "axi", "ipu", "jtag";
+
+ power-domains = <&spm MT8183_POWER_DOMAIN_VPU_CORE1>;
+
+ status = "disabled";
+ };
+
ipu_core1: syscon@19280000 {
compatible = "mediatek,mt8183-ipu_core1", "syscon";
reg = <0 0x19280000 0 0x1000>;
--
2.34.1
This adds dt bindings for the APU present in the MT8183.
Signed-off-by: Alexandre Bailon <[email protected]>
---
.../bindings/remoteproc/mtk,apu.yaml | 122 ++++++++++++++++++
1 file changed, 122 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
new file mode 100644
index 000000000000..b640aa96d678
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
@@ -0,0 +1,122 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+
+---
+$id: "http://devicetree.org/schemas/remoteproc/mtk,apu.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Mediatek AI Processor Unit (APU)
+
+description:
+ This document defines the binding for the APU, a co-processor that could
+ offload the CPU for machine learning and neural network.
+
+maintainers:
+ - Alexandre Bailon <[email protected]>
+
+properties:
+ compatible:
+ const: mediatek,mt8183-apu
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 3
+ maxItems: 3
+
+ clock-names:
+ items:
+ - const: axi
+ - const: ipu
+ - const: jtag
+
+ iommus:
+ maxItems: 3
+
+ memory-region:
+ maxItems: 3
+
+ memory-region-da:
+ description:
+ Array of APU device address. This is used to map the APU device address
+ to a physical address.
+ maxItems: 3
+
+ power-domains:
+ maxItems: 1
+
+ pinctrl:
+ description: pinctrl handles, required to configure pins for JTAG.
+
+ pinctrl-names:
+ items:
+ - const: jtag
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - iommus
+ - memory-region
+ - memory-region-da
+ - power-domains
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/mt8183-clk.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/memory/mt8183-larb-port.h>
+ #include <dt-bindings/power/mt8183-power.h>
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ vdev0buffer: vdev0buffer@52900000 {
+ compatible = "shared-dma-pool";
+ reg = <0x52900000 0x4000>;
+ no-map;
+ };
+
+ vdev0vring0: vdev0vring0@52904000 {
+ compatible = "shared-dma-pool";
+ reg = <0x52904000 0x2000>;
+ no-map;
+ };
+
+ vdev0vring1: vdev0vring1@52906000 {
+ compatible = "shared-dma-pool";
+ reg = <0x52906000 0x2000>;
+ no-map;
+ };
+ };
+
+ apu0: apu@19100000 {
+ compatible = "mediatek,mt8183-apu";
+ reg = <0x19180000 0x14000>;
+ interrupts = <GIC_SPI 292 IRQ_TYPE_LEVEL_LOW>;
+
+ iommus = <&iommu M4U_PORT_IMG_IPUO>,
+ <&iommu M4U_PORT_IMG_IPU3O>,
+ <&iommu M4U_PORT_IMG_IPUI>;
+
+ clocks = <&ipu_core0 CLK_IPU_CORE0_AXI>,
+ <&ipu_core0 CLK_IPU_CORE0_IPU>,
+ <&ipu_core0 CLK_IPU_CORE0_JTAG>;
+
+ clock-names = "axi", "ipu", "jtag";
+
+ power-domains = <&scpsys MT8183_POWER_DOMAIN_VPU_CORE0>;
+ memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>;
+ memory-region-da = <0x6fff8000>, <0x6fffc000>, <0x6fffe000>;
+ };
+...
--
2.34.1
The DSP could be debugged using JTAG.
The support of JTAG could enabled at build time and it could be enabled
using debugfs.
Signed-off-by: Alexandre Bailon <[email protected]>
---
drivers/remoteproc/Kconfig | 9 +++
drivers/remoteproc/mtk_apu.c | 147 ++++++++++++++++++++++++++++++++++-
2 files changed, 155 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 959d24e9492c..28140cf04d8a 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -74,6 +74,15 @@ config MTK_APU
It's safe to say N here.
+config MTK_APU_JTAG
+ bool "Enable support of JTAG"
+ depends on MTK_APU
+ help
+ Say y to enable support of JTAG.
+ By default, JTAG will remain disabled until it is enabled using
+ debugfs: remoteproc/remoteproc0/jtag. Write 1 to enable it and
+ 0 to disable it.
+
config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX
diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
index 867b4682b507..3905eb5b7174 100644
--- a/drivers/remoteproc/mtk_apu.c
+++ b/drivers/remoteproc/mtk_apu.c
@@ -5,12 +5,14 @@
#include <linux/bitops.h>
#include <linux/clk.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/iommu.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of_reserved_mem.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
#include <linux/string.h>
@@ -45,6 +47,11 @@
#define CORE_DEFAULT1 (0x00000140)
#define CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU (0x10 << 0)
#define CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU (0x10 << 5)
+#define CORE_DEFAULT2 (0x00000144)
+#define CORE_DEFAULT2_DBG_EN BIT(3)
+#define CORE_DEFAULT2_NIDEN BIT(2)
+#define CORE_DEFAULT2_SPNIDEN BIT(1)
+#define CORE_DEFAULT2_SPIDEN BIT(0)
#define CORE_XTENSA_ALTRESETVEC (0x000001F8)
#define VDEV_MEM_COUNT (3)
@@ -59,6 +66,13 @@ struct mtk_apu_rproc {
struct clk_bulk_data *clks;
struct iommu_domain *domain;
struct list_head mappings;
+
+#ifdef CONFIG_MTK_APU_JTAG
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinctrl_jtag;
+ bool jtag_enabled;
+ struct mutex jtag_mutex;
+#endif
};
static const char * const mt8183_clk_names[] = {
@@ -355,6 +369,133 @@ static irqreturn_t mtk_apu_rproc_callback(int irq, void *data)
return IRQ_WAKE_THREAD;
}
+#ifdef CONFIG_MTK_APU_JTAG
+
+static int apu_enable_jtag(struct mtk_apu_rproc *apu_rproc)
+{
+ int ret = 0;
+
+ mutex_lock(&apu_rproc->jtag_mutex);
+ if (apu_rproc->jtag_enabled)
+ goto err_mutex_unlock;
+
+ writel(CORE_DEFAULT2_SPNIDEN | CORE_DEFAULT2_SPIDEN |
+ CORE_DEFAULT2_NIDEN | CORE_DEFAULT2_DBG_EN,
+ apu_rproc->base + CORE_DEFAULT2);
+
+ apu_rproc->jtag_enabled = 1;
+
+err_mutex_unlock:
+ mutex_unlock(&apu_rproc->jtag_mutex);
+
+ return ret;
+}
+
+static int apu_disable_jtag(struct mtk_apu_rproc *apu_rproc)
+{
+ int ret = 0;
+
+ mutex_lock(&apu_rproc->jtag_mutex);
+ if (!apu_rproc->jtag_enabled)
+ goto err_mutex_unlock;
+
+ writel(0, apu_rproc->base + CORE_DEFAULT2);
+
+ apu_rproc->jtag_enabled = 0;
+
+err_mutex_unlock:
+ mutex_unlock(&apu_rproc->jtag_mutex);
+
+ return ret;
+}
+
+static ssize_t rproc_jtag_read(struct file *filp, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct rproc *rproc = filp->private_data;
+ struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
+ char *buf = apu_rproc->jtag_enabled ? "enabled\n" : "disabled\n";
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t rproc_jtag_write(struct file *filp, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct rproc *rproc = filp->private_data;
+ struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
+ char buf[10];
+ int ret;
+
+ if (count < 1 || count > sizeof(buf))
+ return -EINVAL;
+
+ ret = copy_from_user(buf, user_buf, count);
+ if (ret)
+ return -EFAULT;
+
+ /* remove end of line */
+ if (buf[count - 1] == '\n')
+ buf[count - 1] = '\0';
+
+ if (!strncmp(buf, "enabled", count))
+ ret = apu_enable_jtag(apu_rproc);
+ else if (!strncmp(buf, "disabled", count))
+ ret = apu_disable_jtag(apu_rproc);
+ else
+ return -EINVAL;
+
+ return ret ? ret : count;
+}
+
+static const struct file_operations rproc_jtag_ops = {
+ .read = rproc_jtag_read,
+ .write = rproc_jtag_write,
+ .open = simple_open,
+};
+
+static int apu_jtag_probe(struct mtk_apu_rproc *apu_rproc)
+{
+ int ret;
+
+ if (!apu_rproc->rproc->dbg_dir)
+ return -ENODEV;
+
+ apu_rproc->pinctrl = devm_pinctrl_get(apu_rproc->dev);
+ if (IS_ERR(apu_rproc->pinctrl)) {
+ dev_warn(apu_rproc->dev, "Failed to find JTAG pinctrl\n");
+ return PTR_ERR(apu_rproc->pinctrl);
+ }
+
+ apu_rproc->pinctrl_jtag = pinctrl_lookup_state(apu_rproc->pinctrl,
+ "jtag");
+ if (IS_ERR(apu_rproc->pinctrl_jtag))
+ return PTR_ERR(apu_rproc->pinctrl_jtag);
+
+ ret = pinctrl_select_state(apu_rproc->pinctrl,
+ apu_rproc->pinctrl_jtag);
+ if (ret < 0)
+ return ret;
+
+ mutex_init(&apu_rproc->jtag_mutex);
+
+ debugfs_create_file("jtag", 0600, apu_rproc->rproc->dbg_dir,
+ apu_rproc->rproc, &rproc_jtag_ops);
+
+ return 0;
+}
+#else
+static int apu_jtag_probe(struct mtk_apu_rproc *apu_rproc)
+{
+ return 0;
+}
+
+static int apu_disable_jtag(struct mtk_apu_rproc *apu_rproc)
+{
+ return 0;
+}
+#endif /* CONFIG_MTK_APU_JTAG */
+
static int mtk_apu_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -442,6 +583,10 @@ static int mtk_apu_rproc_probe(struct platform_device *pdev)
goto free_rproc;
}
+ ret = apu_jtag_probe(apu_rproc);
+ if (ret)
+ dev_warn(dev, "Failed to configure jtag\n");
+
return 0;
free_rproc:
@@ -457,7 +602,7 @@ static int mtk_apu_rproc_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
disable_irq(apu_rproc->irq);
-
+ apu_disable_jtag(apu_rproc);
rproc_del(rproc);
of_reserved_mem_device_release(dev);
rproc_free(rproc);
--
2.34.1
From: Julien STEPHAN <[email protected]>
This adds support of APU available in the MT8365.
Signed-off-by: Julien STEPHAN <[email protected]>
Signed-off-by: Alexandre Bailon <[email protected]>
---
drivers/remoteproc/mtk_apu.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
index deec51b86ba5..57dd73c63d3f 100644
--- a/drivers/remoteproc/mtk_apu.c
+++ b/drivers/remoteproc/mtk_apu.c
@@ -96,6 +96,24 @@ static const struct mtk_apu_conf mt8183_conf = {
.clk_names = mt8183_clk_names
};
+static const char * const mt8365_clk_names[] = {
+ "if_ck",
+ "edma",
+ "ahb",
+ "axi",
+ "ipu",
+ "jtag",
+ "smi_cam",
+ "ifr_apu_axi",
+};
+
+static const struct mtk_apu_conf mt8365_conf = {
+ .core_default0 = BIT(26) | BIT(20),
+ .core_default1 = BIT(3) | BIT(7),
+ .num_clks = ARRAY_SIZE(mt8365_clk_names),
+ .clk_names = mt8365_clk_names
+};
+
static int mtk_apu_iommu_map(struct rproc *rproc, struct rproc_mem_entry *entry)
{
struct mtk_apu_rproc *apu_rproc = rproc->priv;
@@ -633,6 +651,7 @@ static int mtk_apu_rproc_remove(struct platform_device *pdev)
static const struct of_device_id mtk_apu_rproc_of_match[] = {
{ .compatible = "mediatek,mt8183-apu", .data = &mt8183_conf },
+ { .compatible = "mediatek,mt8365-apu", .data = &mt8365_conf },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mtk_apu_rproc_of_match);
--
2.34.1
On Fri, Mar 04, 2022 at 05:15:09PM +0100, Alexandre Bailon wrote:
> This updates the Mediatek APU bindings to support the MT8365.
>
> Signed-off-by: Alexandre Bailon <[email protected]>
> ---
> .../bindings/remoteproc/mtk,apu.yaml | 45 ++++++++++++++++---
> 1 file changed, 39 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
> index b640aa96d678..388352ccb2b5 100644
> --- a/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
> +++ b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
> @@ -16,7 +16,9 @@ maintainers:
>
> properties:
> compatible:
> - const: mediatek,mt8183-apu
> + enum:
> + - mediatek,mt8183-apu
> + - mediatek,mt8365-apu
>
> reg:
> maxItems: 1
> @@ -26,13 +28,11 @@ properties:
>
> clocks:
> minItems: 3
> - maxItems: 3
> + maxItems: 8
>
> clock-names:
> - items:
> - - const: axi
> - - const: ipu
> - - const: jtag
> + minItems: 3
> + maxItems: 8
>
> iommus:
> maxItems: 3
> @@ -69,6 +69,39 @@ required:
>
> additionalProperties: false
>
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - mediatek,mt8183-apu
> + then:
> + properties:
> + clock-names:
> + items:
> + - const: axi
> + - const: ipu
> + - const: jtag
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - mediatek,mt8365-apu
> + then:
> + properties:
> + clock-names:
> + items:
> + - const: if_ck
> + - const: edma
> + - const: ahb
> + - const: axi
> + - const: ipu
> + - const: jtag
> + - const: smi_cam
> + - const: ifr_apu_axi
Keep the first 3 clocks the same as prior h/w and keep at the top level.
Then the if/then just needs to set the number of entries to 3 or 8.
Rob
On Fri, Mar 04, 2022 at 05:15:08PM +0100, Alexandre Bailon wrote:
> This adds dt bindings for the APU present in the MT8183.
>
> Signed-off-by: Alexandre Bailon <[email protected]>
> ---
> .../bindings/remoteproc/mtk,apu.yaml | 122 ++++++++++++++++++
> 1 file changed, 122 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
> new file mode 100644
> index 000000000000..b640aa96d678
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/remoteproc/mtk,apu.yaml
> @@ -0,0 +1,122 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +
> +---
> +$id: "http://devicetree.org/schemas/remoteproc/mtk,apu.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: Mediatek AI Processor Unit (APU)
> +
> +description:
> + This document defines the binding for the APU, a co-processor that could
> + offload the CPU for machine learning and neural network.
> +
> +maintainers:
> + - Alexandre Bailon <[email protected]>
> +
> +properties:
> + compatible:
> + const: mediatek,mt8183-apu
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + clocks:
> + minItems: 3
> + maxItems: 3
> +
> + clock-names:
> + items:
> + - const: axi
> + - const: ipu
> + - const: jtag
> +
> + iommus:
> + maxItems: 3
> +
> + memory-region:
> + maxItems: 3
> +
> + memory-region-da:
> + description:
> + Array of APU device address. This is used to map the APU device address
> + to a physical address.
> + maxItems: 3
'dma-ranges' should work for this.
> +
> + power-domains:
> + maxItems: 1
> +
> + pinctrl:
> + description: pinctrl handles, required to configure pins for JTAG.
> +
> + pinctrl-names:
> + items:
> + - const: jtag
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - clocks
> + - clock-names
> + - iommus
> + - memory-region
> + - memory-region-da
> + - power-domains
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/mt8183-clk.h>
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/memory/mt8183-larb-port.h>
> + #include <dt-bindings/power/mt8183-power.h>
> +
> + reserved-memory {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges;
> +
> + vdev0buffer: vdev0buffer@52900000 {
> + compatible = "shared-dma-pool";
> + reg = <0x52900000 0x4000>;
> + no-map;
> + };
> +
> + vdev0vring0: vdev0vring0@52904000 {
> + compatible = "shared-dma-pool";
> + reg = <0x52904000 0x2000>;
> + no-map;
> + };
> +
> + vdev0vring1: vdev0vring1@52906000 {
> + compatible = "shared-dma-pool";
> + reg = <0x52906000 0x2000>;
> + no-map;
> + };
> + };
> +
> + apu0: apu@19100000 {
> + compatible = "mediatek,mt8183-apu";
> + reg = <0x19180000 0x14000>;
> + interrupts = <GIC_SPI 292 IRQ_TYPE_LEVEL_LOW>;
> +
> + iommus = <&iommu M4U_PORT_IMG_IPUO>,
> + <&iommu M4U_PORT_IMG_IPU3O>,
> + <&iommu M4U_PORT_IMG_IPUI>;
> +
> + clocks = <&ipu_core0 CLK_IPU_CORE0_AXI>,
> + <&ipu_core0 CLK_IPU_CORE0_IPU>,
> + <&ipu_core0 CLK_IPU_CORE0_JTAG>;
> +
> + clock-names = "axi", "ipu", "jtag";
> +
> + power-domains = <&scpsys MT8183_POWER_DOMAIN_VPU_CORE0>;
> + memory-region = <&vdev0buffer>, <&vdev0vring0>, <&vdev0vring1>;
> + memory-region-da = <0x6fff8000>, <0x6fffc000>, <0x6fffe000>;
> + };
> +...
> --
> 2.34.1
>
>
On Fri 04 Mar 10:15 CST 2022, Alexandre Bailon wrote:
> From: Julien STEPHAN <[email protected]>
>
> This adds support of APU available in the MT8365.
>
> Signed-off-by: Julien STEPHAN <[email protected]>
> Signed-off-by: Alexandre Bailon <[email protected]>
> ---
> drivers/remoteproc/mtk_apu.c | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
> index deec51b86ba5..57dd73c63d3f 100644
> --- a/drivers/remoteproc/mtk_apu.c
> +++ b/drivers/remoteproc/mtk_apu.c
> @@ -96,6 +96,24 @@ static const struct mtk_apu_conf mt8183_conf = {
> .clk_names = mt8183_clk_names
> };
>
> +static const char * const mt8365_clk_names[] = {
> + "if_ck",
> + "edma",
> + "ahb",
> + "axi",
> + "ipu",
> + "jtag",
> + "smi_cam",
> + "ifr_apu_axi",
> +};
> +
> +static const struct mtk_apu_conf mt8365_conf = {
> + .core_default0 = BIT(26) | BIT(20),
> + .core_default1 = BIT(3) | BIT(7),
Would it be possible to get some defines for these bits as well?
Thanks,
Bjorn
> + .num_clks = ARRAY_SIZE(mt8365_clk_names),
> + .clk_names = mt8365_clk_names
> +};
> +
> static int mtk_apu_iommu_map(struct rproc *rproc, struct rproc_mem_entry *entry)
> {
> struct mtk_apu_rproc *apu_rproc = rproc->priv;
> @@ -633,6 +651,7 @@ static int mtk_apu_rproc_remove(struct platform_device *pdev)
>
> static const struct of_device_id mtk_apu_rproc_of_match[] = {
> { .compatible = "mediatek,mt8183-apu", .data = &mt8183_conf },
> + { .compatible = "mediatek,mt8365-apu", .data = &mt8365_conf },
> { /* sentinel */ },
> };
> MODULE_DEVICE_TABLE(of, mtk_apu_rproc_of_match);
> --
> 2.34.1
>
On Fri 04 Mar 10:15 CST 2022, Alexandre Bailon wrote:
> This adds a driver to control the APU present in the MT8183.
> This loads the firmware and start the DSP.
>
> Signed-off-by: Alexandre Bailon <[email protected]>
> ---
> drivers/remoteproc/Kconfig | 10 +
> drivers/remoteproc/Makefile | 1 +
> drivers/remoteproc/mtk_apu.c | 486 +++++++++++++++++++++++++++++++++++
> 3 files changed, 497 insertions(+)
> create mode 100644 drivers/remoteproc/mtk_apu.c
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 341156e2a29b..959d24e9492c 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -64,6 +64,16 @@ config MTK_SCP
>
> It's safe to say N here.
>
> +config MTK_APU
> + tristate "Mediatek APU remoteproc support"
> + depends on ARCH_MEDIATEK
> + depends on MTK_IOMMU
> + help
> + Say y to support the Mediatek's AI Processing Unit (APU) via
> + the remote processor framework.
> +
> + It's safe to say N here.
> +
> config OMAP_REMOTEPROC
> tristate "OMAP remoteproc support"
> depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX
> diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> index 0ac256b6c977..0ab4461c33af 100644
> --- a/drivers/remoteproc/Makefile
> +++ b/drivers/remoteproc/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
> obj-$(CONFIG_IMX_DSP_REMOTEPROC) += imx_dsp_rproc.o
> obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o
> obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o
> +obj-$(CONFIG_MTK_APU) += mtk_apu.o
> obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
> obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
> obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
> diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
> new file mode 100644
> index 000000000000..867b4682b507
> --- /dev/null
> +++ b/drivers/remoteproc/mtk_apu.c
> @@ -0,0 +1,486 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 BayLibre SAS
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/iommu.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/platform_device.h>
> +#include <linux/remoteproc.h>
> +#include <linux/string.h>
> +
> +#include "remoteproc_internal.h"
> +
> +#define SW_RST (0x0000000C)
> +#define SW_RST_OCD_HALT_ON_RST BIT(12)
> +#define SW_RST_IPU_D_RST BIT(8)
> +#define SW_RST_IPU_B_RST BIT(4)
> +#define CORE_CTRL (0x00000110)
> +#define CORE_CTRL_PDEBUG_ENABLE BIT(31)
> +#define CORE_CTRL_SRAM_64K_iMEM (0x00 << 27)
> +#define CORE_CTRL_SRAM_96K_iMEM (0x01 << 27)
> +#define CORE_CTRL_SRAM_128K_iMEM (0x02 << 27)
> +#define CORE_CTRL_SRAM_192K_iMEM (0x03 << 27)
> +#define CORE_CTRL_SRAM_256K_iMEM (0x04 << 27)
> +#define CORE_CTRL_PBCLK_ENABLE BIT(26)
> +#define CORE_CTRL_RUN_STALL BIT(23)
> +#define CORE_CTRL_STATE_VECTOR_SELECT BIT(19)
> +#define CORE_CTRL_PIF_GATED BIT(17)
> +#define CORE_CTRL_NMI BIT(0)
> +#define CORE_XTENSA_INT (0x00000114)
> +#define CORE_CTL_XTENSA_INT (0x00000118)
> +#define CORE_DEFAULT0 (0x0000013C)
> +#define CORE_DEFAULT0_QOS_SWAP_0 (0x00 << 28)
> +#define CORE_DEFAULT0_QOS_SWAP_1 (0x01 << 28)
> +#define CORE_DEFAULT0_QOS_SWAP_2 (0x02 << 28)
> +#define CORE_DEFAULT0_QOS_SWAP_3 (0x03 << 28)
> +#define CORE_DEFAULT0_ARUSER_USE_IOMMU (0x10 << 23)
> +#define CORE_DEFAULT0_AWUSER_USE_IOMMU (0x10 << 18)
> +#define CORE_DEFAULT1 (0x00000140)
> +#define CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU (0x10 << 0)
> +#define CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU (0x10 << 5)
> +#define CORE_XTENSA_ALTRESETVEC (0x000001F8)
> +
> +#define VDEV_MEM_COUNT (3)
> +
> +#define APU_RESET_DELAY (27)
> +
> +struct mtk_apu_rproc {
> + struct device *dev;
> + void __iomem *base;
> + int irq;
> + unsigned int num_clks;
> + struct clk_bulk_data *clks;
> + struct iommu_domain *domain;
> + struct list_head mappings;
> +};
> +
> +static const char * const mt8183_clk_names[] = {
> + "ipu",
> + "axi",
> + "jtag"
> +};
> +
> +static int mtk_apu_iommu_map(struct rproc *rproc, struct rproc_mem_entry *entry)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> + struct device *dev = rproc->dev.parent;
> + struct rproc_mem_entry *mapping;
> + int ret;
> + u64 pa;
> +
> + /* vdev buffer and vring are already mapped */
> + if (strstr(entry->name, "vdev"))
> + return 0;
> +
> + mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
> + if (!mapping)
> + return -ENOMEM;
> +
> + if (!entry->va)
> + pa = entry->dma;
> + else
> + pa = rproc_va_to_pa(entry->va);
> +
> + ret = iommu_map(apu_rproc->domain, entry->da, pa, entry->len, entry->flags);
Can you please help me understand how this mapping differs from that
performed in rproc_alloc_carveout()?
What I think you're doing here seems very reasonable and as such I would
expect that this is what the core code does for us...
> + if (ret) {
> + dev_err(dev, "iommu_map failed: %d\n", ret);
> + goto free_mapping;
> + }
> +
> + mapping->da = entry->da;
> + mapping->len = entry->len;
> + list_add_tail(&mapping->node, &apu_rproc->mappings);
> +
> + return 0;
> +
> +free_mapping:
> + kfree(mapping);
> +
> + return ret;
> +}
> +
> +static void mtk_apu_iommu_unmap_all(struct rproc *rproc)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> + struct device *dev = rproc->dev.parent;
> + struct rproc_mem_entry *entry, *tmp;
> +
> + /* clean up iommu mapping entries */
> + list_for_each_entry_safe(entry, tmp, &apu_rproc->mappings, node) {
> + size_t unmapped;
> +
> + unmapped = iommu_unmap(apu_rproc->domain, entry->da, entry->len);
> + if (unmapped != entry->len) {
> + /* nothing much to do besides complaining */
> + dev_err(dev, "failed to unmap %zx/%zu\n", entry->len,
> + unmapped);
> + }
> +
> + list_del(&entry->node);
> + kfree(entry);
> + }
> +}
> +
> +static int mtk_apu_rproc_alloc_carveout(struct rproc *rproc,
> + struct rproc_mem_entry *mem)
> +{
> + int flags = IOMMU_READ | IOMMU_READ | IOMMU_NOEXEC;
> + struct device *dev = rproc->dev.parent;
> + int ret;
> +
> + struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
> +
> + mem->va = memremap(mem->dma, mem->len, MEMREMAP_WC);
> + if (IS_ERR_OR_NULL(mem->va)) {
> + dev_err(dev, "Unable to map memory region: %pa+%zu\n",
> + &mem->dma, mem->len);
> + return PTR_ERR(mem->va);
> + }
> +
> + ret = iommu_map(domain, mem->da, mem->dma, mem->len, flags);
> + if (ret)
> + memunmap(mem->va);
> +
> + return 0;
> +}
> +
> +static int mtk_apu_rproc_release_carveout(struct rproc *rproc,
> + struct rproc_mem_entry *mem)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> + struct device *dev = apu_rproc->dev;
> + struct iommu_domain *domain;
> + size_t unmapped;
> +
> + domain = iommu_get_domain_for_dev(dev);
> + unmapped = iommu_unmap(domain, mem->da, mem->len);
> + if (unmapped != mem->len) {
> + /* nothing much to do besides complaining */
> + dev_err(dev, "failed to unmap %zx/%zu\n", mem->len, unmapped);
> + }
> + memunmap(mem->va);
> +
> + return 0;
> +}
> +
> +static int mtk_apu_rproc_vdev_mem_init(struct rproc *rproc)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> + struct device *dev = apu_rproc->dev;
> + struct device_node *np = dev->of_node;
> + struct reserved_mem *rmem;
> + struct rproc_mem_entry *mem;
> + u32 da[VDEV_MEM_COUNT];
> + int ret;
> + int i;
> +
> + ret = of_property_read_u32_array(np, "memory-region-da", da, VDEV_MEM_COUNT);
> + if (ret)
> + return ret;
> +
> + for (i = 0; i < VDEV_MEM_COUNT; i++) {
> + struct device_node *target;
> + char *name;
> +
> + target = of_parse_phandle(np, "memory-region", i);
> + if (!target)
> + return -EINVAL;
> +
> + rmem = of_reserved_mem_lookup(target);
> + of_node_put(target);
> +
> + if (!rmem)
> + return -ENOMEM;
> +
> + ret = strcspn(rmem->name, "@");
> + if (!ret)
> + return -EINVAL;
> +
> + name = kstrndup(rmem->name, ret, GFP_KERNEL);
> + if (!name)
> + return -ENOMEM;
> +
> + mem = rproc_mem_entry_init(dev, NULL, rmem->base, rmem->size,
> + da[i],
> + mtk_apu_rproc_alloc_carveout,
> + mtk_apu_rproc_release_carveout,
> + name);
> + kfree(name);
> + if (!mem)
> + return -ENOMEM;
> +
> + rproc_add_carveout(rproc, mem);
> + }
> +
> + return 0;
> +}
> +
> +static int mtk_apu_rproc_prepare(struct rproc *rproc)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> + int ret;
> +
> + ret = clk_bulk_prepare_enable(apu_rproc->num_clks, apu_rproc->clks);
> + if (ret)
> + dev_err(apu_rproc->dev, "Failed to enable clocks\n");
> +
> + ret = mtk_apu_rproc_vdev_mem_init(rproc);
> + if (ret) {
> + dev_err(apu_rproc->dev, "Failed to init vdev memory\n");
> + clk_bulk_disable_unprepare(apu_rproc->num_clks, apu_rproc->clks);
> +
> + }
> +
> + return ret;
> +}
> +
> +static int mtk_apu_rproc_unprepare(struct rproc *rproc)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> +
> + clk_bulk_disable_unprepare(apu_rproc->num_clks, apu_rproc->clks);
> +
> + return 0;
> +}
> +
> +static int mtk_apu_rproc_start(struct rproc *rproc)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> + u32 core_ctrl;
> +
> + /* Set reset vector of APU firmware boot address */
> + writel(rproc->bootaddr, apu_rproc->base + CORE_XTENSA_ALTRESETVEC);
> +
> + /* Turn on the clocks and stall the APU */
> + core_ctrl = readl(apu_rproc->base + CORE_CTRL);
> + core_ctrl |= CORE_CTRL_PDEBUG_ENABLE | CORE_CTRL_PBCLK_ENABLE |
> + CORE_CTRL_STATE_VECTOR_SELECT | CORE_CTRL_RUN_STALL |
> + CORE_CTRL_PIF_GATED;
> + writel(core_ctrl, apu_rproc->base + CORE_CTRL);
> +
> + /* Reset the APU: this requires 27 ns to be effective on any platform */
> + writel(SW_RST_OCD_HALT_ON_RST | SW_RST_IPU_B_RST | SW_RST_IPU_D_RST,
> + apu_rproc->base + SW_RST);
> + ndelay(APU_RESET_DELAY);
> + writel(0, apu_rproc->base + SW_RST);
> +
> + core_ctrl &= ~CORE_CTRL_PIF_GATED;
> + writel(core_ctrl, apu_rproc->base + CORE_CTRL);
> +
> + /* Configure memory accesses to go through the IOMMU */
> + writel(CORE_DEFAULT0_AWUSER_USE_IOMMU | CORE_DEFAULT0_ARUSER_USE_IOMMU |
> + CORE_DEFAULT0_QOS_SWAP_1, apu_rproc->base + CORE_DEFAULT0);
> + writel(CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU |
> + CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU,
> + apu_rproc->base + CORE_DEFAULT1);
> +
> + /* Release the APU */
> + core_ctrl &= ~CORE_CTRL_RUN_STALL;
> + writel(core_ctrl, apu_rproc->base + CORE_CTRL);
> +
> + return 0;
> +}
> +
> +static int mtk_apu_rproc_stop(struct rproc *rproc)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> + u32 core_ctrl;
> +
> + core_ctrl = readl(apu_rproc->base + CORE_CTRL);
> + writel(core_ctrl | CORE_CTRL_RUN_STALL, apu_rproc->base + CORE_CTRL);
> +
> + mtk_apu_iommu_unmap_all(rproc);
> +
> + return 0;
> +}
> +
> +static void mtk_apu_rproc_kick(struct rproc *rproc, int vqid)
> +{
> + struct mtk_apu_rproc *apu_rproc = rproc->priv;
> +
> + writel(1 << vqid, apu_rproc->base + CORE_CTL_XTENSA_INT);
> +}
> +
> +static int mtk_apu_load(struct rproc *rproc, const struct firmware *fw)
> +
> +{
> + struct rproc_mem_entry *entry, *tmp;
> + int ret;
> +
> + ret = rproc_elf_load_segments(rproc, fw);
> + if (ret)
> + return ret;
> +
> + list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
> + ret = mtk_apu_iommu_map(rproc, entry);
> + if (ret)
> + goto err_unmap_all;
> + }
> +
> + return 0;
> +
> +err_unmap_all:
> + mtk_apu_iommu_unmap_all(rproc);
> +
> + return ret;
> +}
> +
> +static const struct rproc_ops mtk_apu_rproc_ops = {
> + .prepare = mtk_apu_rproc_prepare,
> + .unprepare = mtk_apu_rproc_unprepare,
> + .start = mtk_apu_rproc_start,
> + .stop = mtk_apu_rproc_stop,
> + .kick = mtk_apu_rproc_kick,
> + .load = mtk_apu_load,
> + .parse_fw = rproc_elf_load_rsc_table,
> + .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
> + .sanity_check = rproc_elf_sanity_check,
> + .get_boot_addr = rproc_elf_get_boot_addr,
> +};
> +
> +static irqreturn_t mtk_apu_rproc_callback(int irq, void *data)
> +{
> + struct rproc *rproc = data;
> + struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
> +
> + writel(1, apu_rproc->base + CORE_XTENSA_INT);
> +
> + return IRQ_WAKE_THREAD;
> +}
> +
> +static int mtk_apu_rproc_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct mtk_apu_rproc *apu_rproc;
> + struct rproc *rproc;
> + struct resource *res;
> + int ret;
> + int i;
> +
> + ret = of_property_count_elems_of_size(dev->of_node, "memory-region",
> + sizeof(phandle));
> + if (ret != VDEV_MEM_COUNT)
> + return -EINVAL;
> +
> + ret = of_property_count_elems_of_size(dev->of_node, "memory-region-da",
> + sizeof(u32));
> + if (ret != VDEV_MEM_COUNT)
> + return -EINVAL;
> +
> + rproc = rproc_alloc(dev, dev_name(dev), &mtk_apu_rproc_ops, NULL,
> + sizeof(*apu_rproc));
> + if (!rproc)
> + return -ENOMEM;
> +
> + rproc->recovery_disabled = true;
> + rproc->has_iommu = false;
> + rproc->auto_boot = false;
> +
> + apu_rproc = rproc->priv;
> + apu_rproc->dev = dev;
> + INIT_LIST_HEAD(&apu_rproc->mappings);
> +
> + platform_set_drvdata(pdev, rproc);
> +
> + apu_rproc->domain = iommu_get_domain_for_dev(dev);
> + if (!apu_rproc->domain) {
> + ret = -ENODEV;
> + goto free_rproc;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + apu_rproc->base = devm_ioremap_resource(dev, res);
Please use devm_platform_ioremap_resource()
> + if (IS_ERR(apu_rproc->base)) {
> + dev_err(dev, "Failed to map mmio\n");
> + ret = PTR_ERR(apu_rproc->base);
> + goto free_rproc;
> + }
> +
> + apu_rproc->irq = platform_get_irq(pdev, 0);
> + if (apu_rproc->irq < 0) {
> + ret = apu_rproc->irq;
> + goto free_rproc;
> + }
> +
> + apu_rproc->domain = iommu_get_domain_for_dev(dev);
You did this ~20 lines above already.
> + if (!apu_rproc->domain) {
> + ret = -ENODEV;
> + goto free_rproc;
> + }
> +
> + ret = devm_request_threaded_irq(dev, apu_rproc->irq,
> + mtk_apu_rproc_callback, handle_event,
> + IRQF_SHARED | IRQF_ONESHOT,
> + NULL, rproc);
> + if (ret) {
> + dev_err(dev, "devm_request_threaded_irq error: %d\n", ret);
> + goto free_rproc;
> + }
> +
> + apu_rproc->num_clks = ARRAY_SIZE(mt8183_clk_names);
> + apu_rproc->clks = devm_kcalloc(dev, apu_rproc->num_clks,
> + sizeof(*apu_rproc->clks), GFP_KERNEL);
You know that this is going to be ARRAY_SIZE(mt8183_clk_names), so you
could make clks a statically sized array instead...
> + for (i = 0; i < apu_rproc->num_clks; ++i)
> + apu_rproc->clks[i].id = mt8183_clk_names[i];
> +
> + ret = devm_clk_bulk_get(dev, apu_rproc->num_clks, apu_rproc->clks);
> + if (ret) {
> + dev_err(dev, "Failed to get clocks\n");
Please use dev_err_probe()
> + goto free_rproc;
> + }
> +
> + ret = rproc_add(rproc);
> + if (ret) {
> + dev_err(dev, "rproc_add failed: %d\n", ret);
> + goto free_rproc;
> + }
> +
> + return 0;
> +
> +free_rproc:
> + rproc_free(rproc);
> +
> + return ret;
> +}
> +
> +static int mtk_apu_rproc_remove(struct platform_device *pdev)
> +{
> + struct rproc *rproc = platform_get_drvdata(pdev);
> + struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
> + struct device *dev = &pdev->dev;
> +
> + disable_irq(apu_rproc->irq);
> +
> + rproc_del(rproc);
> + of_reserved_mem_device_release(dev);
Iiuc this is the reverse of of_reserved_mem_device_init_by_*(), but you
do of_reserved_mem_lookup(). So I don't think you need this.
I'm not sure what your irq handler actually does, is there a specific
reason for you to call disable_irq()?
If not you could use devm_rproc_* and get rid of the remove function...
> + rproc_free(rproc);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mtk_apu_rproc_of_match[] = {
> + { .compatible = "mediatek,mt8183-apu", },
> + { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, mtk_apu_rproc_of_match);
> +
> +static struct platform_driver mtk_apu_rproc_driver = {
> + .probe = mtk_apu_rproc_probe,
> + .remove = mtk_apu_rproc_remove,
> + .driver = {
> + .name = "mtk_apu-rproc",
> + .of_match_table = of_match_ptr(mtk_apu_rproc_of_match),
of_match_ptr() will be dropped in builds without CONFIG_OF and we will
then get a warning that mtk_apu_rproc_of_match isn't referenced.
Just leave it around it won't cost you anything.
Thanks,
Bjorn
> + },
> +};
> +module_platform_driver(mtk_apu_rproc_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Alexandre Bailon");
> +MODULE_DESCRIPTION("MTK APU Remote Processor control driver");
> --
> 2.34.1
>
On Fri 04 Mar 10:15 CST 2022, Alexandre Bailon wrote:
> From: Julien STEPHAN <[email protected]>
>
> This commits prepare the driver to be more generic in order to support
> multiple platform using the compatible property.
> To do that, put some register values and the clocks names inside
> private data.
>
> Signed-off-by: Julien STEPHAN <[email protected]>
> Signed-off-by: Alexandre Bailon <[email protected]>
> ---
> drivers/remoteproc/mtk_apu.c | 35 ++++++++++++++++++++++++++++-------
> 1 file changed, 28 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
> index 3905eb5b7174..deec51b86ba5 100644
> --- a/drivers/remoteproc/mtk_apu.c
> +++ b/drivers/remoteproc/mtk_apu.c
> @@ -58,12 +58,20 @@
>
> #define APU_RESET_DELAY (27)
>
> +struct mtk_apu_conf {
> + u32 core_default0;
> + u32 core_default1;
> + u32 num_clks;
> + const char * const *clk_names;
> +};
> +
> struct mtk_apu_rproc {
> struct device *dev;
> void __iomem *base;
> int irq;
> unsigned int num_clks;
> struct clk_bulk_data *clks;
> + struct mtk_apu_conf *conf;
> struct iommu_domain *domain;
> struct list_head mappings;
>
> @@ -81,6 +89,13 @@ static const char * const mt8183_clk_names[] = {
> "jtag"
> };
>
> +static const struct mtk_apu_conf mt8183_conf = {
> + .core_default0 = (0x10 << 23) | (0x10 << 18),
CORE_DEFAULT0_AWUSER_USE_IOMMU | CORE_DEFAULT0_ARUSER_USE_IOMMU ?
> + .core_default1 = (0x10 << 0) | (0x10 << 5),
CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU | CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU ?
Regards,
Bjorn
> + .num_clks = ARRAY_SIZE(mt8183_clk_names),
> + .clk_names = mt8183_clk_names
> +};
> +
> static int mtk_apu_iommu_map(struct rproc *rproc, struct rproc_mem_entry *entry)
> {
> struct mtk_apu_rproc *apu_rproc = rproc->priv;
> @@ -289,10 +304,9 @@ static int mtk_apu_rproc_start(struct rproc *rproc)
> writel(core_ctrl, apu_rproc->base + CORE_CTRL);
>
> /* Configure memory accesses to go through the IOMMU */
> - writel(CORE_DEFAULT0_AWUSER_USE_IOMMU | CORE_DEFAULT0_ARUSER_USE_IOMMU |
> - CORE_DEFAULT0_QOS_SWAP_1, apu_rproc->base + CORE_DEFAULT0);
> - writel(CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU |
> - CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU,
> + writel(apu_rproc->conf->core_default0 | CORE_DEFAULT0_QOS_SWAP_1,
> + apu_rproc->base + CORE_DEFAULT0);
> + writel(apu_rproc->conf->core_default1,
> apu_rproc->base + CORE_DEFAULT1);
>
> /* Release the APU */
> @@ -565,11 +579,18 @@ static int mtk_apu_rproc_probe(struct platform_device *pdev)
> goto free_rproc;
> }
>
> - apu_rproc->num_clks = ARRAY_SIZE(mt8183_clk_names);
> +
> + apu_rproc->conf = (struct mtk_apu_conf *)device_get_match_data(dev);
> + if (!apu_rproc->conf) {
> + ret = -ENODEV;
> + goto free_rproc;
> + }
> +
> + apu_rproc->num_clks = apu_rproc->conf->num_clks;
> apu_rproc->clks = devm_kcalloc(dev, apu_rproc->num_clks,
> sizeof(*apu_rproc->clks), GFP_KERNEL);
> for (i = 0; i < apu_rproc->num_clks; ++i)
> - apu_rproc->clks[i].id = mt8183_clk_names[i];
> + apu_rproc->clks[i].id = apu_rproc->conf->clk_names[i];
>
> ret = devm_clk_bulk_get(dev, apu_rproc->num_clks, apu_rproc->clks);
> if (ret) {
> @@ -611,7 +632,7 @@ static int mtk_apu_rproc_remove(struct platform_device *pdev)
> }
>
> static const struct of_device_id mtk_apu_rproc_of_match[] = {
> - { .compatible = "mediatek,mt8183-apu", },
> + { .compatible = "mediatek,mt8183-apu", .data = &mt8183_conf },
> { /* sentinel */ },
> };
> MODULE_DEVICE_TABLE(of, mtk_apu_rproc_of_match);
> --
> 2.34.1
>
On Fri 04 Mar 10:15 CST 2022, Alexandre Bailon wrote:
> The DSP could be debugged using JTAG.
> The support of JTAG could enabled at build time and it could be enabled
> using debugfs.
>
> Signed-off-by: Alexandre Bailon <[email protected]>
> ---
> drivers/remoteproc/Kconfig | 9 +++
> drivers/remoteproc/mtk_apu.c | 147 ++++++++++++++++++++++++++++++++++-
> 2 files changed, 155 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> index 959d24e9492c..28140cf04d8a 100644
> --- a/drivers/remoteproc/Kconfig
> +++ b/drivers/remoteproc/Kconfig
> @@ -74,6 +74,15 @@ config MTK_APU
>
> It's safe to say N here.
>
> +config MTK_APU_JTAG
> + bool "Enable support of JTAG"
> + depends on MTK_APU
> + help
> + Say y to enable support of JTAG.
> + By default, JTAG will remain disabled until it is enabled using
> + debugfs: remoteproc/remoteproc0/jtag. Write 1 to enable it and
> + 0 to disable it.
> +
> config OMAP_REMOTEPROC
> tristate "OMAP remoteproc support"
> depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX
> diff --git a/drivers/remoteproc/mtk_apu.c b/drivers/remoteproc/mtk_apu.c
> index 867b4682b507..3905eb5b7174 100644
> --- a/drivers/remoteproc/mtk_apu.c
> +++ b/drivers/remoteproc/mtk_apu.c
> @@ -5,12 +5,14 @@
>
> #include <linux/bitops.h>
> #include <linux/clk.h>
> +#include <linux/debugfs.h>
> #include <linux/delay.h>
> #include <linux/interrupt.h>
> #include <linux/iommu.h>
> #include <linux/irq.h>
> #include <linux/module.h>
> #include <linux/of_reserved_mem.h>
> +#include <linux/pinctrl/consumer.h>
> #include <linux/platform_device.h>
> #include <linux/remoteproc.h>
> #include <linux/string.h>
> @@ -45,6 +47,11 @@
> #define CORE_DEFAULT1 (0x00000140)
> #define CORE_DEFAULT0_ARUSER_IDMA_USE_IOMMU (0x10 << 0)
> #define CORE_DEFAULT0_AWUSER_IDMA_USE_IOMMU (0x10 << 5)
> +#define CORE_DEFAULT2 (0x00000144)
> +#define CORE_DEFAULT2_DBG_EN BIT(3)
> +#define CORE_DEFAULT2_NIDEN BIT(2)
> +#define CORE_DEFAULT2_SPNIDEN BIT(1)
> +#define CORE_DEFAULT2_SPIDEN BIT(0)
> #define CORE_XTENSA_ALTRESETVEC (0x000001F8)
>
> #define VDEV_MEM_COUNT (3)
> @@ -59,6 +66,13 @@ struct mtk_apu_rproc {
> struct clk_bulk_data *clks;
> struct iommu_domain *domain;
> struct list_head mappings;
> +
> +#ifdef CONFIG_MTK_APU_JTAG
> + struct pinctrl *pinctrl;
> + struct pinctrl_state *pinctrl_jtag;
> + bool jtag_enabled;
> + struct mutex jtag_mutex;
> +#endif
> };
>
> static const char * const mt8183_clk_names[] = {
> @@ -355,6 +369,133 @@ static irqreturn_t mtk_apu_rproc_callback(int irq, void *data)
> return IRQ_WAKE_THREAD;
> }
>
> +#ifdef CONFIG_MTK_APU_JTAG
Is there a strong reason to keep this compiled out? It's not that much
code and it means that I have to build test both variations...
> +
> +static int apu_enable_jtag(struct mtk_apu_rproc *apu_rproc)
> +{
> + int ret = 0;
> +
> + mutex_lock(&apu_rproc->jtag_mutex);
What happens if you perform the below writel() when jtag is already
enabled? I.e. do you need this mutex or could you simply have
enable/disable just write the register?
> + if (apu_rproc->jtag_enabled)
> + goto err_mutex_unlock;
> +
> + writel(CORE_DEFAULT2_SPNIDEN | CORE_DEFAULT2_SPIDEN |
> + CORE_DEFAULT2_NIDEN | CORE_DEFAULT2_DBG_EN,
> + apu_rproc->base + CORE_DEFAULT2);
> +
> + apu_rproc->jtag_enabled = 1;
> +
> +err_mutex_unlock:
> + mutex_unlock(&apu_rproc->jtag_mutex);
> +
> + return ret;
> +}
> +
> +static int apu_disable_jtag(struct mtk_apu_rproc *apu_rproc)
> +{
> + int ret = 0;
> +
> + mutex_lock(&apu_rproc->jtag_mutex);
> + if (!apu_rproc->jtag_enabled)
> + goto err_mutex_unlock;
> +
> + writel(0, apu_rproc->base + CORE_DEFAULT2);
> +
> + apu_rproc->jtag_enabled = 0;
> +
> +err_mutex_unlock:
> + mutex_unlock(&apu_rproc->jtag_mutex);
> +
> + return ret;
> +}
> +
> +static ssize_t rproc_jtag_read(struct file *filp, char __user *userbuf,
> + size_t count, loff_t *ppos)
> +{
> + struct rproc *rproc = filp->private_data;
> + struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
> + char *buf = apu_rproc->jtag_enabled ? "enabled\n" : "disabled\n";
> +
> + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
Per my ask about write below, please make this read 'Y' or 'N'.
> +}
> +
> +static ssize_t rproc_jtag_write(struct file *filp, const char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct rproc *rproc = filp->private_data;
> + struct mtk_apu_rproc *apu_rproc = (struct mtk_apu_rproc *)rproc->priv;
> + char buf[10];
> + int ret;
> +
> + if (count < 1 || count > sizeof(buf))
> + return -EINVAL;
> +
> + ret = copy_from_user(buf, user_buf, count);
> + if (ret)
> + return -EFAULT;
> +
> + /* remove end of line */
> + if (buf[count - 1] == '\n')
> + buf[count - 1] = '\0';
> +
Please use kstrtobool_from_user().
> + if (!strncmp(buf, "enabled", count))
> + ret = apu_enable_jtag(apu_rproc);
> + else if (!strncmp(buf, "disabled", count))
> + ret = apu_disable_jtag(apu_rproc);
> + else
> + return -EINVAL;
> +
> + return ret ? ret : count;
> +}
> +
> +static const struct file_operations rproc_jtag_ops = {
> + .read = rproc_jtag_read,
> + .write = rproc_jtag_write,
> + .open = simple_open,
> +};
> +
> +static int apu_jtag_probe(struct mtk_apu_rproc *apu_rproc)
> +{
> + int ret;
> +
> + if (!apu_rproc->rproc->dbg_dir)
> + return -ENODEV;
> +
> + apu_rproc->pinctrl = devm_pinctrl_get(apu_rproc->dev);
> + if (IS_ERR(apu_rproc->pinctrl)) {
> + dev_warn(apu_rproc->dev, "Failed to find JTAG pinctrl\n");
I believe you failed to find the pinctrl instance for the remoteproc
driver, not for the JTAG.
> + return PTR_ERR(apu_rproc->pinctrl);
> + }
> +
> + apu_rproc->pinctrl_jtag = pinctrl_lookup_state(apu_rproc->pinctrl,
> + "jtag");
> + if (IS_ERR(apu_rproc->pinctrl_jtag))
> + return PTR_ERR(apu_rproc->pinctrl_jtag);
> +
> + ret = pinctrl_select_state(apu_rproc->pinctrl,
> + apu_rproc->pinctrl_jtag);
So if the kernel is compiled with MTK_APU_JTAG "jtag" is the new
"default" for this device?
Regards,
Bjorn
> + if (ret < 0)
> + return ret;
> +
> + mutex_init(&apu_rproc->jtag_mutex);
> +
> + debugfs_create_file("jtag", 0600, apu_rproc->rproc->dbg_dir,
> + apu_rproc->rproc, &rproc_jtag_ops);
> +
> + return 0;
> +}
> +#else
> +static int apu_jtag_probe(struct mtk_apu_rproc *apu_rproc)
> +{
> + return 0;
> +}
> +
> +static int apu_disable_jtag(struct mtk_apu_rproc *apu_rproc)
> +{
> + return 0;
> +}
> +#endif /* CONFIG_MTK_APU_JTAG */
> +
> static int mtk_apu_rproc_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -442,6 +583,10 @@ static int mtk_apu_rproc_probe(struct platform_device *pdev)
> goto free_rproc;
> }
>
> + ret = apu_jtag_probe(apu_rproc);
> + if (ret)
> + dev_warn(dev, "Failed to configure jtag\n");
If devm_pinctrl_get() failed you'll get two warnings, and if the user
haven't added a "jtag" pinctrl state this warning isn't very
descriptive. Consider omitting it and add appropriate error messages in
apu_jtag_probe().
Regards,
Bjorn
> +
> return 0;
>
> free_rproc:
> @@ -457,7 +602,7 @@ static int mtk_apu_rproc_remove(struct platform_device *pdev)
> struct device *dev = &pdev->dev;
>
> disable_irq(apu_rproc->irq);
> -
> + apu_disable_jtag(apu_rproc);
> rproc_del(rproc);
> of_reserved_mem_device_release(dev);
> rproc_free(rproc);
> --
> 2.34.1
>