summaryrefslogtreecommitdiff
path: root/drivers/staging/android/ion/hisilicon/hisi_ion.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/android/ion/hisilicon/hisi_ion.c')
-rw-r--r--drivers/staging/android/ion/hisilicon/hisi_ion.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/drivers/staging/android/ion/hisilicon/hisi_ion.c b/drivers/staging/android/ion/hisilicon/hisi_ion.c
new file mode 100644
index 000000000000..05964ef7ff5f
--- /dev/null
+++ b/drivers/staging/android/ion/hisilicon/hisi_ion.c
@@ -0,0 +1,266 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+#define pr_fmt(fmt) "ion: " fmt
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/hisi_ion.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+#include "../ion_priv.h"
+
+struct hisi_ion_name_id_table {
+ const char *name;
+ unsigned int id;
+};
+
+static struct hisi_ion_name_id_table name_id_table[] = {
+ {"fb", ION_FB_HEAP_ID},
+ {"vpu", ION_VPU_HEAP_ID},
+ {"jpu", ION_JPU_HEAP_ID},
+ {"gralloc-carveout", ION_GRALLOC_HEAP_ID},
+ {"overlay", ION_OVERLAY_HEAP_ID},
+ {"sys_user", ION_SYSTEM_HEAP_ID},
+ {"sys_contig", ION_SYSTEM_CONTIG_HEAP_ID},
+ {"cma", ION_HEAP_TYPE_DMA},
+};
+
+struct hisi_ion_type_id_table {
+ const char *name;
+ enum ion_heap_type type;
+};
+
+static struct hisi_ion_type_id_table type_id_table[] = {
+ {"ion_system_contig", ION_HEAP_TYPE_SYSTEM_CONTIG},
+ {"ion_system", ION_HEAP_TYPE_SYSTEM},
+ {"ion_carveout", ION_HEAP_TYPE_CARVEOUT},
+ {"ion_chunk", ION_HEAP_TYPE_CHUNK},
+ {"ion_dma", ION_HEAP_TYPE_DMA},
+ {"ion_custom", ION_HEAP_TYPE_CUSTOM},
+ {"ion_cma", ION_HEAP_TYPE_DMA},
+};
+
+#define HISI_ION_HEAP_NUM 16
+
+static struct ion_platform_data hisi_ion_platform_data = {0};
+static struct ion_platform_heap hisi_ion_platform_heap[HISI_ION_HEAP_NUM] = {{0} };
+
+static struct ion_device *hisi_ion_device;
+static struct ion_heap *hisi_ion_heap[HISI_ION_HEAP_NUM] = {NULL};
+
+int hisi_ion_get_heap_info(unsigned int id, struct ion_heap_info_data *data)
+{
+ int i;
+
+ BUG_ON(!data);
+
+ for (i = 0; i < hisi_ion_platform_data.nr; i++) {
+ if (hisi_ion_platform_heap[i].id == id) {
+ data->heap_phy = hisi_ion_platform_heap[i].base;
+ data->heap_size = hisi_ion_platform_heap[i].size;
+ strncpy((void *)data->name, (void *)hisi_ion_platform_heap[i].name, HISI_ION_NAME_LEN);
+ pr_info("heap info : id %d name %s phy 0x%llx size %u\n",
+ id, data->name, data->heap_phy, data->heap_size);
+ return 0;
+ }
+ }
+ pr_err("in %s please check the id %d\n", __func__, id);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(hisi_ion_get_heap_info);
+
+struct ion_device *get_ion_device(void)
+{
+ return hisi_ion_device;
+}
+EXPORT_SYMBOL(get_ion_device);
+
+static int get_id_by_name(const char *name, unsigned int *id)
+{
+ int i, n;
+
+ n = sizeof(name_id_table)/sizeof(name_id_table[0]);
+ for (i = 0; i < n; i++) {
+ if (strncmp(name, name_id_table[i].name, HISI_ION_NAME_LEN))
+ continue;
+
+ *id = name_id_table[i].id;
+ return 0;
+ }
+ return -1;
+}
+
+static int get_type_by_name(const char *name, enum ion_heap_type *type)
+{
+ int i, n;
+
+ n = sizeof(type_id_table)/sizeof(type_id_table[0]);
+ for (i = 0; i < n; i++) {
+ if (strncmp(name, type_id_table[i].name, HISI_ION_NAME_LEN))
+ continue;
+
+ *type = type_id_table[i].type;
+ return 0;
+ }
+
+ return -1;
+}
+
+static u64 hisi_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device ion_cma_device = {
+ .name = "ion-cma-device",
+ .id = -1,
+ .dev = {
+ .dma_mask = &hisi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
+};
+
+static int hisi_ion_setup_platform_data(struct platform_device *dev)
+{
+ struct device_node *node, *np;
+ const char *heap_name;
+ const char *type_name;
+ unsigned int id;
+ unsigned int range[2] = {0, 0};
+ enum ion_heap_type type;
+ int ret;
+ int index = 0;
+
+ node = dev->dev.of_node;
+ for_each_child_of_node(node, np) {
+ ret = of_property_read_string(np, "heap-name", &heap_name);
+ if (ret < 0) {
+ pr_err("in node %s please check the name property of node %s\n", __func__, np->name);
+ continue;
+ }
+
+ ret = get_id_by_name(heap_name, &id);
+ if (ret < 0) {
+ pr_err("in node %s please check the name %s\n", __func__, heap_name);
+ continue;
+ }
+
+ ret = of_property_read_u32_array(np, "heap-range", range, ARRAY_SIZE(range));
+ if (ret < 0) {
+ pr_err("in node %s please check the range property of node %s\n", __func__, np->name);
+ continue;
+ }
+
+
+ ret = of_property_read_string(np, "heap-type", &type_name);
+ if (ret < 0) {
+ pr_err("in node %s please check the type property of node %s\n", __func__, np->name);
+ continue;
+ }
+
+ ret = get_type_by_name(type_name, &type);
+ if (ret < 0) {
+ pr_err("in node %s please check the type %s\n", __func__, type_name);
+ continue;
+ }
+
+ hisi_ion_platform_heap[index].name = heap_name;
+ hisi_ion_platform_heap[index].base = range[0];
+ hisi_ion_platform_heap[index].size = range[1];
+ hisi_ion_platform_heap[index].id = id;
+ hisi_ion_platform_heap[index].type = type;
+ if (type == ION_HEAP_TYPE_DMA) {
+ // ion_cma_device.dev.archdata.dma_ops = swiotlb_dma_ops;
+ hisi_ion_platform_heap[index].priv =
+ (void *)&ion_cma_device.dev;
+ }
+ index++;
+ }
+
+ hisi_ion_platform_data.nr = index;
+ hisi_ion_platform_data.heaps = hisi_ion_platform_heap;
+
+ return 0;
+}
+
+static int hisi_ion_probe(struct platform_device *pdev)
+{
+ int i, err;
+ struct ion_heap *heap;
+ struct ion_platform_heap *heap_data;
+
+ if (hisi_ion_setup_platform_data(pdev)) {
+ pr_err("hisi_ion_setup_platform_data is failed\n");
+ return -EINVAL;
+ }
+
+ hisi_ion_device = ion_device_create(NULL);
+ if (IS_ERR_OR_NULL(hisi_ion_device))
+ return PTR_ERR(hisi_ion_device);
+ /*
+ * create the heaps as specified in the board file
+ */
+ for (i = 0; i < hisi_ion_platform_data.nr; i++) {
+ heap_data = &hisi_ion_platform_data.heaps[i];
+ heap = ion_heap_create(heap_data);
+ if (IS_ERR_OR_NULL(heap)) {
+ err = PTR_ERR(heap);
+ goto out;
+ }
+
+ ion_device_add_heap(hisi_ion_device, heap);
+ hisi_ion_heap[i] = heap;
+ }
+ platform_set_drvdata(pdev, hisi_ion_device);
+
+ return 0;
+out:
+ for (i = 0; i < HISI_ION_HEAP_NUM; i++) {
+ if (!hisi_ion_heap[i])
+ continue;
+ ion_heap_destroy(hisi_ion_heap[i]);
+ hisi_ion_heap[i] = NULL;
+ }
+ return err;
+}
+
+static int hisi_ion_remove(struct platform_device *pdev)
+{
+ int i;
+
+ ion_device_destroy(hisi_ion_device);
+ for (i = 0; i < HISI_ION_HEAP_NUM; i++) {
+ if (!hisi_ion_heap[i])
+ continue;
+ ion_heap_destroy(hisi_ion_heap[i]);
+ hisi_ion_heap[i] = NULL;
+ }
+
+ return 0;
+}
+
+static struct of_device_id hisi_ion_match_table[] = {
+ {.compatible = "hisilicon,ion"},
+ {},
+};
+
+static struct platform_driver hisi_ion_driver = {
+ .probe = hisi_ion_probe,
+ .remove = hisi_ion_remove,
+ .driver = {
+ .name = "ion",
+ .of_match_table = hisi_ion_match_table,
+ },
+};
+
+module_platform_driver(hisi_ion_driver);