@@ -30,6 +30,11 @@
#include <linux/gpio_keys.h>
#include <linux/delay.h>
+#ifdef CONFIG_ION
+#include <linux/ion.h>
+#include <linux/dma-contiguous.h>
+#endif
+
#include <linux/leds.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -50,6 +55,62 @@
#include "board-mop500.h"
#include "board-mop500-regulators.h"
+#ifdef CONFIG_ION
+static u64 snowball_dmamask = DMA_BIT_MASK(32);
+
+static struct ion_platform_heap snowball_ion_heap1[] = {
+ [0] = {
+ .type = ION_HEAP_TYPE_DMA,
+ .id = 1,
+ .name = "ion-cma-heap-1",
+ .base = 0,
+ .size = (16 * SZ_1M),
+ },
+};
+
+static struct ion_platform_data snowball_ion_data1 = {
+ .heaps = snowball_ion_heap1,
+ .nr = ARRAY_SIZE(snowball_ion_heap1),
+};
+
+static struct platform_device snowball_ion_device1 = {
+ .name = "ion-ux500",
+ .id = 1,
+ .dev = {
+ .dma_mask = &snowball_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &snowball_ion_data1,
+ },
+ .num_resources = 0,
+};
+
+static struct ion_platform_heap snowball_ion_heap2[] = {
+ [0] = {
+ .type = ION_HEAP_TYPE_DMA,
+ .id = 2,
+ .name = "ion-cma-heap-2",
+ .base = 0,
+ .size = (16 * SZ_1M),
+ },
+};
+
+static struct ion_platform_data snowball_ion_data2 = {
+ .heaps = snowball_ion_heap2,
+ .nr = ARRAY_SIZE(snowball_ion_heap2),
+};
+
+static struct platform_device snowball_ion_device2 = {
+ .name = "ion-ux500",
+ .id = 2,
+ .dev = {
+ .dma_mask = &snowball_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &snowball_ion_data2,
+ },
+ .num_resources = 0,
+};
+#endif
+
static struct gpio_led snowball_led_array[] = {
{
.name = "user_led",
@@ -598,8 +659,21 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
&snowball_key_dev,
&snowball_sbnet_dev,
&ab8500_device,
+#ifdef CONFIG_ION
+ &snowball_ion_device1,
+ &snowball_ion_device2,
+#endif
};
+#ifdef CONFIG_ION
+static void __init mop500_reserve(void)
+{
+ dma_declare_contiguous(&snowball_ion_device1.dev,
+ snowball_ion_heap1[0].size,
+ snowball_ion_heap1[0].base, 0);
+}
+#endif
+
static void __init mop500_init_machine(void)
{
int i2c0_devs;
@@ -713,4 +787,7 @@ MACHINE_START(SNOWBALL, "Calao Systems Snowball platform")
/* we re-use nomadik timer here */
.timer = &ux500_timer,
.init_machine = snowball_init_machine,
+#ifdef CONFIG_ION
+ .reserve = mop500_reserve,
+#endif
MACHINE_END
@@ -9,3 +9,9 @@ config ION_TEGRA
depends on ARCH_TEGRA && ION
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.
@@ -1,3 +1,4 @@
ion-driver-objs += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_cma_heap.o
obj-$(CONFIG_ION) += ion-driver.o
obj-$(CONFIG_ION_TEGRA) += tegra/
+obj-$(CONFIG_ION_UX500) += ux500/
new file mode 100644
@@ -0,0 +1 @@
+obj-$(CONFIG_ION_UX500) += ux500_ion.o
new file mode 100644
@@ -0,0 +1,142 @@
+/*
+ * 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_device *ux500_ion_device;
+int num_heaps;
+struct ion_heap **ux500_ion_heaps;
+
+int ux500_ion_probe(struct platform_device *pdev)
+{
+ struct ion_platform_data *pdata = pdev->dev.platform_data;
+ int err;
+ int i, previous_heaps_count = 0;
+
+ /* test if it is the first time we try to create ions heaps */
+ if (num_heaps == 0) {
+ num_heaps = pdata->nr;
+
+ ux500_ion_heaps =
+ kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL);
+ memset(ux500_ion_heaps, 0,
+ sizeof(struct ion_heap *) * pdata->nr);
+
+ dev_dbg(&pdev->dev, "create ion device\n");
+ ux500_ion_device = ion_device_create(NULL);
+ if (IS_ERR_OR_NULL(ux500_ion_device)) {
+ kfree(ux500_ion_heaps);
+ num_heaps = 0;
+ dev_err(&pdev->dev, "failed to create ion device\n");
+ return PTR_ERR(ux500_ion_device);
+ }
+ } else {
+ struct ion_heap **new_ux500_ion_heaps;
+
+ previous_heaps_count = num_heaps;
+ num_heaps += pdata->nr;
+
+ /* allocate a bigger array of ion_heap */
+ new_ux500_ion_heaps =
+ kzalloc(sizeof(struct ion_heap *) * num_heaps, GFP_KERNEL);
+ memset(new_ux500_ion_heaps, 0,
+ sizeof(struct ion_heap *) * num_heaps);
+
+ dev_dbg(&pdev->dev, "realloc ion heap\n");
+ /* copy old heap array info into the new one */
+ for (i = 0; i < previous_heaps_count; i++)
+ new_ux500_ion_heaps[i] = ux500_ion_heaps[i];
+
+ /* free old heap array and swap it with the new one */
+ kfree(ux500_ion_heaps);
+ ux500_ion_heaps = new_ux500_ion_heaps;
+ }
+
+ /* create the heaps as specified in the board file */
+ for (i = previous_heaps_count; i < num_heaps; i++) {
+ struct ion_platform_heap *heap_data =
+ &pdata->heaps[i - previous_heaps_count];
+
+ ux500_ion_heaps[i] =
+ ion_heap_create_full(heap_data, &pdev->dev);
+
+ if (IS_ERR_OR_NULL(ux500_ion_heaps[i])) {
+ err = PTR_ERR(ux500_ion_heaps[i]);
+ ux500_ion_heaps[i] = NULL;
+ dev_err(&pdev->dev,
+ "failed to create heap type %d id %d\n",
+ heap_data->type, heap_data->id);
+ goto err;
+ }
+ ion_device_add_heap(ux500_ion_device, ux500_ion_heaps[i]);
+ }
+
+ platform_set_drvdata(pdev, ux500_ion_device);
+
+ return 0;
+err:
+ for (i = 0; i < num_heaps; i++) {
+ if (ux500_ion_heaps[i])
+ ion_heap_destroy(ux500_ion_heaps[i]);
+ }
+ kfree(ux500_ion_heaps);
+ return err;
+}
+
+int ux500_ion_remove(struct platform_device *pdev)
+{
+ struct ion_device *idev = platform_get_drvdata(pdev);
+ int i;
+
+ ion_device_destroy(idev);
+ for (i = 0; i < num_heaps; i++)
+ ion_heap_destroy(ux500_ion_heaps[i]);
+ kfree(ux500_ion_heaps);
+ 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)
+{
+ ux500_ion_device = NULL;
+ num_heaps = 0;
+ ux500_ion_heaps = NULL;
+
+ return platform_driver_register(&ux500_ion_driver);
+}
+
+static void __exit ux500_ion_exit(void)
+{
+ if (ux500_ion_device)
+ ion_device_destroy(ux500_ion_device);
+
+ platform_driver_unregister(&ux500_ion_driver);
+}
+
+module_init(ux500_ion_init);
+module_exit(ux500_ion_exit);