DO NOT MERGE ux500-ion driver is provided as example. Define 2 CMA heaps, one on a specific CMA region reserved at boot time the other will use the default CMA region.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- arch/arm/mach-ux500/board-mop500.c | 64 +++++++++++++++++ drivers/gpu/ion/Kconfig | 5 ++ drivers/gpu/ion/Makefile | 1 + drivers/gpu/ion/ux500/Makefile | 1 + drivers/gpu/ion/ux500/ux500_ion.c | 134 ++++++++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+) create mode 100644 drivers/gpu/ion/ux500/Makefile create mode 100644 drivers/gpu/ion/ux500/ux500_ion.c
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 77d03c1..c91cd8f 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -30,6 +30,13 @@ #include <linux/gpio_keys.h> #include <linux/delay.h>
+#ifdef CONFIG_ION +#include <linux/ion.h> +#endif +#ifdef CONFIG_CMA +#include <linux/dma-contiguous.h> +#endif + #include <linux/of.h> #include <linux/of_platform.h>
@@ -54,6 +61,50 @@ #include "board-mop500.h" #include "board-mop500-regulators.h"
+#ifdef CONFIG_CMA +static u64 snowball_dmamask = DMA_BIT_MASK(32); + +static struct platform_device snowball_cma_device = { + .name = "snowball-cma-device", + .id = -1, + .dev = { + .dma_mask = &snowball_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = 0, +}; + +#ifdef CONFIG_ION +static struct ion_platform_heap snowball_ion_heaps[] = { + [0] = { + .type = ION_HEAP_TYPE_DMA, + .id = 0, + .name = "ion-cma-heap-1", + .priv = &snowball_cma_device.dev, + }, + [1] = { + .type = ION_HEAP_TYPE_DMA, + .id = 1, + .name = "ion-cma-heap-2", + }, +}; + +static struct ion_platform_data snowball_ion_data = { + .heaps = snowball_ion_heaps, + .nr = ARRAY_SIZE(snowball_ion_heaps), +}; + +static struct platform_device snowball_ion_device = { + .name = "ion-ux500", + .id = -1, + .dev = { + .platform_data = &snowball_ion_data, + }, + .num_resources = 0, +}; +#endif +#endif + static struct gpio_led snowball_led_array[] = { { .name = "user_led", @@ -607,8 +658,18 @@ static struct platform_device *snowball_platform_devs[] __initdata = { &snowball_key_dev, &snowball_sbnet_dev, &ab8500_device, +#ifdef CONFIG_ION + &snowball_ion_device, +#endif };
+#ifdef CONFIG_ION +static void __init mop500_reserve(void) +{ + dma_declare_contiguous(&snowball_cma_device.dev, (16 * SZ_1M), 0, 0); +} +#endif + static void __init mop500_init_machine(void) { struct device *parent = NULL; @@ -741,6 +802,9 @@ MACHINE_START(SNOWBALL, "Calao Systems Snowball platform") .timer = &ux500_timer, .handle_irq = gic_handle_irq, .init_machine = snowball_init_machine, +#ifdef CONFIG_ION + .reserve = mop500_reserve, +#endif MACHINE_END
#ifdef CONFIG_MACH_UX500_DT diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig index b5bfdb4..bfe572d 100644 --- a/drivers/gpu/ion/Kconfig +++ b/drivers/gpu/ion/Kconfig @@ -11,3 +11,8 @@ config ION_TEGRA help Choose this option if you wish to use ion on an nVidia Tegra.
+config ION_UX500 + tristate "Ion for ux500" + depends on ARCH_U8500 && ION + help + Choose this option if you wish to use ion on ux500 platforms. diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile index 32d3385..a7ea570 100644 --- a/drivers/gpu/ion/Makefile +++ b/drivers/gpu/ion/Makefile @@ -2,3 +2,4 @@ ion-driver-objs += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o obj-$(CONFIG_ION) += ion-driver.o obj-$(CONFIG_CMA) += ion_cma_heap.o obj-$(CONFIG_ION_TEGRA) += tegra/ +obj-$(CONFIG_ION_UX500) += ux500/ diff --git a/drivers/gpu/ion/ux500/Makefile b/drivers/gpu/ion/ux500/Makefile new file mode 100644 index 0000000..691c600 --- /dev/null +++ b/drivers/gpu/ion/ux500/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ION_UX500) += ux500_ion.o diff --git a/drivers/gpu/ion/ux500/ux500_ion.c b/drivers/gpu/ion/ux500/ux500_ion.c new file mode 100644 index 0000000..5d5cf77 --- /dev/null +++ b/drivers/gpu/ion/ux500/ux500_ion.c @@ -0,0 +1,134 @@ +/* + * drivers/gpu/ion/ux500/ux500_ion.c + * + * Copyright (C) Linaro 2012 + * Author: benjamin.gaignard@linaro.org for ST-Ericsson. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/err.h> +#include <linux/ion.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include "../ion_priv.h" + +struct ion_ux500_internal { + struct ion_device *ion_device; + int num_heaps; + struct ion_heap **heaps; +}; + +int ux500_ion_probe(struct platform_device *pdev) +{ + struct ion_platform_data *pdata = pdev->dev.platform_data; + struct ion_ux500_internal *ion_ux500; + int ret = 0; + int i; + + ion_ux500 = kzalloc(sizeof(struct ion_ux500_internal), GFP_KERNEL); + if (!ion_ux500) { + dev_err(&pdev->dev, "can't allocate memory\n"); + return -ENOMEM; + } + + ion_ux500->num_heaps = pdata->nr; + if (!ion_ux500->num_heaps) { + dev_err(&pdev->dev, "no heap defined\n"); + ret = -ENODEV; + goto release; + } + + ion_ux500->heaps = kzalloc(sizeof(struct ion_heap *) + * ion_ux500->num_heaps, GFP_KERNEL); + if (!ion_ux500->heaps) { + dev_err(&pdev->dev, "no memory for heaps\n"); + ret = -ENOMEM; + goto release; + } + + ion_ux500->ion_device = ion_device_create(NULL); + if (IS_ERR_OR_NULL(ion_ux500->ion_device)) { + dev_err(&pdev->dev, "failed to create ion device\n"); + ret = PTR_ERR(ion_ux500->ion_device); + goto release_heaps; + } + + /* create the heaps as specified in the board file */ + for (i = 0; i < ion_ux500->num_heaps; i++) { + struct ion_platform_heap *heap_data = &pdata->heaps[i]; + + ion_ux500->heaps[i] = ion_heap_create(heap_data); + + if (IS_ERR_OR_NULL(ion_ux500->heaps[i])) { + ret = PTR_ERR(ion_ux500->heaps[i]); + ion_ux500->heaps[i] = NULL; + dev_err(&pdev->dev, + "failed to create heap type %d id %d\n", + heap_data->type, heap_data->id); + goto destroy_heaps; + } + ion_device_add_heap(ion_ux500->ion_device, ion_ux500->heaps[i]); + } + + platform_set_drvdata(pdev, ion_ux500); + + return ret; + +destroy_heaps: + for (i = 0; i < ion_ux500->num_heaps; i++) + if (ion_ux500->heaps[i]) + ion_heap_destroy(ion_ux500->heaps[i]); + + ion_device_destroy(ion_ux500->ion_device); +release_heaps: + kfree(ion_ux500->heaps); +release: + kfree(ion_ux500); + return ret; +} + +int ux500_ion_remove(struct platform_device *pdev) +{ + struct ion_ux500_internal *ion_ux500 = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ion_ux500->num_heaps; i++) + if (ion_ux500->heaps[i]) + ion_heap_destroy(ion_ux500->heaps[i]); + + ion_device_destroy(ion_ux500->ion_device); + kfree(ion_ux500->heaps); + kfree(ion_ux500); + + return 0; +} + +static struct platform_driver ux500_ion_driver = { + .probe = ux500_ion_probe, + .remove = ux500_ion_remove, + .driver = { + .name = "ion-ux500", + } +}; + +static int __init ux500_ion_init(void) +{ + return platform_driver_register(&ux500_ion_driver); +} + +static void __exit ux500_ion_exit(void) +{ + platform_driver_unregister(&ux500_ion_driver); +} + +module_init(ux500_ion_init); +module_exit(ux500_ion_exit);