[v6,4/4] add test/example driver for ux500 platform

Message ID 1340720293-21221-5-git-send-email-benjamin.gaignard@linaro.org
State New
Headers show

Commit Message

Benjamin Gaignard June 26, 2012, 2:18 p.m.
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

Patch

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);