Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | /*
* Hisilicon Hi6220 ION Driver
*
* Copyright (c) 2015 Hisilicon Limited.
*
* Author: Chen Feng <puck.chen@hisilicon.com>
*
* 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.
*/
#define pr_fmt(fmt) "Ion: " fmt
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/mm.h>
#include "../ion_priv.h"
#include "../ion.h"
struct hi6220_ion_type_table {
const char *name;
enum ion_heap_type type;
};
static struct hi6220_ion_type_table ion_type_table[] = {
{"ion_system", ION_HEAP_TYPE_SYSTEM},
{"ion_system_contig", ION_HEAP_TYPE_SYSTEM_CONTIG},
{"ion_carveout", ION_HEAP_TYPE_CARVEOUT},
{"ion_chunk", ION_HEAP_TYPE_CHUNK},
{"ion_dma", ION_HEAP_TYPE_DMA},
{"ion_custom", ION_HEAP_TYPE_CUSTOM},
};
static struct ion_device *idev;
static int num_heaps;
static struct ion_heap **heaps;
static struct ion_platform_heap **heaps_data;
static int get_type_by_name(const char *name, enum ion_heap_type *type)
{
int i;
for (i = 0; i < ARRAY_SIZE(ion_type_table); i++) {
if (strncmp(name, ion_type_table[i].name, strlen(name)))
continue;
*type = ion_type_table[i].type;
return 0;
}
return -EINVAL;
}
static int hi6220_set_platform_data(struct platform_device *pdev)
{
unsigned int base;
unsigned int size;
unsigned int id;
const char *heap_name;
const char *type_name;
enum ion_heap_type type;
int ret;
struct device_node *np;
struct ion_platform_heap *p_data;
const struct device_node *dt_node = pdev->dev.of_node;
int index = 0;
for_each_child_of_node(dt_node, np)
num_heaps++;
heaps_data = devm_kzalloc(&pdev->dev,
sizeof(struct ion_platform_heap *) *
num_heaps,
GFP_KERNEL);
if (!heaps_data)
return -ENOMEM;
for_each_child_of_node(dt_node, np) {
ret = of_property_read_string(np, "heap-name", &heap_name);
if (ret < 0) {
pr_err("check the name of node %s\n", np->name);
continue;
}
ret = of_property_read_u32(np, "heap-id", &id);
if (ret < 0) {
pr_err("check the id %s\n", np->name);
continue;
}
ret = of_property_read_u32(np, "heap-base", &base);
if (ret < 0) {
pr_err("check the base of node %s\n", np->name);
continue;
}
ret = of_property_read_u32(np, "heap-size", &size);
if (ret < 0) {
pr_err("check the size of node %s\n", np->name);
continue;
}
ret = of_property_read_string(np, "heap-type", &type_name);
if (ret < 0) {
pr_err("check the type of node %s\n", np->name);
continue;
}
ret = get_type_by_name(type_name, &type);
if (ret < 0) {
pr_err("type name error %s!\n", type_name);
continue;
}
pr_info("heap index %d : name %s base 0x%x size 0x%x id %d type %d\n",
index, heap_name, base, size, id, type);
p_data = devm_kzalloc(&pdev->dev,
sizeof(struct ion_platform_heap),
GFP_KERNEL);
if (!p_data)
return -ENOMEM;
p_data->name = heap_name;
p_data->base = base;
p_data->size = size;
p_data->id = id;
p_data->type = type;
heaps_data[index] = p_data;
index++;
}
return 0;
}
static int hi6220_ion_probe(struct platform_device *pdev)
{
int i;
int err;
static struct ion_platform_heap *p_heap;
idev = ion_device_create(NULL);
err = hi6220_set_platform_data(pdev);
if (err) {
pr_err("ion set platform data error!\n");
goto err_free_idev;
}
heaps = devm_kzalloc(&pdev->dev,
sizeof(struct ion_heap *) * num_heaps,
GFP_KERNEL);
if (!heaps) {
err = -ENOMEM;
goto err_free_idev;
}
/*
* create the heaps as specified in the dts file
*/
for (i = 0; i < num_heaps; i++) {
p_heap = heaps_data[i];
heaps[i] = ion_heap_create(p_heap);
if (IS_ERR_OR_NULL(heaps[i])) {
err = PTR_ERR(heaps[i]);
goto err_free_heaps;
}
ion_device_add_heap(idev, heaps[i]);
pr_info("%s: adding heap %s of type %d with %lx@%lx\n",
__func__, p_heap->name, p_heap->type,
p_heap->base, (unsigned long)p_heap->size);
}
return err;
err_free_heaps:
for (i = 0; i < num_heaps; ++i) {
ion_heap_destroy(heaps[i]);
heaps[i] = NULL;
}
err_free_idev:
ion_device_destroy(idev);
return err;
}
static int hi6220_ion_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < num_heaps; i++) {
ion_heap_destroy(heaps[i]);
heaps[i] = NULL;
}
ion_device_destroy(idev);
return 0;
}
static const struct of_device_id hi6220_ion_match_table[] = {
{.compatible = "hisilicon,hi6220-ion"},
{},
};
static struct platform_driver hi6220_ion_driver = {
.probe = hi6220_ion_probe,
.remove = hi6220_ion_remove,
.driver = {
.name = "ion-hi6220",
.of_match_table = hi6220_ion_match_table,
},
};
static int __init hi6220_ion_init(void)
{
int ret;
ret = platform_driver_register(&hi6220_ion_driver);
return ret;
}
subsys_initcall(hi6220_ion_init);
|