1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  linux/arch/arm/mach-mmp/sram.c
4  *
5  *  based on mach-davinci/sram.c - DaVinci simple SRAM allocator
6  *
7  *  Copyright (c) 2011 Marvell Semiconductors Inc.
8  *  All Rights Reserved
9  *
10  *  Add for mmp sram support - Leo Yan <leoy@marvell.com>
11  */
12 
13 #include <linux/module.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/init.h>
16 #include <linux/platform_device.h>
17 #include <linux/io.h>
18 #include <linux/err.h>
19 #include <linux/slab.h>
20 #include <linux/genalloc.h>
21 
22 #include <linux/platform_data/dma-mmp_tdma.h>
23 
24 struct sram_bank_info {
25 	char *pool_name;
26 	struct gen_pool *gpool;
27 	int granularity;
28 
29 	phys_addr_t sram_phys;
30 	void __iomem *sram_virt;
31 	u32 sram_size;
32 
33 	struct list_head node;
34 };
35 
36 static DEFINE_MUTEX(sram_lock);
37 static LIST_HEAD(sram_bank_list);
38 
sram_get_gpool(char * pool_name)39 struct gen_pool *sram_get_gpool(char *pool_name)
40 {
41 	struct sram_bank_info *info = NULL;
42 
43 	if (!pool_name)
44 		return NULL;
45 
46 	mutex_lock(&sram_lock);
47 
48 	list_for_each_entry(info, &sram_bank_list, node)
49 		if (!strcmp(pool_name, info->pool_name))
50 			break;
51 
52 	mutex_unlock(&sram_lock);
53 
54 	if (&info->node == &sram_bank_list)
55 		return NULL;
56 
57 	return info->gpool;
58 }
59 EXPORT_SYMBOL(sram_get_gpool);
60 
sram_probe(struct platform_device * pdev)61 static int sram_probe(struct platform_device *pdev)
62 {
63 	struct sram_platdata *pdata = pdev->dev.platform_data;
64 	struct sram_bank_info *info;
65 	struct resource *res;
66 	int ret = 0;
67 
68 	if (!pdata || !pdata->pool_name)
69 		return -ENODEV;
70 
71 	info = kzalloc(sizeof(*info), GFP_KERNEL);
72 	if (!info)
73 		return -ENOMEM;
74 
75 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
76 	if (res == NULL) {
77 		dev_err(&pdev->dev, "no memory resource defined\n");
78 		ret = -ENODEV;
79 		goto out;
80 	}
81 
82 	if (!resource_size(res))
83 		return 0;
84 
85 	info->sram_phys   = (phys_addr_t)res->start;
86 	info->sram_size   = resource_size(res);
87 	info->sram_virt   = ioremap(info->sram_phys, info->sram_size);
88 	info->pool_name	  = kstrdup(pdata->pool_name, GFP_KERNEL);
89 	info->granularity = pdata->granularity;
90 
91 	info->gpool = gen_pool_create(ilog2(info->granularity), -1);
92 	if (!info->gpool) {
93 		dev_err(&pdev->dev, "create pool failed\n");
94 		ret = -ENOMEM;
95 		goto create_pool_err;
96 	}
97 
98 	ret = gen_pool_add_virt(info->gpool, (unsigned long)info->sram_virt,
99 				info->sram_phys, info->sram_size, -1);
100 	if (ret < 0) {
101 		dev_err(&pdev->dev, "add new chunk failed\n");
102 		ret = -ENOMEM;
103 		goto add_chunk_err;
104 	}
105 
106 	mutex_lock(&sram_lock);
107 	list_add(&info->node, &sram_bank_list);
108 	mutex_unlock(&sram_lock);
109 
110 	platform_set_drvdata(pdev, info);
111 
112 	dev_info(&pdev->dev, "initialized\n");
113 	return 0;
114 
115 add_chunk_err:
116 	gen_pool_destroy(info->gpool);
117 create_pool_err:
118 	iounmap(info->sram_virt);
119 	kfree(info->pool_name);
120 out:
121 	kfree(info);
122 	return ret;
123 }
124 
sram_remove(struct platform_device * pdev)125 static int sram_remove(struct platform_device *pdev)
126 {
127 	struct sram_bank_info *info;
128 
129 	info = platform_get_drvdata(pdev);
130 	if (info == NULL)
131 		return -ENODEV;
132 
133 	mutex_lock(&sram_lock);
134 	list_del(&info->node);
135 	mutex_unlock(&sram_lock);
136 
137 	gen_pool_destroy(info->gpool);
138 	iounmap(info->sram_virt);
139 	kfree(info->pool_name);
140 	kfree(info);
141 	return 0;
142 }
143 
144 static const struct platform_device_id sram_id_table[] = {
145 	{ "asram", MMP_ASRAM },
146 	{ "isram", MMP_ISRAM },
147 	{ }
148 };
149 
150 static struct platform_driver sram_driver = {
151 	.probe		= sram_probe,
152 	.remove		= sram_remove,
153 	.driver		= {
154 		.name	= "mmp-sram",
155 	},
156 	.id_table	= sram_id_table,
157 };
158 
sram_init(void)159 static int __init sram_init(void)
160 {
161 	return platform_driver_register(&sram_driver);
162 }
163 core_initcall(sram_init);
164 
165 MODULE_LICENSE("GPL");
166