From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,NICE_REPLY_A, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 54698C63777 for ; Tue, 17 Nov 2020 19:42:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E984B22210 for ; Tue, 17 Nov 2020 19:42:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="X/2BbAve" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730578AbgKQTll (ORCPT ); Tue, 17 Nov 2020 14:41:41 -0500 Received: from fllv0016.ext.ti.com ([198.47.19.142]:42996 "EHLO fllv0016.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728951AbgKQTll (ORCPT ); Tue, 17 Nov 2020 14:41:41 -0500 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id 0AHJfV46052816; Tue, 17 Nov 2020 13:41:31 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1605642091; bh=x6eUH5rjsyfE9sQFowThR5PVN8Osc4d7zM3/s2ETbk0=; h=Subject:To:CC:References:From:Date:In-Reply-To; b=X/2BbAveTkEjQK5uYax1hWnC8JC8TY/haVEymLlGDofhKNjIc8xwR7NYXv3NJXV6p LQ3KccJAmuJvPGNVREO0OKT8sSPzMWFvbPaMHiYzwJ43xkgJQKVvSENxCUCZo51KHo APIUR/HC+/68h1plB1BIOZBYshI1Otvy7ENExem4= Received: from DLEE114.ent.ti.com (dlee114.ent.ti.com [157.170.170.25]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 0AHJfVxd095954 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 17 Nov 2020 13:41:31 -0600 Received: from DLEE103.ent.ti.com (157.170.170.33) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1979.3; Tue, 17 Nov 2020 13:41:31 -0600 Received: from fllv0039.itg.ti.com (10.64.41.19) by DLEE103.ent.ti.com (157.170.170.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1979.3 via Frontend Transport; Tue, 17 Nov 2020 13:41:30 -0600 Received: from [10.250.38.244] (ileax41-snat.itg.ti.com [10.172.224.153]) by fllv0039.itg.ti.com (8.15.2/8.15.2) with ESMTP id 0AHJfUvX123354; Tue, 17 Nov 2020 13:41:30 -0600 Subject: Re: [PATCH 2/6] remoteproc/pru: Add a PRU remoteproc driver To: Grzegorz Jaszczyk , , , CC: , , , , , , , , References: <20201114084613.13503-1-grzegorz.jaszczyk@linaro.org> <20201114084613.13503-3-grzegorz.jaszczyk@linaro.org> From: Suman Anna Message-ID: <19cfcc3f-6b7b-4073-9d0d-84ab3207658f@ti.com> Date: Tue, 17 Nov 2020 13:41:25 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <20201114084613.13503-3-grzegorz.jaszczyk@linaro.org> Content-Type: text/plain; charset="utf-8" Content-Language: en-US Content-Transfer-Encoding: 7bit X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Precedence: bulk List-ID: X-Mailing-List: linux-remoteproc@vger.kernel.org Hi Greg, I have a few minor comments below.. On 11/14/20 2:46 AM, Grzegorz Jaszczyk wrote: > From: Suman Anna > > The Programmable Real-Time Unit Subsystem (PRUSS) consists of > dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs) > for program execution. This patch adds a remoteproc platform > driver for managing the individual PRU RISC cores life cycle. > > The PRUs do not have a unified address space (have an Instruction > RAM and a primary Data RAM at both 0x0). The PRU remoteproc driver > therefore uses a custom remoteproc core ELF loader ops. The added > .da_to_va ops is only used to provide translations for the PRU > Data RAMs. This remoteproc driver does not have support for error > recovery and system suspend/resume features. Different compatibles > are used to allow providing scalability for instance-specific device > data if needed. The driver uses a default firmware-name retrieved > from device-tree for each PRU core, and the firmwares are expected > to be present in the standard Linux firmware search paths. They can > also be adjusted by userspace if required through the sysfs interface > provided by the remoteproc core. > > The PRU remoteproc driver uses a client-driven boot methodology: it > does _not_ support auto-boot so that the PRU load and boot is dictated > by the corresponding client drivers for achieving various usecases. > This allows flexibility for the client drivers or applications to set > a firmware name (if needed) based on their desired functionality and > boot the PRU. The sysfs bind and unbind attributes have also been > suppressed so that the PRU devices cannot be unbound and thereby > shutdown a PRU from underneath a PRU client driver. > > The driver currently supports the AM335x, AM437x, AM57xx and 66AK2G > SoCs, and support for other TI SoCs will be added in subsequent > patches. > > Co-developed-by: Andrew F. Davis > Signed-off-by: Andrew F. Davis > Signed-off-by: Suman Anna > Co-developed-by: Grzegorz Jaszczyk > Signed-off-by: Grzegorz Jaszczyk > --- > drivers/remoteproc/Kconfig | 12 + > drivers/remoteproc/Makefile | 1 + > drivers/remoteproc/pru_rproc.c | 428 +++++++++++++++++++++++++++++++++ > 3 files changed, 441 insertions(+) > create mode 100644 drivers/remoteproc/pru_rproc.c > > diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig > index d99548fb5dde..3e3865a7cd78 100644 > --- a/drivers/remoteproc/Kconfig > +++ b/drivers/remoteproc/Kconfig > @@ -125,6 +125,18 @@ config KEYSTONE_REMOTEPROC > It's safe to say N here if you're not interested in the Keystone > DSPs or just want to use a bare minimum kernel. > > +config PRU_REMOTEPROC > + tristate "TI PRU remoteproc support" > + depends on TI_PRUSS > + default TI_PRUSS > + help > + Support for TI PRU remote processors present within a PRU-ICSS > + subsystem via the remote processor framework. > + > + Say Y or M here to support the Programmable Realtime Unit (PRU) > + processors on various TI SoCs. It's safe to say N here if you're > + not interested in the PRU or if you are unsure. > + > config QCOM_PIL_INFO > tristate > > diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile > index da2ace4ec86c..bb26c9e4ef9c 100644 > --- a/drivers/remoteproc/Makefile > +++ b/drivers/remoteproc/Makefile > @@ -18,6 +18,7 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o > obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o > obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o > obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o > +obj-$(CONFIG_PRU_REMOTEPROC) += pru_rproc.o > obj-$(CONFIG_QCOM_PIL_INFO) += qcom_pil_info.o > obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o > obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o > diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c > new file mode 100644 > index 000000000000..c94c8e965c21 > --- /dev/null > +++ b/drivers/remoteproc/pru_rproc.c > @@ -0,0 +1,428 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * PRU-ICSS remoteproc driver for various TI SoCs > + * > + * Copyright (C) 2014-2020 Texas Instruments Incorporated - https://www.ti.com/ > + * > + * Author(s): > + * Suman Anna > + * Andrew F. Davis > + * Grzegorz Jaszczyk for Texas Instruments > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "remoteproc_internal.h" > +#include "remoteproc_elf_helpers.h" > + > +/* PRU_ICSS_PRU_CTRL registers */ > +#define PRU_CTRL_CTRL 0x0000 > +#define PRU_CTRL_STS 0x0004 > + > +/* CTRL register bit-fields */ > +#define CTRL_CTRL_SOFT_RST_N BIT(0) > +#define CTRL_CTRL_EN BIT(1) > +#define CTRL_CTRL_SLEEPING BIT(2) > +#define CTRL_CTRL_CTR_EN BIT(3) > +#define CTRL_CTRL_SINGLE_STEP BIT(8) > +#define CTRL_CTRL_RUNSTATE BIT(15) > + > +/* PRU Core IRAM address masks */ > +#define PRU0_IRAM_ADDR_MASK 0x34000 > +#define PRU1_IRAM_ADDR_MASK 0x38000 > + > +/* PRU device addresses for various type of PRU RAMs */ > +#define PRU_IRAM_DA 0 /* Instruction RAM */ > +#define PRU_PDRAM_DA 0 /* Primary Data RAM */ > +#define PRU_SDRAM_DA 0x2000 /* Secondary Data RAM */ > +#define PRU_SHRDRAM_DA 0x10000 /* Shared Data RAM */ > + > +/** > + * enum pru_iomem - PRU core memory/register range identifiers > + * > + * @PRU_IOMEM_IRAM: PRU Instruction RAM range > + * @PRU_IOMEM_CTRL: PRU Control register range > + * @PRU_IOMEM_DEBUG: PRU Debug register range > + * @PRU_IOMEM_MAX: just keep this one at the end > + */ > +enum pru_iomem { > + PRU_IOMEM_IRAM = 0, > + PRU_IOMEM_CTRL, > + PRU_IOMEM_DEBUG, > + PRU_IOMEM_MAX, > +}; > + > +/** > + * struct pru_rproc - PRU remoteproc structure > + * @id: id of the PRU core within the PRUSS > + * @dev: PRU core device pointer > + * @pruss: back-reference to parent PRUSS structure > + * @rproc: remoteproc pointer for this PRU core > + * @mem_regions: data for each of the PRU memory regions > + * @fw_name: name of firmware image used during loading > + */ > +struct pru_rproc { > + int id; > + struct device *dev; > + struct pruss *pruss; > + struct rproc *rproc; > + struct pruss_mem_region mem_regions[PRU_IOMEM_MAX]; > + const char *fw_name; > +}; > + > +static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int reg) > +{ > + return readl_relaxed(pru->mem_regions[PRU_IOMEM_CTRL].va + reg); > +} > + > +static inline > +void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val) > +{ > + writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); > +} > + > +static int pru_rproc_start(struct rproc *rproc) > +{ > + struct device *dev = &rproc->dev; > + struct pru_rproc *pru = rproc->priv; > + u32 val; > + > + dev_dbg(dev, "starting PRU%d: entry-point = 0x%llx\n", > + pru->id, (rproc->bootaddr >> 2)); > + > + val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16); > + pru_control_write_reg(pru, PRU_CTRL_CTRL, val); > + > + return 0; > +} > + > +static int pru_rproc_stop(struct rproc *rproc) > +{ > + struct device *dev = &rproc->dev; > + struct pru_rproc *pru = rproc->priv; > + u32 val; > + > + dev_dbg(dev, "stopping PRU%d\n", pru->id); > + > + val = pru_control_read_reg(pru, PRU_CTRL_CTRL); > + val &= ~CTRL_CTRL_EN; > + pru_control_write_reg(pru, PRU_CTRL_CTRL, val); > + > + return 0; > +} > + > +/* > + * Convert PRU device address (data spaces only) to kernel virtual address. > + * > + * Each PRU has access to all data memories within the PRUSS, accessible at > + * different ranges. So, look through both its primary and secondary Data > + * RAMs as well as any shared Data RAM to convert a PRU device address to > + * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data > + * RAM1 is primary Data RAM for PRU1. > + */ > +static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len) The .da_to_va() ops argument has changed to using size_t in recent kernels, so let's convert the type from int to size_t for the len argument. > +{ > + struct pruss_mem_region dram0, dram1, shrd_ram; > + struct pruss *pruss = pru->pruss; > + u32 offset; > + void *va = NULL; > + > + if (len <= 0) > + return NULL; And we adjust this accordingly. > + > + dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0]; > + dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1]; > + /* PRU1 has its local RAM addresses reversed */ > + if (pru->id == 1) > + swap(dram0, dram1); > + shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2]; > + > + if (da >= PRU_PDRAM_DA && da + len <= PRU_PDRAM_DA + dram0.size) { > + offset = da - PRU_PDRAM_DA; > + va = (__force void *)(dram0.va + offset); > + } else if (da >= PRU_SDRAM_DA && > + da + len <= PRU_SDRAM_DA + dram1.size) { > + offset = da - PRU_SDRAM_DA; > + va = (__force void *)(dram1.va + offset); > + } else if (da >= PRU_SHRDRAM_DA && > + da + len <= PRU_SHRDRAM_DA + shrd_ram.size) { > + offset = da - PRU_SHRDRAM_DA; > + va = (__force void *)(shrd_ram.va + offset); > + } > + > + return va; > +} > + > +/* > + * Convert PRU device address (instruction space) to kernel virtual address. > + * > + * A PRU does not have an unified address space. Each PRU has its very own > + * private Instruction RAM, and its device address is identical to that of > + * its primary Data RAM device address. > + */ > +static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, int len) > +{ > + u32 offset; > + void *va = NULL; > + > + if (len <= 0) > + return NULL; Same comments as above. > + > + if (da >= PRU_IRAM_DA && > + da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) { > + offset = da - PRU_IRAM_DA; > + va = (__force void *)(pru->mem_regions[PRU_IOMEM_IRAM].va + > + offset); > + } > + > + return va; > +} > + > +/* > + * Provide address translations for only PRU Data RAMs through the remoteproc > + * core for any PRU client drivers. The PRU Instruction RAM access is restricted > + * only to the PRU loader code. > + */ > +static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) > +{ > + struct pru_rproc *pru = rproc->priv; > + > + return pru_d_da_to_va(pru, da, len); > +} > + > +/* PRU-specific address translator used by PRU loader. */ > +static void *pru_da_to_va(struct rproc *rproc, u64 da, int len, bool is_iram) > +{ > + struct pru_rproc *pru = rproc->priv; > + void *va; > + > + if (is_iram) > + va = pru_i_da_to_va(pru, da, len); > + else > + va = pru_d_da_to_va(pru, da, len); > + > + return va; > +} > + > +static struct rproc_ops pru_rproc_ops = { > + .start = pru_rproc_start, > + .stop = pru_rproc_stop, > + .da_to_va = pru_rproc_da_to_va, > +}; > + > +static int > +pru_rproc_load_elf_segments(struct rproc *rproc, const struct firmware *fw) > +{ > + struct device *dev = &rproc->dev; > + struct elf32_hdr *ehdr; > + struct elf32_phdr *phdr; > + int i, ret = 0; > + const u8 *elf_data = fw->data; > + > + ehdr = (struct elf32_hdr *)elf_data; > + phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); > + > + /* go through the available ELF segments */ > + for (i = 0; i < ehdr->e_phnum; i++, phdr++) { > + u32 da = phdr->p_paddr; > + u32 memsz = phdr->p_memsz; > + u32 filesz = phdr->p_filesz; > + u32 offset = phdr->p_offset; > + bool is_iram; > + void *ptr; > + > + if (phdr->p_type != PT_LOAD) > + continue; > + > + dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", > + phdr->p_type, da, memsz, filesz); > + > + if (filesz > memsz) { > + dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", > + filesz, memsz); > + ret = -EINVAL; > + break; > + } > + > + if (offset + filesz > fw->size) { > + dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", > + offset + filesz, fw->size); > + ret = -EINVAL; > + break; > + } > + > + /* grab the kernel address for this device address */ > + is_iram = phdr->p_flags & PF_X; > + ptr = pru_da_to_va(rproc, da, memsz, is_iram); > + if (!ptr) { > + dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); > + ret = -EINVAL; > + break; > + } > + > + /* skip the memzero logic performed by remoteproc ELF loader */ > + if (!phdr->p_filesz) > + continue; > + > + memcpy(ptr, elf_data + phdr->p_offset, filesz); > + } > + > + return ret; > +} > + > +static int pru_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) > +{ > + int ret; > + > + /* load optional rsc table */ > + ret = rproc_elf_load_rsc_table(rproc, fw); > + if (ret == -EINVAL) > + dev_dbg(&rproc->dev, "no resource table found for this fw\n"); > + > + return ret; This should return 0 if there is no resource table, otherwise this fails. You have this corrected in Patch 3, but please move that logic here. > +} > + > +/* > + * Compute PRU id based on the IRAM addresses. The PRU IRAMs are > + * always at a particular offset within the PRUSS address space. > + */ > +static int pru_rproc_set_id(struct pru_rproc *pru) > +{ > + int ret = 0; > + > + switch (pru->mem_regions[PRU_IOMEM_IRAM].pa & 0x3ffff) { We can probably update this to use a macro for 0x3fffff. regards Suman > + case PRU0_IRAM_ADDR_MASK: > + pru->id = 0; > + break; > + case PRU1_IRAM_ADDR_MASK: > + pru->id = 1; > + break; > + default: > + ret = -EINVAL; > + } > + > + return ret; > +} > + > +static int pru_rproc_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + struct platform_device *ppdev = to_platform_device(dev->parent); > + struct pru_rproc *pru; > + const char *fw_name; > + struct rproc *rproc = NULL; > + struct resource *res; > + int i, ret; > + const char *mem_names[PRU_IOMEM_MAX] = { "iram", "control", "debug" }; > + > + ret = of_property_read_string(np, "firmware-name", &fw_name); > + if (ret) { > + dev_err(dev, "unable to retrieve firmware-name %d\n", ret); > + return ret; > + } > + > + rproc = devm_rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name, > + sizeof(*pru)); > + if (!rproc) { > + dev_err(dev, "rproc_alloc failed\n"); > + return -ENOMEM; > + } > + /* use a custom load function to deal with PRU-specific quirks */ > + rproc->ops->load = pru_rproc_load_elf_segments; > + > + /* use a custom parse function to deal with PRU-specific resources */ > + rproc->ops->parse_fw = pru_rproc_parse_fw; > + > + /* error recovery is not supported for PRUs */ > + rproc->recovery_disabled = true; > + > + /* > + * rproc_add will auto-boot the processor normally, but this is not > + * desired with PRU client driven boot-flow methodology. A PRU > + * application/client driver will boot the corresponding PRU > + * remote-processor as part of its state machine either through the > + * remoteproc sysfs interface or through the equivalent kernel API. > + */ > + rproc->auto_boot = false; > + > + pru = rproc->priv; > + pru->dev = dev; > + pru->pruss = platform_get_drvdata(ppdev); > + pru->rproc = rproc; > + pru->fw_name = fw_name; > + > + for (i = 0; i < ARRAY_SIZE(mem_names); i++) { > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, > + mem_names[i]); > + pru->mem_regions[i].va = devm_ioremap_resource(dev, res); > + if (IS_ERR(pru->mem_regions[i].va)) { > + dev_err(dev, "failed to parse and map memory resource %d %s\n", > + i, mem_names[i]); > + ret = PTR_ERR(pru->mem_regions[i].va); > + return ret; > + } > + pru->mem_regions[i].pa = res->start; > + pru->mem_regions[i].size = resource_size(res); > + > + dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", > + mem_names[i], &pru->mem_regions[i].pa, > + pru->mem_regions[i].size, pru->mem_regions[i].va); > + } > + > + ret = pru_rproc_set_id(pru); > + if (ret < 0) > + return ret; > + > + platform_set_drvdata(pdev, rproc); > + > + ret = devm_rproc_add(dev, pru->rproc); > + if (ret) { > + dev_err(dev, "rproc_add failed: %d\n", ret); > + return ret; > + } > + > + dev_dbg(dev, "PRU rproc node %pOF probed successfully\n", np); > + > + return 0; > +} > + > +static int pru_rproc_remove(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct rproc *rproc = platform_get_drvdata(pdev); > + > + dev_dbg(dev, "%s: removing rproc %s\n", __func__, rproc->name); > + > + return 0; > +} > + > +static const struct of_device_id pru_rproc_match[] = { > + { .compatible = "ti,am3356-pru", }, > + { .compatible = "ti,am4376-pru", }, > + { .compatible = "ti,am5728-pru", }, > + { .compatible = "ti,k2g-pru", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, pru_rproc_match); > + > +static struct platform_driver pru_rproc_driver = { > + .driver = { > + .name = "pru-rproc", > + .of_match_table = pru_rproc_match, > + .suppress_bind_attrs = true, > + }, > + .probe = pru_rproc_probe, > + .remove = pru_rproc_remove, > +}; > +module_platform_driver(pru_rproc_driver); > + > +MODULE_AUTHOR("Suman Anna "); > +MODULE_AUTHOR("Andrew F. Davis "); > +MODULE_AUTHOR("Grzegorz Jaszczyk "); > +MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver"); > +MODULE_LICENSE("GPL v2"); > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F140EC2D0E4 for ; Tue, 17 Nov 2020 19:43:02 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 598642222E for ; Tue, 17 Nov 2020 19:43:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="DWaP5TBm"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=ti.com header.i=@ti.com header.b="X/2BbAve" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 598642222E Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:Date:Message-ID:From: References:To:Subject:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=Z1YsojgdVtFkVgamSgfVD921n3sfNqbQ7XqZJNsH6O8=; b=DWaP5TBmiZCn+/jUfKg1VCuxB oTOuaWRXdVMka6RQO0SqBsdIfWWIBgLN3xmMfsgTr1IYKa08EztqfzvbZIudw0JEdLdj22uunOprw QdQLRCv5rKOs/M5giaWHodQqTpNP3nTJOTpwCfhcVlVF/vK+1sFD7yk3THFJaQMLRGNsZBoK9msaa gJYaSLz9SdDoZafCaDFxhHrO5IoNBFe5IGvzHQjZQnANNiVOow6hAWDX5Ny4GqPxXY6UZ4TsW38+g Yon+ZtpmgyIVkFh+HUixwPU0fdJM86D8HR8AVkEUhHBW3txseadD+iNd4r1Y83ymSHkr7CD1U4zgw 3zP9PLhIg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kf6rF-0002B8-Ve; Tue, 17 Nov 2020 19:41:42 +0000 Received: from fllv0016.ext.ti.com ([198.47.19.142]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kf6rB-00029b-I7 for linux-arm-kernel@lists.infradead.org; Tue, 17 Nov 2020 19:41:39 +0000 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id 0AHJfV46052816; Tue, 17 Nov 2020 13:41:31 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1605642091; bh=x6eUH5rjsyfE9sQFowThR5PVN8Osc4d7zM3/s2ETbk0=; h=Subject:To:CC:References:From:Date:In-Reply-To; b=X/2BbAveTkEjQK5uYax1hWnC8JC8TY/haVEymLlGDofhKNjIc8xwR7NYXv3NJXV6p LQ3KccJAmuJvPGNVREO0OKT8sSPzMWFvbPaMHiYzwJ43xkgJQKVvSENxCUCZo51KHo APIUR/HC+/68h1plB1BIOZBYshI1Otvy7ENExem4= Received: from DLEE114.ent.ti.com (dlee114.ent.ti.com [157.170.170.25]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 0AHJfVxd095954 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 17 Nov 2020 13:41:31 -0600 Received: from DLEE103.ent.ti.com (157.170.170.33) by DLEE114.ent.ti.com (157.170.170.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1979.3; Tue, 17 Nov 2020 13:41:31 -0600 Received: from fllv0039.itg.ti.com (10.64.41.19) by DLEE103.ent.ti.com (157.170.170.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1979.3 via Frontend Transport; Tue, 17 Nov 2020 13:41:30 -0600 Received: from [10.250.38.244] (ileax41-snat.itg.ti.com [10.172.224.153]) by fllv0039.itg.ti.com (8.15.2/8.15.2) with ESMTP id 0AHJfUvX123354; Tue, 17 Nov 2020 13:41:30 -0600 Subject: Re: [PATCH 2/6] remoteproc/pru: Add a PRU remoteproc driver To: Grzegorz Jaszczyk , , , References: <20201114084613.13503-1-grzegorz.jaszczyk@linaro.org> <20201114084613.13503-3-grzegorz.jaszczyk@linaro.org> From: Suman Anna Message-ID: <19cfcc3f-6b7b-4073-9d0d-84ab3207658f@ti.com> Date: Tue, 17 Nov 2020 13:41:25 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <20201114084613.13503-3-grzegorz.jaszczyk@linaro.org> Content-Language: en-US X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201117_144137_768582_663954C0 X-CRM114-Status: GOOD ( 46.81 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, praneeth@ti.com, linux-remoteproc@vger.kernel.org, linux-kernel@vger.kernel.org, robh+dt@kernel.org, linux-omap@vger.kernel.org, lee.jones@linaro.org, linux-arm-kernel@lists.infradead.org, rogerq@ti.com Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Hi Greg, I have a few minor comments below.. On 11/14/20 2:46 AM, Grzegorz Jaszczyk wrote: > From: Suman Anna > > The Programmable Real-Time Unit Subsystem (PRUSS) consists of > dual 32-bit RISC cores (Programmable Real-Time Units, or PRUs) > for program execution. This patch adds a remoteproc platform > driver for managing the individual PRU RISC cores life cycle. > > The PRUs do not have a unified address space (have an Instruction > RAM and a primary Data RAM at both 0x0). The PRU remoteproc driver > therefore uses a custom remoteproc core ELF loader ops. The added > .da_to_va ops is only used to provide translations for the PRU > Data RAMs. This remoteproc driver does not have support for error > recovery and system suspend/resume features. Different compatibles > are used to allow providing scalability for instance-specific device > data if needed. The driver uses a default firmware-name retrieved > from device-tree for each PRU core, and the firmwares are expected > to be present in the standard Linux firmware search paths. They can > also be adjusted by userspace if required through the sysfs interface > provided by the remoteproc core. > > The PRU remoteproc driver uses a client-driven boot methodology: it > does _not_ support auto-boot so that the PRU load and boot is dictated > by the corresponding client drivers for achieving various usecases. > This allows flexibility for the client drivers or applications to set > a firmware name (if needed) based on their desired functionality and > boot the PRU. The sysfs bind and unbind attributes have also been > suppressed so that the PRU devices cannot be unbound and thereby > shutdown a PRU from underneath a PRU client driver. > > The driver currently supports the AM335x, AM437x, AM57xx and 66AK2G > SoCs, and support for other TI SoCs will be added in subsequent > patches. > > Co-developed-by: Andrew F. Davis > Signed-off-by: Andrew F. Davis > Signed-off-by: Suman Anna > Co-developed-by: Grzegorz Jaszczyk > Signed-off-by: Grzegorz Jaszczyk > --- > drivers/remoteproc/Kconfig | 12 + > drivers/remoteproc/Makefile | 1 + > drivers/remoteproc/pru_rproc.c | 428 +++++++++++++++++++++++++++++++++ > 3 files changed, 441 insertions(+) > create mode 100644 drivers/remoteproc/pru_rproc.c > > diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig > index d99548fb5dde..3e3865a7cd78 100644 > --- a/drivers/remoteproc/Kconfig > +++ b/drivers/remoteproc/Kconfig > @@ -125,6 +125,18 @@ config KEYSTONE_REMOTEPROC > It's safe to say N here if you're not interested in the Keystone > DSPs or just want to use a bare minimum kernel. > > +config PRU_REMOTEPROC > + tristate "TI PRU remoteproc support" > + depends on TI_PRUSS > + default TI_PRUSS > + help > + Support for TI PRU remote processors present within a PRU-ICSS > + subsystem via the remote processor framework. > + > + Say Y or M here to support the Programmable Realtime Unit (PRU) > + processors on various TI SoCs. It's safe to say N here if you're > + not interested in the PRU or if you are unsure. > + > config QCOM_PIL_INFO > tristate > > diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile > index da2ace4ec86c..bb26c9e4ef9c 100644 > --- a/drivers/remoteproc/Makefile > +++ b/drivers/remoteproc/Makefile > @@ -18,6 +18,7 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o > obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o > obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o > obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o > +obj-$(CONFIG_PRU_REMOTEPROC) += pru_rproc.o > obj-$(CONFIG_QCOM_PIL_INFO) += qcom_pil_info.o > obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o > obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o > diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c > new file mode 100644 > index 000000000000..c94c8e965c21 > --- /dev/null > +++ b/drivers/remoteproc/pru_rproc.c > @@ -0,0 +1,428 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * PRU-ICSS remoteproc driver for various TI SoCs > + * > + * Copyright (C) 2014-2020 Texas Instruments Incorporated - https://www.ti.com/ > + * > + * Author(s): > + * Suman Anna > + * Andrew F. Davis > + * Grzegorz Jaszczyk for Texas Instruments > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "remoteproc_internal.h" > +#include "remoteproc_elf_helpers.h" > + > +/* PRU_ICSS_PRU_CTRL registers */ > +#define PRU_CTRL_CTRL 0x0000 > +#define PRU_CTRL_STS 0x0004 > + > +/* CTRL register bit-fields */ > +#define CTRL_CTRL_SOFT_RST_N BIT(0) > +#define CTRL_CTRL_EN BIT(1) > +#define CTRL_CTRL_SLEEPING BIT(2) > +#define CTRL_CTRL_CTR_EN BIT(3) > +#define CTRL_CTRL_SINGLE_STEP BIT(8) > +#define CTRL_CTRL_RUNSTATE BIT(15) > + > +/* PRU Core IRAM address masks */ > +#define PRU0_IRAM_ADDR_MASK 0x34000 > +#define PRU1_IRAM_ADDR_MASK 0x38000 > + > +/* PRU device addresses for various type of PRU RAMs */ > +#define PRU_IRAM_DA 0 /* Instruction RAM */ > +#define PRU_PDRAM_DA 0 /* Primary Data RAM */ > +#define PRU_SDRAM_DA 0x2000 /* Secondary Data RAM */ > +#define PRU_SHRDRAM_DA 0x10000 /* Shared Data RAM */ > + > +/** > + * enum pru_iomem - PRU core memory/register range identifiers > + * > + * @PRU_IOMEM_IRAM: PRU Instruction RAM range > + * @PRU_IOMEM_CTRL: PRU Control register range > + * @PRU_IOMEM_DEBUG: PRU Debug register range > + * @PRU_IOMEM_MAX: just keep this one at the end > + */ > +enum pru_iomem { > + PRU_IOMEM_IRAM = 0, > + PRU_IOMEM_CTRL, > + PRU_IOMEM_DEBUG, > + PRU_IOMEM_MAX, > +}; > + > +/** > + * struct pru_rproc - PRU remoteproc structure > + * @id: id of the PRU core within the PRUSS > + * @dev: PRU core device pointer > + * @pruss: back-reference to parent PRUSS structure > + * @rproc: remoteproc pointer for this PRU core > + * @mem_regions: data for each of the PRU memory regions > + * @fw_name: name of firmware image used during loading > + */ > +struct pru_rproc { > + int id; > + struct device *dev; > + struct pruss *pruss; > + struct rproc *rproc; > + struct pruss_mem_region mem_regions[PRU_IOMEM_MAX]; > + const char *fw_name; > +}; > + > +static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int reg) > +{ > + return readl_relaxed(pru->mem_regions[PRU_IOMEM_CTRL].va + reg); > +} > + > +static inline > +void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val) > +{ > + writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); > +} > + > +static int pru_rproc_start(struct rproc *rproc) > +{ > + struct device *dev = &rproc->dev; > + struct pru_rproc *pru = rproc->priv; > + u32 val; > + > + dev_dbg(dev, "starting PRU%d: entry-point = 0x%llx\n", > + pru->id, (rproc->bootaddr >> 2)); > + > + val = CTRL_CTRL_EN | ((rproc->bootaddr >> 2) << 16); > + pru_control_write_reg(pru, PRU_CTRL_CTRL, val); > + > + return 0; > +} > + > +static int pru_rproc_stop(struct rproc *rproc) > +{ > + struct device *dev = &rproc->dev; > + struct pru_rproc *pru = rproc->priv; > + u32 val; > + > + dev_dbg(dev, "stopping PRU%d\n", pru->id); > + > + val = pru_control_read_reg(pru, PRU_CTRL_CTRL); > + val &= ~CTRL_CTRL_EN; > + pru_control_write_reg(pru, PRU_CTRL_CTRL, val); > + > + return 0; > +} > + > +/* > + * Convert PRU device address (data spaces only) to kernel virtual address. > + * > + * Each PRU has access to all data memories within the PRUSS, accessible at > + * different ranges. So, look through both its primary and secondary Data > + * RAMs as well as any shared Data RAM to convert a PRU device address to > + * kernel virtual address. Data RAM0 is primary Data RAM for PRU0 and Data > + * RAM1 is primary Data RAM for PRU1. > + */ > +static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, int len) The .da_to_va() ops argument has changed to using size_t in recent kernels, so let's convert the type from int to size_t for the len argument. > +{ > + struct pruss_mem_region dram0, dram1, shrd_ram; > + struct pruss *pruss = pru->pruss; > + u32 offset; > + void *va = NULL; > + > + if (len <= 0) > + return NULL; And we adjust this accordingly. > + > + dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0]; > + dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1]; > + /* PRU1 has its local RAM addresses reversed */ > + if (pru->id == 1) > + swap(dram0, dram1); > + shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2]; > + > + if (da >= PRU_PDRAM_DA && da + len <= PRU_PDRAM_DA + dram0.size) { > + offset = da - PRU_PDRAM_DA; > + va = (__force void *)(dram0.va + offset); > + } else if (da >= PRU_SDRAM_DA && > + da + len <= PRU_SDRAM_DA + dram1.size) { > + offset = da - PRU_SDRAM_DA; > + va = (__force void *)(dram1.va + offset); > + } else if (da >= PRU_SHRDRAM_DA && > + da + len <= PRU_SHRDRAM_DA + shrd_ram.size) { > + offset = da - PRU_SHRDRAM_DA; > + va = (__force void *)(shrd_ram.va + offset); > + } > + > + return va; > +} > + > +/* > + * Convert PRU device address (instruction space) to kernel virtual address. > + * > + * A PRU does not have an unified address space. Each PRU has its very own > + * private Instruction RAM, and its device address is identical to that of > + * its primary Data RAM device address. > + */ > +static void *pru_i_da_to_va(struct pru_rproc *pru, u32 da, int len) > +{ > + u32 offset; > + void *va = NULL; > + > + if (len <= 0) > + return NULL; Same comments as above. > + > + if (da >= PRU_IRAM_DA && > + da + len <= PRU_IRAM_DA + pru->mem_regions[PRU_IOMEM_IRAM].size) { > + offset = da - PRU_IRAM_DA; > + va = (__force void *)(pru->mem_regions[PRU_IOMEM_IRAM].va + > + offset); > + } > + > + return va; > +} > + > +/* > + * Provide address translations for only PRU Data RAMs through the remoteproc > + * core for any PRU client drivers. The PRU Instruction RAM access is restricted > + * only to the PRU loader code. > + */ > +static void *pru_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) > +{ > + struct pru_rproc *pru = rproc->priv; > + > + return pru_d_da_to_va(pru, da, len); > +} > + > +/* PRU-specific address translator used by PRU loader. */ > +static void *pru_da_to_va(struct rproc *rproc, u64 da, int len, bool is_iram) > +{ > + struct pru_rproc *pru = rproc->priv; > + void *va; > + > + if (is_iram) > + va = pru_i_da_to_va(pru, da, len); > + else > + va = pru_d_da_to_va(pru, da, len); > + > + return va; > +} > + > +static struct rproc_ops pru_rproc_ops = { > + .start = pru_rproc_start, > + .stop = pru_rproc_stop, > + .da_to_va = pru_rproc_da_to_va, > +}; > + > +static int > +pru_rproc_load_elf_segments(struct rproc *rproc, const struct firmware *fw) > +{ > + struct device *dev = &rproc->dev; > + struct elf32_hdr *ehdr; > + struct elf32_phdr *phdr; > + int i, ret = 0; > + const u8 *elf_data = fw->data; > + > + ehdr = (struct elf32_hdr *)elf_data; > + phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); > + > + /* go through the available ELF segments */ > + for (i = 0; i < ehdr->e_phnum; i++, phdr++) { > + u32 da = phdr->p_paddr; > + u32 memsz = phdr->p_memsz; > + u32 filesz = phdr->p_filesz; > + u32 offset = phdr->p_offset; > + bool is_iram; > + void *ptr; > + > + if (phdr->p_type != PT_LOAD) > + continue; > + > + dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", > + phdr->p_type, da, memsz, filesz); > + > + if (filesz > memsz) { > + dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", > + filesz, memsz); > + ret = -EINVAL; > + break; > + } > + > + if (offset + filesz > fw->size) { > + dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", > + offset + filesz, fw->size); > + ret = -EINVAL; > + break; > + } > + > + /* grab the kernel address for this device address */ > + is_iram = phdr->p_flags & PF_X; > + ptr = pru_da_to_va(rproc, da, memsz, is_iram); > + if (!ptr) { > + dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); > + ret = -EINVAL; > + break; > + } > + > + /* skip the memzero logic performed by remoteproc ELF loader */ > + if (!phdr->p_filesz) > + continue; > + > + memcpy(ptr, elf_data + phdr->p_offset, filesz); > + } > + > + return ret; > +} > + > +static int pru_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) > +{ > + int ret; > + > + /* load optional rsc table */ > + ret = rproc_elf_load_rsc_table(rproc, fw); > + if (ret == -EINVAL) > + dev_dbg(&rproc->dev, "no resource table found for this fw\n"); > + > + return ret; This should return 0 if there is no resource table, otherwise this fails. You have this corrected in Patch 3, but please move that logic here. > +} > + > +/* > + * Compute PRU id based on the IRAM addresses. The PRU IRAMs are > + * always at a particular offset within the PRUSS address space. > + */ > +static int pru_rproc_set_id(struct pru_rproc *pru) > +{ > + int ret = 0; > + > + switch (pru->mem_regions[PRU_IOMEM_IRAM].pa & 0x3ffff) { We can probably update this to use a macro for 0x3fffff. regards Suman > + case PRU0_IRAM_ADDR_MASK: > + pru->id = 0; > + break; > + case PRU1_IRAM_ADDR_MASK: > + pru->id = 1; > + break; > + default: > + ret = -EINVAL; > + } > + > + return ret; > +} > + > +static int pru_rproc_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + struct platform_device *ppdev = to_platform_device(dev->parent); > + struct pru_rproc *pru; > + const char *fw_name; > + struct rproc *rproc = NULL; > + struct resource *res; > + int i, ret; > + const char *mem_names[PRU_IOMEM_MAX] = { "iram", "control", "debug" }; > + > + ret = of_property_read_string(np, "firmware-name", &fw_name); > + if (ret) { > + dev_err(dev, "unable to retrieve firmware-name %d\n", ret); > + return ret; > + } > + > + rproc = devm_rproc_alloc(dev, pdev->name, &pru_rproc_ops, fw_name, > + sizeof(*pru)); > + if (!rproc) { > + dev_err(dev, "rproc_alloc failed\n"); > + return -ENOMEM; > + } > + /* use a custom load function to deal with PRU-specific quirks */ > + rproc->ops->load = pru_rproc_load_elf_segments; > + > + /* use a custom parse function to deal with PRU-specific resources */ > + rproc->ops->parse_fw = pru_rproc_parse_fw; > + > + /* error recovery is not supported for PRUs */ > + rproc->recovery_disabled = true; > + > + /* > + * rproc_add will auto-boot the processor normally, but this is not > + * desired with PRU client driven boot-flow methodology. A PRU > + * application/client driver will boot the corresponding PRU > + * remote-processor as part of its state machine either through the > + * remoteproc sysfs interface or through the equivalent kernel API. > + */ > + rproc->auto_boot = false; > + > + pru = rproc->priv; > + pru->dev = dev; > + pru->pruss = platform_get_drvdata(ppdev); > + pru->rproc = rproc; > + pru->fw_name = fw_name; > + > + for (i = 0; i < ARRAY_SIZE(mem_names); i++) { > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, > + mem_names[i]); > + pru->mem_regions[i].va = devm_ioremap_resource(dev, res); > + if (IS_ERR(pru->mem_regions[i].va)) { > + dev_err(dev, "failed to parse and map memory resource %d %s\n", > + i, mem_names[i]); > + ret = PTR_ERR(pru->mem_regions[i].va); > + return ret; > + } > + pru->mem_regions[i].pa = res->start; > + pru->mem_regions[i].size = resource_size(res); > + > + dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", > + mem_names[i], &pru->mem_regions[i].pa, > + pru->mem_regions[i].size, pru->mem_regions[i].va); > + } > + > + ret = pru_rproc_set_id(pru); > + if (ret < 0) > + return ret; > + > + platform_set_drvdata(pdev, rproc); > + > + ret = devm_rproc_add(dev, pru->rproc); > + if (ret) { > + dev_err(dev, "rproc_add failed: %d\n", ret); > + return ret; > + } > + > + dev_dbg(dev, "PRU rproc node %pOF probed successfully\n", np); > + > + return 0; > +} > + > +static int pru_rproc_remove(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct rproc *rproc = platform_get_drvdata(pdev); > + > + dev_dbg(dev, "%s: removing rproc %s\n", __func__, rproc->name); > + > + return 0; > +} > + > +static const struct of_device_id pru_rproc_match[] = { > + { .compatible = "ti,am3356-pru", }, > + { .compatible = "ti,am4376-pru", }, > + { .compatible = "ti,am5728-pru", }, > + { .compatible = "ti,k2g-pru", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, pru_rproc_match); > + > +static struct platform_driver pru_rproc_driver = { > + .driver = { > + .name = "pru-rproc", > + .of_match_table = pru_rproc_match, > + .suppress_bind_attrs = true, > + }, > + .probe = pru_rproc_probe, > + .remove = pru_rproc_remove, > +}; > +module_platform_driver(pru_rproc_driver); > + > +MODULE_AUTHOR("Suman Anna "); > +MODULE_AUTHOR("Andrew F. Davis "); > +MODULE_AUTHOR("Grzegorz Jaszczyk "); > +MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver"); > +MODULE_LICENSE("GPL v2"); > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel