From patchwork Tue Jun 21 07:18:28 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ohad Ben Cohen X-Patchwork-Id: 900212 X-Patchwork-Delegate: tony@atomide.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p5L7OZj2023053 for ; Tue, 21 Jun 2011 07:24:35 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755974Ab1FUHYA (ORCPT ); Tue, 21 Jun 2011 03:24:00 -0400 Received: from mail-wy0-f174.google.com ([74.125.82.174]:59375 "EHLO mail-wy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755749Ab1FUHWJ (ORCPT ); Tue, 21 Jun 2011 03:22:09 -0400 Received: by mail-wy0-f174.google.com with SMTP id 38so2173104wyb.19 for ; Tue, 21 Jun 2011 00:22:09 -0700 (PDT) Received: by 10.227.32.84 with SMTP id b20mr5873440wbd.105.1308640928810; Tue, 21 Jun 2011 00:22:08 -0700 (PDT) Received: from localhost.localdomain (46-116-119-47.bb.netvision.net.il [46.116.119.47]) by mx.google.com with ESMTPS id o19sm3767542wbh.38.2011.06.21.00.22.05 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 21 Jun 2011 00:22:07 -0700 (PDT) From: Ohad Ben-Cohen To: , , Cc: , Brian Swetland , Arnd Bergmann , Grant Likely , davinci-linux-open-source , Rusty Russell , "Guzman Lugo, Fernando" , Ohad Ben-Cohen Subject: [RFC 2/8] remoteproc: add omap implementation Date: Tue, 21 Jun 2011 10:18:28 +0300 Message-Id: <1308640714-17961-3-git-send-email-ohad@wizery.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1308640714-17961-1-git-send-email-ohad@wizery.com> References: <1308640714-17961-1-git-send-email-ohad@wizery.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Tue, 21 Jun 2011 07:24:35 +0000 (UTC) From: Guzman Lugo, Fernando Add remoteproc implementation for OMAP4, so we can load the M3 and DSP remote processors. Based on code by Hari Kanigeri While this code is functional, and works on OMAP4 & its M3's, it is still preliminary and going to substantially change: 1. Splitting physically contiguous regions to pages should happen inside the IOMMU API framework, and not here (so omap_rproc_map_unmap should go away). 2. IOMMU programming in general should go away too; it should be handled by generic code (preferably using the DMA mapping API), and not by an OMAP specific component. This patch depends on OMAP's IOMMU API migration, as posted here: https://lkml.org/lkml/2011/6/2/369 [ohad@wizery.com: commit log, generic iommu api migration, refactoring, cleanups] Signed-off-by: Guzman Lugo, Fernando Signed-off-by: Ohad Ben-Cohen --- arch/arm/plat-omap/include/plat/remoteproc.h | 41 +++++ drivers/remoteproc/Kconfig | 21 +++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/omap_remoteproc.c | 243 ++++++++++++++++++++++++++ 4 files changed, 306 insertions(+), 0 deletions(-) create mode 100644 arch/arm/plat-omap/include/plat/remoteproc.h create mode 100644 drivers/remoteproc/omap_remoteproc.c diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/arch/arm/plat-omap/include/plat/remoteproc.h new file mode 100644 index 0000000..6494570 --- /dev/null +++ b/arch/arm/plat-omap/include/plat/remoteproc.h @@ -0,0 +1,41 @@ +/* + * Remote Processor - omap-specific bits + * + * Copyright (C) 2011 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PLAT_REMOTEPROC_H +#define _PLAT_REMOTEPROC_H + +#include + +/* + * struct omap_rproc_pdata - omap remoteproc's platform data + * @name: the remoteproc's name, cannot exceed RPROC_MAX_NAME bytes + * @iommu_name: iommu device we're behind of + * @oh_name: omap hwmod device + * @oh_name_opt: optional, secondary omap hwmod device + * @firmware: name of firmware file to load + * @ops: start/stop rproc handlers + * @memory_maps: table of da-to-pa iommu memory maps + */ +struct omap_rproc_pdata { + const char *name; + const char *iommu_name; + const char *oh_name; + const char *oh_name_opt; + const char *firmware; + const struct rproc_ops *ops; + const struct rproc_mem_entry *memory_maps; +}; + +#endif /* _PLAT_REMOTEPROC_H */ diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index a60bb12..88421bd 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -5,3 +5,24 @@ # REMOTE_PROC gets selected by whoever wants it config REMOTE_PROC tristate + +# for tristate, either expose omap_device_* or pass it via pdata +config OMAP_REMOTE_PROC + bool "OMAP remoteproc support" + depends on ARCH_OMAP4 + select OMAP_IOMMU + select REMOTE_PROC + select OMAP_MBOX_FWK + default y + help + Say y here to support OMAP's remote processors (dual M3 + and DSP on OMAP4) via the remote processor framework. + + Currently only supported on OMAP4. + + Usually you want to say y here, in order to enable multimedia + use-cases to run on your platform (multimedia codecs are + offloaded to remote DSP processors using this framework). + + It's safe to say n here if you're not interested in multimedia + offloading or just want a bare minimum kernel. diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index d0f60c7..0198b1d 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_REMOTE_PROC) += remoteproc.o +obj-$(CONFIG_OMAP_REMOTE_PROC) += omap_remoteproc.o diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c new file mode 100644 index 0000000..91f7f11 --- /dev/null +++ b/drivers/remoteproc/omap_remoteproc.c @@ -0,0 +1,243 @@ +/* + * Remote processor machine-specific module for OMAP4 + * + * Copyright (C) 2011 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct omap_rproc_priv { + struct iommu_domain *domain; + struct device *iommu; +}; + +/* + * Map a physically contiguous memory region using biggest pages possible. + * TODO: this code should go away; it belongs in the generic IOMMU layer + */ +static int omap_rproc_map_unmap(struct iommu_domain *domain, + const struct rproc_mem_entry *me, bool map) +{ + u32 all_bits; + /* these are the page sizes supported by OMAP's IOMMU */ + u32 pg_size[] = {SZ_16M, SZ_1M, SZ_64K, SZ_4K}; + int i, ret, size = me->size; + u32 da = me->da; + u32 pa = me->pa; + int order; + int flags; + + /* must be aligned at least with the smallest supported iommu page */ + if (!IS_ALIGNED(size, SZ_4K) || !IS_ALIGNED(da | pa, SZ_4K)) { + pr_err("misaligned: size %x da 0x%x pa 0x%x\n", size, da, pa); + return -EINVAL; + } + + while (size) { + /* find the max page size with which both pa, da are aligned */ + all_bits = pa | da; + for (i = 0; i < ARRAY_SIZE(pg_size); i++) { + if ((size >= pg_size[i]) && + ((all_bits & (pg_size[i] - 1)) == 0)) { + break; + } + } + + order = get_order(pg_size[i]); + + /* OMAP4's M3 is little endian, so no need for conversions */ + flags = MMU_RAM_ENDIAN_LITTLE | MMU_RAM_ELSZ_NONE; + + if (map) + ret = iommu_map(domain, da, pa, order, flags); + else + ret = iommu_unmap(domain, da, order); + + if (ret) + return ret; + + size -= pg_size[i]; + da += pg_size[i]; + pa += pg_size[i]; + } + + return 0; +} + +/* bootaddr isn't needed for the dual M3's */ +static inline int omap_rproc_start(struct rproc *rproc, u64 bootaddr) +{ + struct device *dev = rproc->dev; + struct platform_device *pdev = to_platform_device(dev); + struct omap_rproc_pdata *pdata = dev->platform_data; + struct iommu_domain *domain; + struct device *iommu; + struct omap_rproc_priv *priv; + int ret, i; + + if (!iommu_found()) { + dev_err(&pdev->dev, "iommu not found\n"); + return -ENODEV; + } + + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "kzalloc failed\n"); + return -ENOMEM; + } + + /* + * Use the specified iommu name to find our iommu device. + * TODO: solve this generically so other platforms can use it, too + */ + iommu = omap_find_iommu_device(pdata->iommu_name); + if (!iommu) { + dev_err(dev, "omap_find_iommu_device failed\n"); + ret = -ENODEV; + goto free_mem; + } + + domain = iommu_domain_alloc(); + if (!domain) { + dev_err(&pdev->dev, "can't alloc iommu domain\n"); + ret = -ENODEV; + goto free_mem; + } + + priv->iommu = iommu; + priv->domain = domain; + rproc->priv = priv; + + ret = iommu_attach_device(domain, iommu); + if (ret) { + dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret); + goto free_domain; + } + + for (i = 0; rproc->memory_maps[i].size; i++) { + const struct rproc_mem_entry *me = &rproc->memory_maps[i]; + + ret = omap_rproc_map_unmap(domain, me, true); + if (ret) { + dev_err(&pdev->dev, "iommu_map failed: %d\n", ret); + goto unmap_regions; + } + } + + /* power on the remote processor itself */ + ret = omap_device_enable(pdev); + if (ret) + goto unmap_regions; + + return 0; + +unmap_regions: + for (--i; i >= 0 && rproc->memory_maps[i].size; i--) { + const struct rproc_mem_entry *me = &rproc->memory_maps[i]; + omap_rproc_map_unmap(domain, me, false); + } +free_domain: + iommu_domain_free(domain); +free_mem: + kfree(priv); + return ret; +} + +static inline int omap_rproc_stop(struct rproc *rproc) +{ + struct device *dev = rproc->dev; + struct platform_device *pdev = to_platform_device(dev); + struct omap_rproc_priv *priv = rproc->priv; + struct iommu_domain *domain = priv->domain; + struct device *iommu = priv->iommu; + int ret, i; + + /* power off the remote processor itself */ + ret = omap_device_shutdown(pdev); + if (ret) { + dev_err(dev, "failed to shutdown: %d\n", ret); + goto out; + } + + for (i = 0; rproc->memory_maps[i].size; i++) { + const struct rproc_mem_entry *me = &rproc->memory_maps[i]; + + ret = omap_rproc_map_unmap(domain, me, false); + if (ret) { + dev_err(&pdev->dev, "iommu_unmap failed: %d\n", ret); + goto out; + } + } + + iommu_detach_device(domain, iommu); + iommu_domain_free(domain); + +out: + return ret; +} + +static struct rproc_ops omap_rproc_ops = { + .start = omap_rproc_start, + .stop = omap_rproc_stop, +}; + +static int omap_rproc_probe(struct platform_device *pdev) +{ + struct omap_rproc_pdata *pdata = pdev->dev.platform_data; + + return rproc_register(&pdev->dev, pdata->name, &omap_rproc_ops, + pdata->firmware, pdata->memory_maps, + THIS_MODULE); +} + +static int __devexit omap_rproc_remove(struct platform_device *pdev) +{ + struct omap_rproc_pdata *pdata = pdev->dev.platform_data; + + return rproc_unregister(pdata->name); +} + +static struct platform_driver omap_rproc_driver = { + .probe = omap_rproc_probe, + .remove = __devexit_p(omap_rproc_remove), + .driver = { + .name = "omap-rproc", + .owner = THIS_MODULE, + }, +}; + +static int __init omap_rproc_init(void) +{ + return platform_driver_register(&omap_rproc_driver); +} +/* must be ready in time for device_initcall users */ +subsys_initcall(omap_rproc_init); + +static void __exit omap_rproc_exit(void) +{ + platform_driver_unregister(&omap_rproc_driver); +} +module_exit(omap_rproc_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("OMAP Remote Processor control driver");