Hello,
This is another approach to finish support for reserved memory regions defined in device tree. Previous attempts (http://lists.linaro.org/pipermail/linaro-mm-sig/2014-February/003738.html and https://lkml.org/lkml/2014/7/14/108) ended in merging parts of the code and documentation. Merged patches allow to reserve memory, but there is still no reserved memory drivers nor any code that actually uses reserved memory regions.
The final conclusion from the above mentioned threads is that there is no automated reserved memory initialization. All drivers that want to use reserved memory, should initialize it on their own.
This patch series provides two driver for reserved memory regions (one based on CMA and one based on dma_coherent allocator). The main improvement comparing to the previous version is removal of automated reserved memory for every device and support for named memory regions.
Support for more than one reserved memory region can be considered as a separate DMA address space, so support for more than one region per device has been implemented the same way as support for separate IO/DMA address spaces in my Exynos IOMMU dma-mapping proposal: http://thread.gmane.org/gmane.linux.kernel.samsung-soc/36079
Best regards Marek Szyprowski Samsung R&D Institute Poland
Changes since '[PATCH v2 RESEND 0/4] CMA & device tree, once again' version: (https://lkml.org/lkml/2014/7/14/108) - added return error value to of_reserved_mem_device_init() - added support for named memory regions (so more than one region can be defined per device) - added usage example - converted custom reserved memory code used by s5p-mfc driver to the generic reserved memory handling code
Patch summary:
Marek Szyprowski (7): drivers: of: add return value to of_reserved_mem_device_init drivers: of: add support for named memory regions drivers: dma-coherent: add initialization from device tree drivers: dma-contiguous: add initialization from device tree media: s5p-mfc: replace custom reserved memory init code with generic one ARM: Exynos: convert MFC to generic reserved memory bindings ARM: DTS: exynos4412-odroid*: enable MFC device
.../devicetree/bindings/media/s5p-mfc.txt | 16 +-- .../bindings/reserved-memory/reserved-memory.txt | 6 +- arch/arm/boot/dts/exynos4210-origen.dts | 22 +++- arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 +++- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 24 ++++ arch/arm/boot/dts/exynos4412-origen.dts | 22 +++- arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 +++- arch/arm/boot/dts/exynos5250-arndale.dts | 22 +++- arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 +++- arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 +++- arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 +++- arch/arm/mach-exynos/exynos.c | 18 --- arch/arm/mach-exynos/mfc.h | 16 --- arch/arm/plat-samsung/Kconfig | 5 - arch/arm/plat-samsung/Makefile | 1 - arch/arm/plat-samsung/s5p-dev-mfc.c | 94 -------------- drivers/base/dma-coherent.c | 138 ++++++++++++++++++--- drivers/base/dma-contiguous.c | 71 +++++++++++ drivers/media/platform/s5p-mfc/s5p_mfc.c | 102 ++++++--------- drivers/of/of_reserved_mem.c | 102 ++++++++++----- include/linux/cma.h | 3 + include/linux/of_reserved_mem.h | 9 +- mm/cma.c | 62 +++++++-- 23 files changed, 552 insertions(+), 291 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/plat-samsung/s5p-dev-mfc.c
Driver calling of_reserved_mem_device_init() might be interested if the initialization has been successful or not, so add support for returning error code.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/of/of_reserved_mem.c | 3 ++- include/linux/of_reserved_mem.h | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 59fb12e84e6b..7e7de03585f9 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -243,7 +243,7 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) * This function assign memory region pointed by "memory-region" device tree * property to the given device. */ -void of_reserved_mem_device_init(struct device *dev) +int of_reserved_mem_device_init(struct device *dev) { struct reserved_mem *rmem; struct device_node *np; @@ -260,6 +260,7 @@ void of_reserved_mem_device_init(struct device *dev)
rmem->ops->device_init(rmem, dev); dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + return 0; }
/** diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index 5b5efae09135..ad2f67054372 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -16,7 +16,7 @@ struct reserved_mem { };
struct reserved_mem_ops { - void (*device_init)(struct reserved_mem *rmem, + int (*device_init)(struct reserved_mem *rmem, struct device *dev); void (*device_release)(struct reserved_mem *rmem, struct device *dev); @@ -28,14 +28,17 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
#ifdef CONFIG_OF_RESERVED_MEM -void of_reserved_mem_device_init(struct device *dev); +int of_reserved_mem_device_init(struct device *dev); void of_reserved_mem_device_release(struct device *dev);
void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); #else -static inline void of_reserved_mem_device_init(struct device *dev) { } +static inline int of_reserved_mem_device_init(struct device *dev) +{ + return -ENOSYS; +} static inline void of_reserved_mem_device_release(struct device *pdev) { }
static inline void fdt_init_reserved_mem(void) { }
This patch adds a code to initialize memory regions also for child devices if parent device has "memory-region" and "memory-region-names" device tree properties and given device's name matches "<parent_name>:<region_name>" template.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- .../bindings/reserved-memory/reserved-memory.txt | 6 +- drivers/of/of_reserved_mem.c | 101 ++++++++++++++------- 2 files changed, 74 insertions(+), 33 deletions(-)
diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt index 3da0ebdba8d9..69d28288ed37 100644 --- a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -73,7 +73,11 @@ Device node references to reserved memory Regions in the /reserved-memory node may be referenced by other device nodes by adding a memory-region property to the device node.
-memory-region (optional) - phandle, specifier pairs to children of /reserved-memory +memory-region (optional) - arrays of phandles, specifier pairs to children + of /reserved-memory, first phandle is used as a default memory + region +memory-region-names (optional) - array of strings with names of memory + regions, used when more than one region has been defined
Example ------- diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 7e7de03585f9..3ab9446ffa43 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -237,32 +237,82 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) return NULL; }
-/** - * of_reserved_mem_device_init() - assign reserved memory region to given device - * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. - */ -int of_reserved_mem_device_init(struct device *dev) +static int __rmem_dev_init(struct device *dev, struct device_node *np) { - struct reserved_mem *rmem; - struct device_node *np; - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return; - - rmem = __find_rmem(np); - of_node_put(np); - + struct reserved_mem *rmem = __find_rmem(np); if (!rmem || !rmem->ops || !rmem->ops->device_init) - return; + return -EINVAL;
rmem->ops->device_init(rmem, dev); dev_info(dev, "assigned reserved memory node %s\n", rmem->name); return 0; }
+static int __rmem_dev_release(struct device *dev, struct device_node *np) +{ + struct reserved_mem *rmem = __find_rmem(np); + if (!rmem || !rmem->ops) + return -EINVAL; + + if (rmem->ops->device_release) + rmem->ops->device_release(rmem, dev); + return 0; +} + +static int __rmem_dev_call(struct device *dev, + int (*func)(struct device *dev, struct device_node *np)) +{ + int ret = -ENODEV; + if (of_get_property(dev->of_node, "memory-region", NULL)) { + struct device_node *np; + np = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!np) + return -ENODEV; + ret = func(dev, np); + of_node_put(np); + } else if (dev->parent && + of_get_property(dev->parent->of_node, "memory-region", + NULL)) { + struct device *parent = dev->parent; + struct device_node *np; + char *name; + int idx; + + name = strrchr(dev_name(dev), ':'); + if (!name) + return -ENODEV; + name++; + + idx = of_property_match_string(parent->of_node, + "memory-region-names", name); + if (idx < 0) + return -ENODEV; + + np = of_parse_phandle(parent->of_node, "memory-region", idx); + if (!np) + return -ENODEV; + + ret = func(dev, np); + of_node_put(np); + } + return ret; +} + +/** + * of_reserved_mem_device_init() - assign reserved memory region to given device + * + * This function assigns default memory region pointed by first entry of + * "memory-region" device tree property (if available) to the given device or + * checks if the given device can be used to give access to named memory region + * if parent device has "memory-region" and "memory-region-names" device tree + * properties and given device's name matches "<parent_name>:<region_name>" + * template. + */ +int of_reserved_mem_device_init(struct device *dev) +{ + return __rmem_dev_call(dev, __rmem_dev_init); +} + /** * of_reserved_mem_device_release() - release reserved memory device structures * @@ -271,18 +321,5 @@ int of_reserved_mem_device_init(struct device *dev) */ void of_reserved_mem_device_release(struct device *dev) { - struct reserved_mem *rmem; - struct device_node *np; - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return; - - rmem = __find_rmem(np); - of_node_put(np); - - if (!rmem || !rmem->ops || !rmem->ops->device_release) - return; - - rmem->ops->device_release(rmem, dev); + __rmem_dev_call(dev, __rmem_dev_release); }
Initialization procedure of dma coherent pool has been split into two parts, so memory pool can now be initialized without assigning to particular struct device. Then initialized region can be assigned to more than one struct device. To protect from concurent allocations from different devices, a spinlock has been added to dma_coherent_mem structure. The last part of this patch adds support for handling 'shared-dma-pool' reserved-memory device tree nodes.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/base/dma-coherent.c | 138 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 119 insertions(+), 19 deletions(-)
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 7d6e84a51424..4e2dfcc16b70 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -14,11 +14,14 @@ struct dma_coherent_mem { int size; int flags; unsigned long *bitmap; + spinlock_t spinlock; };
-int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags) +static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr, + size_t size, int flags, + struct dma_coherent_mem **mem) { + struct dma_coherent_mem *dma_mem = NULL; void __iomem *mem_base = NULL; int pages = size >> PAGE_SHIFT; int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); @@ -27,27 +30,26 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, goto out; if (!size) goto out; - if (dev->dma_mem) - goto out; - - /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
mem_base = ioremap(phys_addr, size); if (!mem_base) goto out;
- dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); - if (!dev->dma_mem) + dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); + if (!dma_mem) goto out; - dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!dev->dma_mem->bitmap) + dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dma_mem->bitmap) goto free1_out;
- dev->dma_mem->virt_base = mem_base; - dev->dma_mem->device_base = device_addr; - dev->dma_mem->pfn_base = PFN_DOWN(phys_addr); - dev->dma_mem->size = pages; - dev->dma_mem->flags = flags; + dma_mem->virt_base = mem_base; + dma_mem->device_base = device_addr; + dma_mem->pfn_base = PFN_DOWN(phys_addr); + dma_mem->size = pages; + dma_mem->flags = flags; + spin_lock_init(&dma_mem->spinlock); + + *mem = dma_mem;
if (flags & DMA_MEMORY_MAP) return DMA_MEMORY_MAP; @@ -55,12 +57,51 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, return DMA_MEMORY_IO;
free1_out: - kfree(dev->dma_mem); + kfree(dma_mem); out: if (mem_base) iounmap(mem_base); return 0; } + +static void dma_release_coherent_memory(struct dma_coherent_mem *mem) +{ + if (!mem) + return; + iounmap(mem->virt_base); + kfree(mem->bitmap); + kfree(mem); +} + +static int dma_assign_coherent_memory(struct device *dev, + struct dma_coherent_mem *mem) +{ + if (dev->dma_mem) + return -EBUSY; + + dev->dma_mem = mem; + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + return 0; +} + +int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + struct dma_coherent_mem *mem; + int ret; + + ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags, + &mem); + if (ret == 0) + return 0; + + if (dma_assign_coherent_memory(dev, mem) == 0) + return ret; + + dma_release_coherent_memory(mem); + return 0; +} EXPORT_SYMBOL(dma_declare_coherent_memory);
void dma_release_declared_memory(struct device *dev) @@ -69,10 +110,8 @@ void dma_release_declared_memory(struct device *dev)
if (!mem) return; + dma_release_coherent_memory(mem); dev->dma_mem = NULL; - iounmap(mem->virt_base); - kfree(mem->bitmap); - kfree(mem); } EXPORT_SYMBOL(dma_release_declared_memory);
@@ -80,6 +119,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev, dma_addr_t device_addr, size_t size) { struct dma_coherent_mem *mem = dev->dma_mem; + unsigned long flags; int pos, err;
size += device_addr & ~PAGE_MASK; @@ -87,8 +127,11 @@ void *dma_mark_declared_memory_occupied(struct device *dev, if (!mem) return ERR_PTR(-EINVAL);
+ spin_lock_irqsave(&mem->spinlock, flags); pos = (device_addr - mem->device_base) >> PAGE_SHIFT; err = bitmap_allocate_region(mem->bitmap, pos, get_order(size)); + spin_unlock_irqrestore(&mem->spinlock, flags); + if (err != 0) return ERR_PTR(err); return mem->virt_base + (pos << PAGE_SHIFT); @@ -115,6 +158,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, { struct dma_coherent_mem *mem; int order = get_order(size); + unsigned long flags; int pageno;
if (!dev) @@ -124,6 +168,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, return 0;
*ret = NULL; + spin_lock_irqsave(&mem->spinlock, flags);
if (unlikely(size > (mem->size << PAGE_SHIFT))) goto err; @@ -138,10 +183,12 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, *dma_handle = mem->device_base + (pageno << PAGE_SHIFT); *ret = mem->virt_base + (pageno << PAGE_SHIFT); memset(*ret, 0, size); + spin_unlock_irqrestore(&mem->spinlock, flags);
return 1;
err: + spin_unlock_irqrestore(&mem->spinlock, flags); /* * In the case where the allocation can not be satisfied from the * per-device area, try to fall back to generic memory if the @@ -171,8 +218,11 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr) if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + unsigned long flags;
+ spin_lock_irqsave(&mem->spinlock, flags); bitmap_release_region(mem->bitmap, page, order); + spin_unlock_irqrestore(&mem->spinlock, flags); return 1; } return 0; @@ -218,3 +268,53 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, return 0; } EXPORT_SYMBOL(dma_mmap_from_coherent); + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/of_reserved_mem.h> + +static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev) +{ + struct dma_coherent_mem *mem = rmem->priv; + if (!mem && + dma_init_coherent_memory(rmem->base, rmem->base, rmem->size, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE, + &mem) != DMA_MEMORY_MAP) { + pr_info("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n", + &rmem->base, (unsigned long)rmem->size / SZ_1M); + return -ENODEV; + } + rmem->priv = mem; + dma_assign_coherent_memory(dev, mem); + return 0; +} + +static void rmem_dma_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dev->dma_mem = NULL; +} + +static const struct reserved_mem_ops rmem_dma_ops = { + .device_init = rmem_dma_device_init, + .device_release = rmem_dma_device_release, +}; + +static int __init rmem_dma_setup(struct reserved_mem *rmem) +{ + unsigned long node = rmem->fdt_node; + + if (of_get_flat_dt_prop(node, "reusable", NULL)) + return -EINVAL; + + rmem->ops = &rmem_dma_ops; + pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n", + &rmem->base, (unsigned long)rmem->size / SZ_1M); + return 0; +} +RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup); +#endif
Add a function to create CMA region from previously reserved memory and add support for handling 'shared-dma-pool' reserved-memory device tree nodes.
Based on previous code provided by Josh Cartwright joshc@codeaurora.org
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/base/dma-contiguous.c | 71 +++++++++++++++++++++++++++++++++++++++++++ include/linux/cma.h | 3 ++ mm/cma.c | 62 ++++++++++++++++++++++++++++++------- 3 files changed, 125 insertions(+), 11 deletions(-)
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 6606abdf880c..eefb81b85b42 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -211,3 +211,74 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages, { return cma_release(dev_get_cma_area(dev), pages, count); } + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/of_reserved_mem.h> + +#undef pr_fmt +#define pr_fmt(fmt) fmt + +static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev) +{ + struct cma *cma = rmem->priv; + if (!cma) + return -ENODEV; + + dev_set_cma_area(dev, cma); + return 0; +} + +static void rmem_cma_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dev_set_cma_area(dev, NULL); +} + +static const struct reserved_mem_ops rmem_cma_ops = { + .device_init = rmem_cma_device_init, + .device_release = rmem_cma_device_release, +}; + +static int __init rmem_cma_setup(struct reserved_mem *rmem) +{ + phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); + phys_addr_t mask = align - 1; + unsigned long node = rmem->fdt_node; + struct cma *cma; + int err; + + if (!of_get_flat_dt_prop(node, "reusable", NULL) || + of_get_flat_dt_prop(node, "no-map", NULL)) + return -EINVAL; + + if ((rmem->base & mask) || (rmem->size & mask)) { + pr_err("Reserved memory: incorrect alignment of CMA region\n"); + return -EINVAL; + } + + err = cma_init_reserved_mem(rmem->base, rmem->size, 0, &cma); + if (err) { + pr_err("Reserved memory: unable to setup CMA region\n"); + return err; + } + /* Architecture specific contiguous memory fixup. */ + dma_contiguous_early_fixup(rmem->base, rmem->size); + + if (of_get_flat_dt_prop(node, "linux,cma-default", NULL)) + dma_contiguous_set_default(cma); + + rmem->ops = &rmem_cma_ops; + rmem->priv = cma; + + pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n", + &rmem->base, (unsigned long)rmem->size / SZ_1M); + + return 0; +} +RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup); +#endif diff --git a/include/linux/cma.h b/include/linux/cma.h index 371b93042520..0430ed05d3b9 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -22,6 +22,9 @@ extern int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base, phys_addr_t limit, phys_addr_t alignment, unsigned int order_per_bit, bool fixed, struct cma **res_cma); +extern int cma_init_reserved_mem(phys_addr_t size, + phys_addr_t base, int order_per_bit, + struct cma **res_cma); extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align); extern bool cma_release(struct cma *cma, struct page *pages, int count); #endif diff --git a/mm/cma.c b/mm/cma.c index 4acc6aa4a086..d0065af4f000 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -141,6 +141,54 @@ static int __init cma_init_reserved_areas(void) core_initcall(cma_init_reserved_areas);
/** + * cma_init_reserved_mem() - create custom contiguous area from reserved memory + * @base: Base address of the reserved area + * @size: Size of the reserved area (in bytes), + * @order_per_bit: Order of pages represented by one bit on bitmap. + * @res_cma: Pointer to store the created cma region. + * + * This function creates custom contiguous area from already reserved memory. + */ +int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, + int order_per_bit, struct cma **res_cma) +{ + struct cma *cma; + phys_addr_t alignment; + + /* Sanity checks */ + if (cma_area_count == ARRAY_SIZE(cma_areas)) { + pr_err("Not enough slots for CMA reserved regions!\n"); + return -ENOSPC; + } + + if (!size || !memblock_is_region_reserved(base, size)) + return -EINVAL; + + /* ensure minimal alignment requied by mm core */ + alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); + + /* alignment should be aligned with order_per_bit */ + if (!IS_ALIGNED(alignment >> PAGE_SHIFT, 1 << order_per_bit)) + return -EINVAL; + + if (ALIGN(base, alignment) != base || ALIGN(size, alignment) != size) + return -EINVAL; + + /* + * Each reserved area must be initialised later, when more kernel + * subsystems (like slab allocator) are available. + */ + cma = &cma_areas[cma_area_count]; + cma->base_pfn = PFN_DOWN(base); + cma->count = size >> PAGE_SHIFT; + cma->order_per_bit = order_per_bit; + *res_cma = cma; + cma_area_count++; + + return 0; +} + +/** * cma_declare_contiguous() - reserve custom contiguous area * @base: Base address of the reserved area optional, use 0 for any * @size: Size of the reserved area (in bytes), @@ -163,7 +211,6 @@ int __init cma_declare_contiguous(phys_addr_t base, phys_addr_t alignment, unsigned int order_per_bit, bool fixed, struct cma **res_cma) { - struct cma *cma; phys_addr_t memblock_end = memblock_end_of_DRAM(); phys_addr_t highmem_start = __pa(high_memory); int ret = 0; @@ -235,16 +282,9 @@ int __init cma_declare_contiguous(phys_addr_t base, } }
- /* - * Each reserved area must be initialised later, when more kernel - * subsystems (like slab allocator) are available. - */ - cma = &cma_areas[cma_area_count]; - cma->base_pfn = PFN_DOWN(base); - cma->count = size >> PAGE_SHIFT; - cma->order_per_bit = order_per_bit; - *res_cma = cma; - cma_area_count++; + ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma); + if (ret) + goto err;
pr_info("Reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M, (unsigned long)base);
This patch removes custom initialization of reserved memory regions from s5p-mfc driver and adds a new code for handling reserved memory with generic named reserved memory regions read from device tree.
s5p-mfc driver now handles two reserved memory regions: "left" and "right", defined by generic reserved memory bindings. Support for non-dt platform has been removed, because all supported platforms have been converted to device tree.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 102 +++++++++++-------------------- 1 file changed, 35 insertions(+), 67 deletions(-)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d35b0418ab37..668e82247a3f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,6 +22,7 @@ #include <media/v4l2-event.h> #include <linux/workqueue.h> #include <linux/of.h> +#include <linux/of_reserved_mem.h> #include <media/videobuf2-core.h> #include "s5p_mfc_common.h" #include "s5p_mfc_ctrl.h" @@ -996,55 +997,40 @@ static const struct v4l2_file_operations s5p_mfc_fops = { .mmap = s5p_mfc_mmap, };
-static int match_child(struct device *dev, void *data) +static struct device *s5p_mfc_alloc_memdev(struct device *dev, const char *name) { - if (!dev_name(dev)) - return 0; - return !strcmp(dev_name(dev), (char *)data); -} - -static void *mfc_get_drv_data(struct platform_device *pdev); - -static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) -{ - unsigned int mem_info[2] = { }; + struct device *child; + int ret;
- dev->mem_dev_l = devm_kzalloc(&dev->plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_l) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_l); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-l", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_l, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - mfc_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; + child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL); + if (!child) + return NULL; + + device_initialize(child); + dev_set_name(child, "%s:%s", dev_name(dev), name); + child->parent = dev; + child->bus = dev->bus; + child->coherent_dma_mask = dev->coherent_dma_mask; + child->dma_mask = dev->dma_mask; + + if (device_add(child) == 0) { + ret = of_reserved_mem_device_init(child); + if (ret == 0) + return child; }
- dev->mem_dev_r = devm_kzalloc(&dev->plat_dev->dev, - sizeof(struct device), GFP_KERNEL); - if (!dev->mem_dev_r) { - mfc_err("Not enough memory\n"); - return -ENOMEM; - } - device_initialize(dev->mem_dev_r); - of_property_read_u32_array(dev->plat_dev->dev.of_node, - "samsung,mfc-r", mem_info, 2); - if (dma_declare_coherent_memory(dev->mem_dev_r, mem_info[0], - mem_info[0], mem_info[1], - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { - pr_err("Failed to declare coherent memory for\n" - "MFC device\n"); - return -ENOMEM; - } - return 0; + put_device(child); + return NULL; }
+void s5p_mfc_free_memdev(struct device *dev) +{ + of_reserved_mem_device_release(dev); + put_device(dev); +} + +static void *mfc_get_drv_data(struct platform_device *pdev); + /* MFC probe function */ static int s5p_mfc_probe(struct platform_device *pdev) { @@ -1096,26 +1082,8 @@ static int s5p_mfc_probe(struct platform_device *pdev) goto err_res; }
- if (pdev->dev.of_node) { - ret = s5p_mfc_alloc_memdevs(dev); - if (ret < 0) - goto err_res; - } else { - dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, - "s5p-mfc-l", match_child); - if (!dev->mem_dev_l) { - mfc_err("Mem child (L) device get failed\n"); - ret = -ENODEV; - goto err_res; - } - dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, - "s5p-mfc-r", match_child); - if (!dev->mem_dev_r) { - mfc_err("Mem child (R) device get failed\n"); - ret = -ENODEV; - goto err_res; - } - } + dev->mem_dev_l = s5p_mfc_alloc_memdev(&dev->plat_dev->dev, "left"); + dev->mem_dev_r = s5p_mfc_alloc_memdev(&dev->plat_dev->dev, "right");
dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); if (IS_ERR(dev->alloc_ctx[0])) { @@ -1246,10 +1214,10 @@ static int s5p_mfc_remove(struct platform_device *pdev) s5p_mfc_release_firmware(dev); vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]); vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]); - if (pdev->dev.of_node) { - put_device(dev->mem_dev_l); - put_device(dev->mem_dev_r); - } + if (dev->mem_dev_l) + s5p_mfc_free_memdev(dev->mem_dev_l); + if (dev->mem_dev_r) + s5p_mfc_free_memdev(dev->mem_dev_r);
s5p_mfc_final_pm(dev); return 0;
Support for reserved memory for MFC device (samsung,mfc-r and samsung,mfc-l properties) was merged quickly without any deep review and discussion. This patch replaces those custom properties with support for generic reserved memory bindings. All custom code for handling MFC-specific reserved memory can be now removed.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- .../devicetree/bindings/media/s5p-mfc.txt | 16 ++-- arch/arm/boot/dts/exynos4210-origen.dts | 22 ++++- arch/arm/boot/dts/exynos4210-smdkv310.dts | 22 ++++- arch/arm/boot/dts/exynos4412-origen.dts | 22 ++++- arch/arm/boot/dts/exynos4412-smdk4412.dts | 22 ++++- arch/arm/boot/dts/exynos5250-arndale.dts | 22 ++++- arch/arm/boot/dts/exynos5250-smdk5250.dts | 22 ++++- arch/arm/boot/dts/exynos5420-arndale-octa.dts | 22 ++++- arch/arm/boot/dts/exynos5420-smdk5420.dts | 22 ++++- arch/arm/mach-exynos/exynos.c | 18 ----- arch/arm/mach-exynos/mfc.h | 16 ---- arch/arm/plat-samsung/Kconfig | 5 -- arch/arm/plat-samsung/Makefile | 1 - arch/arm/plat-samsung/s5p-dev-mfc.c | 94 ---------------------- 14 files changed, 168 insertions(+), 158 deletions(-) delete mode 100644 arch/arm/mach-exynos/mfc.h delete mode 100644 arch/arm/plat-samsung/s5p-dev-mfc.c
diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 3e3c5f349570..468e991b322c 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -21,16 +21,16 @@ Required properties: - clock-names : from common clock binding: must contain "mfc", corresponding to entry in the clocks property.
- - samsung,mfc-r : Base address of the first memory bank used by MFC - for DMA contiguous memory allocation and its size. - - - samsung,mfc-l : Base address of the second memory bank used by MFC - for DMA contiguous memory allocation and its size. - Optional properties: - samsung,power-domain : power-domain property defined with a phandle to respective power domain.
+ - memory-region : from reserved memory binding: phandles to two reserved + memory regions: accessed by "left" and "right" mfc memory bus + interfaces, used when no SYSMMU support is available + - memory-region-names : from reserved memory binding: must be "left" + and "right" + Example: SoC specific DT entry:
@@ -46,6 +46,6 @@ mfc: codec@13400000 { Board specific DT entry:
codec@13400000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; }; diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index f767c425d0b5..face32952a36 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -29,6 +29,24 @@ 0x70000000 0x10000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; }; @@ -82,8 +100,8 @@ };
codec@13400000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; status = "okay"; };
diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts index 676e6e0c8cf3..292f2188d7b6 100644 --- a/arch/arm/boot/dts/exynos4210-smdkv310.dts +++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts @@ -25,6 +25,24 @@ reg = <0x40000000 0x80000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc"; }; @@ -41,8 +59,8 @@ };
codec@13400000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; status = "okay"; };
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts index e925c9fbfb07..d007b186c722 100644 --- a/arch/arm/boot/dts/exynos4412-origen.dts +++ b/arch/arm/boot/dts/exynos4412-origen.dts @@ -24,6 +24,24 @@ reg = <0x40000000 0x40000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs ="console=ttySAC2,115200"; }; @@ -151,8 +169,8 @@ };
codec@13400000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; status = "okay"; };
diff --git a/arch/arm/boot/dts/exynos4412-smdk4412.dts b/arch/arm/boot/dts/exynos4412-smdk4412.dts index ded0b70f7644..a1a25d2c999b 100644 --- a/arch/arm/boot/dts/exynos4412-smdk4412.dts +++ b/arch/arm/boot/dts/exynos4412-smdk4412.dts @@ -23,6 +23,24 @@ reg = <0x40000000 0x40000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc"; }; @@ -126,8 +144,8 @@ };
codec@13400000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; status = "okay"; };
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index d0de1f50d15b..c444b6a7cd47 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -22,6 +22,24 @@ reg = <0x40000000 0x80000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs = "console=ttySAC2,115200"; }; @@ -31,8 +49,8 @@ };
codec@11000000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; };
i2c@12C60000 { diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index b4b35adae565..f22e3c884449 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -23,6 +23,24 @@ reg = <0x40000000 0x80000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; }; @@ -350,8 +368,8 @@ };
codec@11000000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; };
i2s0: i2s@03830000 { diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts index 434fd9d3e09d..f237c0a98131 100644 --- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts +++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts @@ -22,6 +22,24 @@ reg = <0x20000000 0x80000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs = "console=ttySAC3,115200"; }; @@ -43,8 +61,8 @@ };
codec@11000000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; };
mmc@12200000 { diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index 6052aa9c5659..3cac4015b0c4 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -20,6 +20,24 @@ reg = <0x20000000 0x80000000>; };
+ reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; + }; + chosen { bootargs = "console=ttySAC2,115200 init=/linuxrc"; }; @@ -69,8 +87,8 @@ };
codec@11000000 { - samsung,mfc-r = <0x43000000 0x800000>; - samsung,mfc-l = <0x51000000 0x800000>; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; };
mmc@12200000 { diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 6a24e111d6e1..c20eb2bf6dbe 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -28,7 +28,6 @@ #include <asm/memory.h>
#include "common.h" -#include "mfc.h" #include "regs-pmu.h" #include "regs-sys.h"
@@ -340,22 +339,6 @@ static char const *exynos_dt_compat[] __initconst = { NULL };
-static void __init exynos_reserve(void) -{ -#ifdef CONFIG_S5P_DEV_MFC - int i; - char *mfc_mem[] = { - "samsung,mfc-v5", - "samsung,mfc-v6", - "samsung,mfc-v7", - }; - - for (i = 0; i < ARRAY_SIZE(mfc_mem); i++) - if (of_scan_flat_dt(s5p_fdt_alloc_mfc_mem, mfc_mem[i])) - break; -#endif -} - static void __init exynos_dt_fixup(void) { /* @@ -378,6 +361,5 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") .init_late = exynos_init_late, .dt_compat = exynos_dt_compat, .restart = exynos_restart, - .reserve = exynos_reserve, .dt_fixup = exynos_dt_fixup, MACHINE_END diff --git a/arch/arm/mach-exynos/mfc.h b/arch/arm/mach-exynos/mfc.h deleted file mode 100644 index dec93cd5b3c6..000000000000 --- a/arch/arm/mach-exynos/mfc.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2013 Samsung Electronics Co.Ltd - * - * 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 - * option) any later version. - */ - -#ifndef __MACH_EXYNOS_MFC_H -#define __MACH_EXYNOS_MFC_H __FILE__ - -int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname, - int depth, void *data); - -#endif /* __MACH_EXYNOS_MFC_H */ diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index c87aefbf3a13..8b0d53b76917 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -260,11 +260,6 @@ config SAMSUNG_DMADEV
endif
-config S5P_DEV_MFC - bool - help - Compile in setup memory (init) code for MFC - comment "Power management"
config SAMSUNG_PM_DEBUG diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 5fe175017f07..46561b66d9a0 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_SAMSUNG_ATAGS) += platformdata.o
obj-$(CONFIG_SAMSUNG_ATAGS) += devs.o obj-$(CONFIG_SAMSUNG_ATAGS) += dev-uart.o -obj-$(CONFIG_S5P_DEV_MFC) += s5p-dev-mfc.o
obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o
diff --git a/arch/arm/plat-samsung/s5p-dev-mfc.c b/arch/arm/plat-samsung/s5p-dev-mfc.c deleted file mode 100644 index 0b04b6b0fa30..000000000000 --- a/arch/arm/plat-samsung/s5p-dev-mfc.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd - * - * Base S5P MFC resource and device definitions - * - * 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. - */ - -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/memblock.h> -#include <linux/ioport.h> -#include <linux/of_fdt.h> -#include <linux/of.h> - -static struct platform_device s5p_device_mfc_l; -static struct platform_device s5p_device_mfc_r; - -struct s5p_mfc_dt_meminfo { - unsigned long loff; - unsigned long lsize; - unsigned long roff; - unsigned long rsize; - char *compatible; -}; - -struct s5p_mfc_reserved_mem { - phys_addr_t base; - unsigned long size; - struct device *dev; -}; - -static struct s5p_mfc_reserved_mem s5p_mfc_mem[2] __initdata; - - -static void __init s5p_mfc_reserve_mem(phys_addr_t rbase, unsigned int rsize, - phys_addr_t lbase, unsigned int lsize) -{ - int i; - - s5p_mfc_mem[0].dev = &s5p_device_mfc_r.dev; - s5p_mfc_mem[0].base = rbase; - s5p_mfc_mem[0].size = rsize; - - s5p_mfc_mem[1].dev = &s5p_device_mfc_l.dev; - s5p_mfc_mem[1].base = lbase; - s5p_mfc_mem[1].size = lsize; - - for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) { - struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i]; - if (memblock_remove(area->base, area->size)) { - printk(KERN_ERR "Failed to reserve memory for MFC device (%ld bytes at 0x%08lx)\n", - area->size, (unsigned long) area->base); - area->base = 0; - } - } -} - -int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname, - int depth, void *data) -{ - const __be32 *prop; - int len; - struct s5p_mfc_dt_meminfo mfc_mem; - - if (!data) - return 0; - - if (!of_flat_dt_is_compatible(node, data)) - return 0; - - prop = of_get_flat_dt_prop(node, "samsung,mfc-l", &len); - if (!prop || (len != 2 * sizeof(unsigned long))) - return 0; - - mfc_mem.loff = be32_to_cpu(prop[0]); - mfc_mem.lsize = be32_to_cpu(prop[1]); - - prop = of_get_flat_dt_prop(node, "samsung,mfc-r", &len); - if (!prop || (len != 2 * sizeof(unsigned long))) - return 0; - - mfc_mem.roff = be32_to_cpu(prop[0]); - mfc_mem.rsize = be32_to_cpu(prop[1]); - - s5p_mfc_reserve_mem(mfc_mem.roff, mfc_mem.rsize, - mfc_mem.loff, mfc_mem.lsize); - - return 1; -}
Enable support for Multimedia Codec (MFC) device for all Exynos4412-based Odroid boards.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index adadaf97ac01..3728c667e7ec 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -11,6 +11,24 @@ #include "exynos4412.dtsi"
/ { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@77000000 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x77000000 0x1000000>; + }; + + mfc_right: region@78000000 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x78000000 0x1000000>; + }; + }; + firmware@0204F000 { compatible = "samsung,secure-firmware"; reg = <0x0204F000 0x1000>; @@ -367,6 +385,12 @@ ehci: ehci@12580000 { status = "okay"; }; + + codec@13400000 { + status = "okay"; + memory-region = <&mfc_left>, <&mfc_right>; + memory-region-names = "left", "right"; + }; };
&pinctrl_1 {
linaro-mm-sig@lists.linaro.org