From patchwork Mon Aug 5 06:53:43 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 18764 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vb0-f72.google.com (mail-vb0-f72.google.com [209.85.212.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id CCD0F25E7C for ; Mon, 5 Aug 2013 06:54:42 +0000 (UTC) Received: by mail-vb0-f72.google.com with SMTP id f12sf3957065vbg.3 for ; Sun, 04 Aug 2013 23:54:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-beenthere:x-forwarded-to:x-forwarded-for:delivered-to:x-auditid :from:to:date:message-id:x-mailer:in-reply-to:references :x-brightmail-tracker:cc:subject:x-beenthere:x-mailman-version :precedence:list-id:list-unsubscribe:list-archive:list-post :list-help:list-subscribe:mime-version:errors-to:sender :x-gm-message-state:x-removed-original-auth:x-original-sender :x-original-authentication-results:mailing-list:x-google-group-id :content-type:content-transfer-encoding; bh=h0fMBxpDmCbAX5v9kv30vf9iWgm/O5ko033LSwdrtis=; b=ELhJuikkiRiydP/Gpj8LC/+SAs7TaVmTAg92ZihzdWkqh/0OF5/A/kyhRhzbRahWEB 0+HrbWJac+/ZCpQFy6ZLGIXBnCJBDBSplYN1X7wHkDf/02vGKD8j3QcIMRkqOOmu/vJM W3kkNJuaCTlwpi8E63HeQatyed1Kj5MWhE/J0wWzuJ7BiGdvtnUGi6xwuvoutuN+v9RY VWBcEVSIwrKJZbamOjdOh91zpFkA6a80DDX04ghJGQTBJuBNjgTCqy5LTmnYoz+BHn7A TQSoH8OhNbPC6yzscCO4sT5GPXMkfyd8ee6Zqo6q9f6LnbRDYenO/5my3W8ZoLhdpfxq EBAA== X-Received: by 10.236.169.196 with SMTP id n44mr8166631yhl.9.1375685682419; Sun, 04 Aug 2013 23:54:42 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.73.193 with SMTP id n1ls2579971qev.50.gmail; Sun, 04 Aug 2013 23:54:42 -0700 (PDT) X-Received: by 10.58.168.202 with SMTP id zy10mr5504765veb.23.1375685682311; Sun, 04 Aug 2013 23:54:42 -0700 (PDT) Received: from mail-ve0-f170.google.com (mail-ve0-f170.google.com [209.85.128.170]) by mx.google.com with ESMTPS id ya5si4701941vec.57.2013.08.04.23.54.42 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 04 Aug 2013 23:54:42 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.170 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.170; Received: by mail-ve0-f170.google.com with SMTP id 15so2701753vea.29 for ; Sun, 04 Aug 2013 23:54:42 -0700 (PDT) X-Received: by 10.52.26.76 with SMTP id j12mr502371vdg.48.1375685682137; Sun, 04 Aug 2013 23:54:42 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.221.11.8 with SMTP id pc8csp72234vcb; Sun, 4 Aug 2013 23:54:41 -0700 (PDT) X-Received: by 10.14.205.196 with SMTP id j44mr15409543eeo.96.1375685680494; Sun, 04 Aug 2013 23:54:40 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id e5si15116034eeg.162.2013.08.04.23.54.39 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Sun, 04 Aug 2013 23:54:40 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linaro-mm-sig-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1V6EgT-0001n7-Lt; Mon, 05 Aug 2013 06:54:25 +0000 Received: from mailout2.samsung.com ([203.254.224.25]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1V6EgR-0001mN-Dp for linaro-mm-sig@lists.linaro.org; Mon, 05 Aug 2013 06:54:23 +0000 Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MR100JAPPURLNB0@mailout2.samsung.com> for linaro-mm-sig@lists.linaro.org; Mon, 05 Aug 2013 15:54:33 +0900 (KST) X-AuditID: cbfee61b-b7efe6d000007b11-62-51ff4c29bf15 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 60.4E.31505.92C4FF15; Mon, 05 Aug 2013 15:54:33 +0900 (KST) Received: from localhost.localdomain ([106.116.147.30]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MR1001JGPTNTLG1@mmp1.samsung.com>; Mon, 05 Aug 2013 15:54:33 +0900 (KST) From: Marek Szyprowski To: linux-arm-kernel@lists.infradead.org, linaro-mm-sig@lists.linaro.org, devicetree@vger.kernel.org Date: Mon, 05 Aug 2013 08:53:43 +0200 Message-id: <1375685624-12103-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1375685624-12103-1-git-send-email-m.szyprowski@samsung.com> References: <1375685624-12103-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrBLMWRmVeSWpSXmKPExsVy+t9jAV1Nn/+BBr9b+Sz+TjrGbjH/yDlW i1dnNrJZnG16w26xvXMGu8WXKw+ZLDY9vsZqsfbIXXaLDS8PMlksON7CavFnupzFqeuf2Sy+ f/vGZvF3+yYWi8Nv2lkt1s94zeIg4PH71yRGj8t9vUweO2fdZffYvKTe4/a/x8weV040sXqs +/OKyaP/r4FH35ZVjB4/X+p4fN4kF8AdxWWTkpqTWZZapG+XwJWxrPM3U8HGtIr1sxYwNTA2 hnQxcnBICJhI9K8z7GLkBDLFJC7cW8/WxcjFISSwiFHiRkM3I4TTziTx6/QSZpAqNgFDia63 XWwgtohAmsSMVRtYQGxmgTYWiRcQtrBAmMSf1sfsIDaLgKpE7892MJtXwEPix+M2FojFChJz JtmAmJwCnhI3n2WCVAgBVSzoP8k2gZF3ASPDKkbR1ILkguKk9FwjveLE3OLSvHS95PzcTYzg 8H4mvYNxVYPFIUYBDkYlHl4F9v+BQqyJZcWVuYcYJTiYlUR42fv/BgrxpiRWVqUW5ccXleak Fh9ilOZgURLnPdhqHSgkkJ5YkpqdmlqQWgSTZeLglGpgFHnEHMq27tHd+v3iohPf9a1dLzXD oIfJ59Q7VdUvq7+8jKk6Xy3gouo7a+GVsL+mLc8OhiiXXTYW1573S/GbHr9D56ms6huyblNX b+JLFS/sr3qWfmahjdk9hktdou9uiqwUml7y0z6Rf8rD8Hwl+Xye4xuiOGIKI8xE126Rj73+ 8Kfl66AVSizFGYmGWsxFxYkAkUpdoGsCAAA= Cc: Arnd Bergmann , Tomasz Figa , Michal Nazarewicz , Grant Likely , Kyungmin Park , Rob Herring , Sylwester Nawrocki , Olof Johansson , Sascha Hauer Subject: [Linaro-mm-sig] [PATCH v4 3/4] drivers: of: add initialization code for dma reserved memory X-BeenThere: linaro-mm-sig@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: linaro-mm-sig-bounces@lists.linaro.org Sender: linaro-mm-sig-bounces@lists.linaro.org X-Gm-Message-State: ALoCoQko9hh2idS/hK8hho1smDuWs6wZFIwKiiIrEeg3BytcJT8igxN2Ken+of9Dz211pkkEaD6m X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: m.szyprowski@samsung.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.170 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Add device tree support for contiguous and reserved memory regions defined in device tree. Initialization is done in 2 steps. First, the memory is reserved, what happens very early when only flattened device tree is available. Then on device initialization the corresponding cma and reserved regions are assigned to each device structure. Signed-off-by: Marek Szyprowski Acked-by: Kyungmin Park --- Documentation/devicetree/bindings/memory.txt | 152 ++++++++++++++++++++++ drivers/of/Kconfig | 6 + drivers/of/Makefile | 1 + drivers/of/of_reserved_mem.c | 175 ++++++++++++++++++++++++++ include/asm-generic/dma-coherent.h | 6 + 5 files changed, 340 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory.txt create mode 100644 drivers/of/of_reserved_mem.c diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt new file mode 100644 index 0000000..4aece19 --- /dev/null +++ b/Documentation/devicetree/bindings/memory.txt @@ -0,0 +1,152 @@ +*** Memory binding *** + +The /memory node provides basic information about the address and size +of the physical memory. This node is usually filled or updated by the +bootloader, depending on the actual memory configuration of the given +hardware. + +The memory layout is described by the folllowing node: + +memory { + reg = <(baseaddr1) (size1) + (baseaddr2) (size2) + ... + (baseaddrN) (sizeN)>; +}; + +baseaddrX: the base address of the defined memory bank +sizeX: the size of the defined memory bank + +More than one memory bank can be defined. + + +*** Reserved memory regions *** + +In /memory/reserved-memory node one can create additional nodes +describing particular reserved (excluded from normal use) memory +regions. Such memory regions are usually designed for the special usage +by various device drivers. A good example are contiguous memory +allocations or memory sharing with other operating system on the same +hardware board. Those special memory regions might depend on the board +configuration and devices used on the target system. + +Parameters for each memory region can be encoded into the device tree +wit the following convention: + +[(label):] (name)@(address) { + compatible = "contiguous-memory-region", "reserved-memory-region"; + reg = <(address) (size)>; + (linux,contiguous-region); + (linux,default-contiguous-region); +}; + +label: label given to the defined region (optional) +name: an name given to the defined region +address: the base address of the defined region +size: the size of the memory region + +compatible: "contiguous-memory-region" - enables binding of this + region to Contiguous Memory Allocator (special region for + contiguous memory allocations, shared with movable system + memory, Linux kernel-specific), alternatively if + "reserved-memory-region" - compatibility is defined, given + region is assigned for exclusive usage for DMA transfers + +linux,default-contiguous-region: property indicating that the region + is the default region for all contiguous memory + allocations, Linux specific (optional) + +Each defined region must use unique name. It is optional to specify the +base address, so if one wants to use autoconfiguration of the base +address, he must specify the '0' as base address in the 'reg' property +and assign ann uniqe name to such regions. + + +*** Device node's properties *** + +Once the regions in the /memory/reserved-memory node are defined, they +can be assigned to device nodes to enable drivers for their special use. +The following properties are defined: + +dma-memory-region = <&phandle_to_defined_region>; + +This property indicates that the device driver should use the +memory region pointed by the given phandle. + + +*** Example *** + +This example defines a memory consisting of 4 memory banks. 3 contiguous +regions are defined for Linux kernel, one default of all device drivers +(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the +framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB) +and one for multimedia processing (labelled multimedia_mem, placed at +0x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000 +device for DMA memory allocations (Linux kernel drivers will use CMA is +available or dma-exclusive usage otherwise). 'multimedia_mem' is +assigned to scaller@12500000 and codec@12600000 devices for contiguous +memory allocations when CMA driver is enabled. + +The reason for creating a separate region for framebuffer device is to +match the framebuffer base address to the one configured by bootloader, +so once Linux kernel drivers starts no glitches on the displayed boot +logo appears. Scaller and codec drivers should share the memory +allocations. + +/ { + /* ... */ + memory { + reg = <0x40000000 0x10000000 + 0x50000000 0x10000000 + 0x60000000 0x10000000 + 0x70000000 0x10000000>; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + /* + * global autoconfigured region for contiguous allocations + * (used only with Contiguous Memory Allocator) + */ + contig_region@0 { + compatible = "contiguous-memory-region"; + reg = <0x0 0x4000000>; + linux,default-contiguous-region; + }; + + /* + * special region for framebuffer + */ + display_mem: region@78000000 { + compatible = "contiguous-memory-region", "reserved-memory-region"; + reg = <0x78000000 0x800000>; + }; + + /* + * special region for multimedia processing devices + */ + multimedia_mem: region@77000000 { + compatible = "contiguous-memory-region"; + reg = <0x77000000 0x4000000>; + }; + }; + }; + + /* ... */ + + fb0: fb@12300000 { + status = "okay"; + dma-memory-region = <&display_mem>; + }; + + scaller: scaller@12500000 { + status = "okay"; + dma-memory-region = <&multimedia_mem>; + }; + + codec: codec@12600000 { + status = "okay"; + dma-memory-region = <&multimedia_mem>; + }; +}; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 80e5c13..a83ab43 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -80,4 +80,10 @@ config OF_MTD depends on MTD def_bool y +config OF_RESERVED_MEM + depends on CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK) + def_bool y + help + Initialization code for DMA reserved memory + endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 1f9c0c4..e7e3322 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o obj-$(CONFIG_OF_PCI) += of_pci.o obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o obj-$(CONFIG_OF_MTD) += of_mtd.o +obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c new file mode 100644 index 0000000..d97fcdf --- /dev/null +++ b/drivers/of/of_reserved_mem.c @@ -0,0 +1,175 @@ +/* + * Device tree based initialization code for reserved memory. + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Author: Marek Szyprowski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License or (at your optional) any later version of the license. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_RESERVED_REGIONS 16 +struct reserved_mem { + phys_addr_t base; + unsigned long size; + struct cma *cma; + char name[32]; +}; +static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; +static int reserved_mem_count; + +static int __init reserved_mem_fdt_scan(unsigned long node, const char *uname, + int depth, void *data) +{ + phys_addr_t base, size; + int is_cma, is_reserved; + unsigned long len; + void *prop; + + is_cma = of_flat_dt_is_compatible(node, "contiguous-memory-region"); + is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region"); + + if (!is_reserved && !(is_cma && IS_ENABLED(CONFIG_CMA))) + return 0; + + prop = of_get_flat_dt_prop(node, "reg", &len); + if (!prop || (len != 2 * sizeof(unsigned long))) { + pr_err("Reserved mem: node %s, incorrect \"reg\" property\n", + uname); + return 0; + } + + if (sizeof(unsigned long) == 4) { + base = be32_to_cpu(((__be32 *)prop)[0]); + size = be32_to_cpu(((__be32 *)prop)[1]); + } else { + base = be64_to_cpu(((__be64 *)prop)[0]); + size = be64_to_cpu(((__be64 *)prop)[1]); + } + + pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n", + uname, (unsigned long)base, (unsigned long)size / SZ_1M); + + if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) + return -ENOMEM; + + reserved_mem[reserved_mem_count].base = base; + reserved_mem[reserved_mem_count].size = size; + strcpy(reserved_mem[reserved_mem_count].name, uname); + + if (IS_ENABLED(CONFIG_CMA) && is_cma) { + struct cma *cma; + if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) { + reserved_mem[reserved_mem_count].cma = cma; + reserved_mem_count++; + + if (of_get_flat_dt_prop(node, + "linux,default-contiguous-region", + NULL)) + dma_contiguous_set_default_area(cma); + } + } else if (is_reserved) { + if (memblock_remove(base, size) == 0) + reserved_mem_count++; + else + pr_err("Failed to reserve memory for %s\n", uname); + } + + return 0; +} + +static struct reserved_mem *get_dma_memory_region(struct device *dev) +{ + struct device_node *node; + const char *name; + int i; + + node = of_parse_phandle(dev->of_node, "dma-memory-region", 0); + if (!node) + return NULL; + + name = kbasename(node->full_name); + for (i = 0; i < reserved_mem_count; i++) + if (strcmp(name, reserved_mem[i].name) == 0) + return &reserved_mem[i]; + return NULL; +} + +static void reserved_mem_assign_device_from_dt(struct device *dev) +{ + struct reserved_mem *region = get_dma_memory_region(dev); + if (!region) + return; + + if (region->cma) { + dma_contiguous_add_device(dev, region->cma); + pr_info("Assigned CMA %s to %s device\n", region->name, + dev_name(dev)); + } else { + if (dma_declare_coherent_memory(dev, region->base, region->base, + region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0) + pr_info("Declared reserved memory %s to %s device\n", + region->name, dev_name(dev)); + } +} + +static void reserved_mem_release_device_from_dt(struct device *dev) +{ + struct reserved_mem *region = get_dma_memory_region(dev); + if (!region) + return; + if (!region->cma) + dma_release_declared_memory(dev); +} + +static int reserved_mem_device_init_notifier_call(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct device *dev = data; + if (event == BUS_NOTIFY_ADD_DEVICE && dev->of_node) + reserved_mem_assign_device_from_dt(dev); + else if (event == BUS_NOTIFY_DEL_DEVICE && dev->of_node) + reserved_mem_release_device_from_dt(dev); + return NOTIFY_DONE; +} + +static struct notifier_block reserved_mem_dev_init_nb = { + .notifier_call = reserved_mem_device_init_notifier_call, +}; + +static int __init reserved_mem_init_reserved_areas(void) +{ + bus_register_notifier(&platform_bus_type, &reserved_mem_dev_init_nb); + return 0; +} +core_initcall(reserved_mem_init_reserved_areas); + +/** + * dma_reserved_mem_reserve() - grab memory reserved for device exclusive use + * + * This function grabs memory from early allocator for device exclusive use + * defined in device tree structures. It should be called by arch specific code + * once the early allocator (memblock) has been activated and all other + * subsystems have already allocated/reserved memory. + */ +void __init dma_reserved_mem_of_reserve(void) +{ + of_scan_flat_dt_by_path("/memory/reserved-memory", + reserved_mem_fdt_scan, NULL); +} diff --git a/include/asm-generic/dma-coherent.h b/include/asm-generic/dma-coherent.h index 2be8a2d..06111d00 100644 --- a/include/asm-generic/dma-coherent.h +++ b/include/asm-generic/dma-coherent.h @@ -32,4 +32,10 @@ dma_mark_declared_memory_occupied(struct device *dev, #define dma_mmap_from_coherent(dev, vma, vaddr, order, ret) (0) #endif +#ifdef CONFIG_OF_RESERVED_MEM +void __init dma_reserved_mem_of_reserve(void); +#else +#define dma_reserved_mem_of_reserve() +#endif + #endif