blob: 5826ce68b7773642f8933c253dfd2a711a77939a [file] [log] [blame]
wanwei.jiangd8cfbc12021-12-08 16:32:55 +08001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
wanwei.jiang63f85852022-04-20 18:14:26 +08005// #define DEBUG
qinglin.liafe35bd2022-01-18 16:09:02 +08006// #define USE_CMA
7// #define TEST_ACESS
wanwei.jiangd8cfbc12021-12-08 16:32:55 +08008#include <linux/errno.h>
9#include <linux/err.h>
10#include <linux/of.h>
11#include <linux/module.h>
12#include <linux/of_fdt.h>
13#include <linux/libfdt_env.h>
14#include <linux/of_reserved_mem.h>
15#include <linux/io.h>
16#include <linux/platform_device.h>
wanwei.jiang24483b32021-12-08 16:57:18 +080017#include <linux/uaccess.h>
18#ifdef USE_CMA
19#include <linux/dma-map-ops.h>
20#include <linux/cma.h>
21#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080022#include <linux/arm-smccc.h>
Lei Zhang3faeb772022-02-22 09:53:59 +080023#include <linux/memblock.h>
24#include <linux/vmalloc.h>
25#include <linux/slab.h>
26#include <asm/page.h>
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080027
28static void __iomem *sharemem_in_base;
29static void __iomem *sharemem_out_base;
30static long phy_in_base;
31static long phy_out_base;
32static unsigned long secmon_start_virt;
33static unsigned int secmon_size;
34
Wanwei Jiang24ec3212022-11-02 19:11:33 +080035#if IS_ENABLED(CONFIG_ARM64)
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080036#define IN_SIZE 0x6000
37#else
Wanwei Jiang24ec3212022-11-02 19:11:33 +080038#define IN_SIZE 0x6000
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080039#endif
Wanwei Jiang24ec3212022-11-02 19:11:33 +080040
41#define OUT_SIZE 0x1000
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080042static DEFINE_MUTEX(sharemem_mutex);
43#define DEV_REGISTERED 1
pengzhao.liuc2a22ec2022-09-20 14:48:32 +080044#define DEV_UNREGISTERED 0
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080045
46unsigned int sharemem_in_size = IN_SIZE;
47unsigned int sharemem_out_size = OUT_SIZE;
48
pengzhao.liuc2a22ec2022-09-20 14:48:32 +080049static int secmon_dev_registered = DEV_UNREGISTERED;
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080050static long get_sharemem_info(unsigned int function_id)
51{
52 struct arm_smccc_res res;
53
54 arm_smccc_smc(function_id, 0, 0, 0, 0, 0, 0, 0, &res);
55
56 return res.a0;
57}
58
59static void get_sharemem_size(unsigned int function_id)
60{
61 struct arm_smccc_res res;
62
63 arm_smccc_smc(function_id, 1, 0, 0, 0, 0, 0, 0, &res);
64 if (res.a0 != -1)
65 sharemem_in_size = res.a0;
66
67 arm_smccc_smc(function_id, 2, 0, 0, 0, 0, 0, 0, &res);
68 if (res.a0 != -1)
69 sharemem_out_size = res.a0;
70}
71
72#define RESERVE_MEM_SIZE 0x300000
73
74int within_secmon_region(unsigned long addr)
75{
76 if (!secmon_start_virt)
77 return 0;
78
79 if (addr >= secmon_start_virt &&
80 addr <= (secmon_start_virt + secmon_size))
81 return 1;
82
83 return 0;
84}
wanwei.jiang24483b32021-12-08 16:57:18 +080085EXPORT_SYMBOL(within_secmon_region);
86
87static int get_reserver_base_size(struct platform_device *pdev)
88{
89 struct device_node *mem_region;
90 struct reserved_mem *rmem;
91
92 mem_region = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
93 if (!mem_region) {
94 dev_warn(&pdev->dev, "no such memory-region\n");
95 return -ENODEV;
96 }
97
98 rmem = of_reserved_mem_lookup(mem_region);
99 if (!rmem) {
100 dev_warn(&pdev->dev, "no such reserved mem of node name %s\n",
101 pdev->dev.of_node->name);
102 return -ENODEV;
103 }
104
105 /* Need to wait for reserved memory to be mapped */
106 //if (!rmem->priv)
107 // return -EPROBE_DEFER;
108
109 if (!rmem->base || !rmem->size) {
110 dev_warn(&pdev->dev, "unexpected reserved memory\n");
111 return -EINVAL;
112 }
113
114 secmon_start_virt = __phys_to_virt(rmem->base);
115
116 //pr_info("secmon_start_virt=0x%016lx, base=0x%010lx, size=0x%010x\n",
117 // secmon_start_virt, rmem->base, rmem->size);
118
119 return 0;
120}
121
122#ifdef TEST_ACESS
123static void test_access_secmon(void)
124{
125 int i, j;
126 int nlines;
127 u32 *p;
128
129 nlines = 16;
130 p = (u32 *)(secmon_start_virt + 0x200000);
131 for (i = 0; i < nlines; i++) {
132 /*
133 * just display low 16 bits of address to keep
134 * each line of the dump < 80 characters
135 */
136 pr_info("%04lx ", (unsigned long)p & 0xffff);
137 for (j = 0; j < 8; j++) {
138 u32 data;
139
140 if (get_kernel_nofault(data, p))
141 pr_cont(" ********");
142 else
143 pr_cont(" %08x", data);
144 ++p;
145 }
146 pr_cont("\n");
147 }
148}
149#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800150
Lei Zhang3faeb772022-02-22 09:53:59 +0800151static void *ram_vmap(phys_addr_t start, size_t size)
152{
153 struct page **pages;
154 phys_addr_t page_start;
155 unsigned int page_count;
156 unsigned int i;
157 void *vaddr;
158
159 page_start = start - offset_in_page(start);
160 page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
161
162 pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL);
163 if (!pages)
164 return NULL;
165
166 for (i = 0; i < page_count; i++) {
167 phys_addr_t addr = page_start + i * PAGE_SIZE;
168
169 pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
170 }
171 vaddr = vmap(pages, page_count, VM_MAP, PAGE_KERNEL);
172 kfree(pages);
173
174 return vaddr + offset_in_page(start);
175}
176
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800177static int secmon_probe(struct platform_device *pdev)
178{
179 struct device_node *np = pdev->dev.of_node;
180 unsigned int id;
wanwei.jiang24483b32021-12-08 16:57:18 +0800181 int ret = 0;
182#ifdef USE_CMA
183 struct page *page;
184#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800185
186 if (!of_property_read_u32(np, "in_base_func", &id))
187 phy_in_base = get_sharemem_info(id);
188
189 if (!of_property_read_u32(np, "out_base_func", &id))
190 phy_out_base = get_sharemem_info(id);
191
192 if (!of_property_read_u32(np, "inout_size_func", &id))
193 get_sharemem_size(id);
194
wanwei.jiang63f85852022-04-20 18:14:26 +0800195 if (!of_property_read_bool (pdev->dev.of_node, "no-memory")) {
196 if (of_property_read_u32(np, "reserve_mem_size", &secmon_size)) {
197 pr_err("can't get reserve_mem_size, use default value\n");
198 secmon_size = RESERVE_MEM_SIZE;
199 } else {
200 pr_info("reserve_mem_size:0x%x\n", secmon_size);
201 }
wanwei.jiang24483b32021-12-08 16:57:18 +0800202
wanwei.jiang63f85852022-04-20 18:14:26 +0800203 get_reserver_base_size(pdev);
wanwei.jiang24483b32021-12-08 16:57:18 +0800204#ifdef USE_CMA
wanwei.jiang63f85852022-04-20 18:14:26 +0800205 ret = of_reserved_mem_device_init(&pdev->dev);
206 if (ret) {
207 pr_err("reserve memory init fail:%d\n", ret);
208 return ret;
209 }
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800210
wanwei.jiang63f85852022-04-20 18:14:26 +0800211 page = dma_alloc_from_contiguous(&pdev->dev, secmon_size >> PAGE_SHIFT, 0, 0);
212 if (!page) {
213 pr_err("alloc page failed, ret:%p\n", page);
214 return -ENOMEM;
215 }
216 pr_debug("get page:%p, %lx\n", page, page_to_pfn(page));
217 secmon_start_virt = (unsigned long)page_to_virt(page);
wanwei.jiang24483b32021-12-08 16:57:18 +0800218#endif
219
220#ifdef TEST_ACESS
wanwei.jiang63f85852022-04-20 18:14:26 +0800221 test_access_secmon();
wanwei.jiang24483b32021-12-08 16:57:18 +0800222#endif
wanwei.jiang63f85852022-04-20 18:14:26 +0800223 }
224
Lei Zhang3faeb772022-02-22 09:53:59 +0800225 sharemem_in_base = ram_vmap(phy_in_base, sharemem_in_size);
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800226 if (!sharemem_in_base) {
qinglin.liafe35bd2022-01-18 16:09:02 +0800227 pr_err("secmon share mem in buffer remap fail!\n");
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800228 return -ENOMEM;
229 }
Lei Zhang3faeb772022-02-22 09:53:59 +0800230 sharemem_out_base = ram_vmap(phy_out_base, sharemem_out_size);
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800231 if (!sharemem_out_base) {
qinglin.liafe35bd2022-01-18 16:09:02 +0800232 pr_err("secmon share mem out buffer remap fail!\n");
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800233 return -ENOMEM;
234 }
235 secmon_dev_registered = DEV_REGISTERED;
236 pr_info("share in base: 0x%lx, share out base: 0x%lx\n",
237 (long)sharemem_in_base, (long)sharemem_out_base);
238 pr_info("phy_in_base: 0x%lx, phy_out_base: 0x%lx\n",
239 phy_in_base, phy_out_base);
240
241 return ret;
242}
243
wanwei.jiang24483b32021-12-08 16:57:18 +0800244#ifdef USE_CMA
245void __init secmon_clear_cma_mmu(void)
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800246{
247 struct device_node *np;
248 unsigned int clear[2] = {};
249
250 np = of_find_node_by_name(NULL, "secmon");
251 if (!np)
252 return;
253
254 if (of_property_read_u32_array(np, "clear_range", clear, 2))
255 pr_info("can't fine clear_range\n");
256 else
257 pr_info("clear_range:%x %x\n", clear[0], clear[1]);
258
259 if (clear[0]) {
260 struct page *page = phys_to_page(clear[0]);
261 int cnt = clear[1] / PAGE_SIZE;
262
wanwei.jiang24483b32021-12-08 16:57:18 +0800263 cma_mmu_op(page, cnt, 0); //cma_mmu_op() implemented in kernel
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800264 }
wanwei.jiang24483b32021-12-08 16:57:18 +0800265}
266#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800267
268static const struct of_device_id secmon_dt_match[] = {
269 { .compatible = "amlogic, secmon" },
270 { /* sentinel */ },
271};
272
273static struct platform_driver secmon_platform_driver = {
274 .probe = secmon_probe,
275 .driver = {
276 .owner = THIS_MODULE,
277 .name = "secmon",
278 .of_match_table = secmon_dt_match,
279 },
280};
281
282int __init meson_secmon_init(void)
283{
284 int ret;
285
286 ret = platform_driver_register(&secmon_platform_driver);
287 WARN((secmon_dev_registered != DEV_REGISTERED),
wanwei.jiang24483b32021-12-08 16:57:18 +0800288 "ERROR: secmon device must be enable!!!\n");
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800289 return ret;
290}
291
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800292void meson_sm_mutex_lock(void)
293{
294 mutex_lock(&sharemem_mutex);
295}
296EXPORT_SYMBOL(meson_sm_mutex_lock);
297
298void meson_sm_mutex_unlock(void)
299{
300 mutex_unlock(&sharemem_mutex);
301}
302EXPORT_SYMBOL(meson_sm_mutex_unlock);
303
304void __iomem *get_meson_sm_input_base(void)
305{
306 return sharemem_in_base;
307}
308EXPORT_SYMBOL(get_meson_sm_input_base);
wanwei.jiangdd140762022-04-27 20:56:00 +0800309
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800310void __iomem *get_meson_sm_output_base(void)
311{
312 return sharemem_out_base;
313}
314EXPORT_SYMBOL(get_meson_sm_output_base);
315
316long get_secmon_phy_input_base(void)
317{
318 return phy_in_base;
319}
320EXPORT_SYMBOL(get_secmon_phy_input_base);
321
322long get_secmon_phy_output_base(void)
323{
324 return phy_out_base;
325}
wanwei.jiangdd140762022-04-27 20:56:00 +0800326EXPORT_SYMBOL(get_secmon_phy_output_base);
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800327
328unsigned int get_secmon_sharemem_in_size(void)
329{
330 return sharemem_in_size;
331}
332EXPORT_SYMBOL(get_secmon_sharemem_in_size);
wanwei.jiangdd140762022-04-27 20:56:00 +0800333
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800334unsigned int get_secmon_sharemem_out_size(void)
335{
336 return sharemem_out_size;
337}
338EXPORT_SYMBOL(get_secmon_sharemem_out_size);
339