blob: 82a8caa0e6a87106831f30d6c31913e7c25c6de2 [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
qinglin.li7938f742022-12-01 17:03:20 +08007// #define TEST_ACCESS
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>
luke.liu824a1772024-09-29 14:04:13 +080027#include <linux/suspend.h>
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080028
29static void __iomem *sharemem_in_base;
30static void __iomem *sharemem_out_base;
31static long phy_in_base;
32static long phy_out_base;
33static unsigned long secmon_start_virt;
34static unsigned int secmon_size;
35
Wanwei Jiang24ec3212022-11-02 19:11:33 +080036#if IS_ENABLED(CONFIG_ARM64)
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080037#define IN_SIZE 0x6000
38#else
Wanwei Jiang24ec3212022-11-02 19:11:33 +080039#define IN_SIZE 0x6000
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080040#endif
Wanwei Jiang24ec3212022-11-02 19:11:33 +080041
42#define OUT_SIZE 0x1000
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080043static DEFINE_MUTEX(sharemem_mutex);
44#define DEV_REGISTERED 1
pengzhao.liuc2a22ec2022-09-20 14:48:32 +080045#define DEV_UNREGISTERED 0
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080046
47unsigned int sharemem_in_size = IN_SIZE;
48unsigned int sharemem_out_size = OUT_SIZE;
49
pengzhao.liuc2a22ec2022-09-20 14:48:32 +080050static int secmon_dev_registered = DEV_UNREGISTERED;
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080051static long get_sharemem_info(unsigned int function_id)
52{
53 struct arm_smccc_res res;
54
55 arm_smccc_smc(function_id, 0, 0, 0, 0, 0, 0, 0, &res);
56
57 return res.a0;
58}
59
60static void get_sharemem_size(unsigned int function_id)
61{
62 struct arm_smccc_res res;
63
64 arm_smccc_smc(function_id, 1, 0, 0, 0, 0, 0, 0, &res);
65 if (res.a0 != -1)
66 sharemem_in_size = res.a0;
67
68 arm_smccc_smc(function_id, 2, 0, 0, 0, 0, 0, 0, &res);
69 if (res.a0 != -1)
70 sharemem_out_size = res.a0;
71}
72
73#define RESERVE_MEM_SIZE 0x300000
74
qiankun.wange1d5f7d2023-08-10 11:25:39 +080075static unsigned long reg_to_pfn(unsigned long reg)
76{
77 struct page *page;
78
79 if (reg < (unsigned long)PAGE_OFFSET)
80 return 0;
81 else if (reg <= (unsigned long)high_memory)
82 return virt_to_pfn(reg);
83
84 page = vmalloc_to_page((const void *)reg);
85 if (page)
86 return page_to_pfn(page);
87
88 return 0;
89}
90
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080091int within_secmon_region(unsigned long addr)
92{
qiankun.wange1d5f7d2023-08-10 11:25:39 +080093 unsigned long addr_pfn = reg_to_pfn(addr);
94
wanwei.jiangd8cfbc12021-12-08 16:32:55 +080095 if (!secmon_start_virt)
96 return 0;
97
qiankun.wange1d5f7d2023-08-10 11:25:39 +080098 if (!addr_pfn)
qiankun.wangbd5059f2023-09-21 13:39:22 +080099 return 0;
qiankun.wange1d5f7d2023-08-10 11:25:39 +0800100
101 if (addr_pfn >= virt_to_pfn(secmon_start_virt) &&
102 addr_pfn <= virt_to_pfn(secmon_start_virt + secmon_size))
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800103 return 1;
104
105 return 0;
106}
wanwei.jiang24483b32021-12-08 16:57:18 +0800107EXPORT_SYMBOL(within_secmon_region);
108
109static int get_reserver_base_size(struct platform_device *pdev)
110{
111 struct device_node *mem_region;
112 struct reserved_mem *rmem;
113
114 mem_region = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
115 if (!mem_region) {
116 dev_warn(&pdev->dev, "no such memory-region\n");
117 return -ENODEV;
118 }
119
120 rmem = of_reserved_mem_lookup(mem_region);
121 if (!rmem) {
122 dev_warn(&pdev->dev, "no such reserved mem of node name %s\n",
123 pdev->dev.of_node->name);
124 return -ENODEV;
125 }
126
127 /* Need to wait for reserved memory to be mapped */
128 //if (!rmem->priv)
129 // return -EPROBE_DEFER;
130
131 if (!rmem->base || !rmem->size) {
132 dev_warn(&pdev->dev, "unexpected reserved memory\n");
133 return -EINVAL;
134 }
135
136 secmon_start_virt = __phys_to_virt(rmem->base);
137
138 //pr_info("secmon_start_virt=0x%016lx, base=0x%010lx, size=0x%010x\n",
139 // secmon_start_virt, rmem->base, rmem->size);
140
141 return 0;
142}
143
qinglin.li7938f742022-12-01 17:03:20 +0800144#ifdef TEST_ACCESS
wanwei.jiang24483b32021-12-08 16:57:18 +0800145static void test_access_secmon(void)
146{
147 int i, j;
148 int nlines;
149 u32 *p;
150
151 nlines = 16;
152 p = (u32 *)(secmon_start_virt + 0x200000);
153 for (i = 0; i < nlines; i++) {
154 /*
155 * just display low 16 bits of address to keep
156 * each line of the dump < 80 characters
157 */
158 pr_info("%04lx ", (unsigned long)p & 0xffff);
159 for (j = 0; j < 8; j++) {
160 u32 data;
161
162 if (get_kernel_nofault(data, p))
163 pr_cont(" ********");
164 else
165 pr_cont(" %08x", data);
166 ++p;
167 }
168 pr_cont("\n");
169 }
170}
171#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800172
Lei Zhang3faeb772022-02-22 09:53:59 +0800173static void *ram_vmap(phys_addr_t start, size_t size)
174{
175 struct page **pages;
176 phys_addr_t page_start;
177 unsigned int page_count;
178 unsigned int i;
179 void *vaddr;
180
181 page_start = start - offset_in_page(start);
182 page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
183
184 pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL);
185 if (!pages)
186 return NULL;
187
188 for (i = 0; i < page_count; i++) {
189 phys_addr_t addr = page_start + i * PAGE_SIZE;
190
191 pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
192 }
193 vaddr = vmap(pages, page_count, VM_MAP, PAGE_KERNEL);
194 kfree(pages);
195
196 return vaddr + offset_in_page(start);
197}
198
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800199static int secmon_probe(struct platform_device *pdev)
200{
201 struct device_node *np = pdev->dev.of_node;
202 unsigned int id;
wanwei.jiang24483b32021-12-08 16:57:18 +0800203 int ret = 0;
204#ifdef USE_CMA
205 struct page *page;
206#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800207
208 if (!of_property_read_u32(np, "in_base_func", &id))
209 phy_in_base = get_sharemem_info(id);
210
211 if (!of_property_read_u32(np, "out_base_func", &id))
212 phy_out_base = get_sharemem_info(id);
213
214 if (!of_property_read_u32(np, "inout_size_func", &id))
215 get_sharemem_size(id);
216
wanwei.jiang63f85852022-04-20 18:14:26 +0800217 if (!of_property_read_bool (pdev->dev.of_node, "no-memory")) {
218 if (of_property_read_u32(np, "reserve_mem_size", &secmon_size)) {
219 pr_err("can't get reserve_mem_size, use default value\n");
220 secmon_size = RESERVE_MEM_SIZE;
221 } else {
222 pr_info("reserve_mem_size:0x%x\n", secmon_size);
223 }
wanwei.jiang24483b32021-12-08 16:57:18 +0800224
wanwei.jiang63f85852022-04-20 18:14:26 +0800225 get_reserver_base_size(pdev);
wanwei.jiang24483b32021-12-08 16:57:18 +0800226#ifdef USE_CMA
wanwei.jiang63f85852022-04-20 18:14:26 +0800227 ret = of_reserved_mem_device_init(&pdev->dev);
228 if (ret) {
229 pr_err("reserve memory init fail:%d\n", ret);
230 return ret;
231 }
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800232
wanwei.jiang63f85852022-04-20 18:14:26 +0800233 page = dma_alloc_from_contiguous(&pdev->dev, secmon_size >> PAGE_SHIFT, 0, 0);
234 if (!page) {
235 pr_err("alloc page failed, ret:%p\n", page);
236 return -ENOMEM;
237 }
238 pr_debug("get page:%p, %lx\n", page, page_to_pfn(page));
239 secmon_start_virt = (unsigned long)page_to_virt(page);
wanwei.jiang24483b32021-12-08 16:57:18 +0800240#endif
241
qinglin.li7938f742022-12-01 17:03:20 +0800242#ifdef TEST_ACCESS
wanwei.jiang63f85852022-04-20 18:14:26 +0800243 test_access_secmon();
wanwei.jiang24483b32021-12-08 16:57:18 +0800244#endif
wanwei.jiang63f85852022-04-20 18:14:26 +0800245 }
246
Lei Zhang3faeb772022-02-22 09:53:59 +0800247 sharemem_in_base = ram_vmap(phy_in_base, sharemem_in_size);
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800248 if (!sharemem_in_base) {
qinglin.liafe35bd2022-01-18 16:09:02 +0800249 pr_err("secmon share mem in buffer remap fail!\n");
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800250 return -ENOMEM;
251 }
Lei Zhang3faeb772022-02-22 09:53:59 +0800252 sharemem_out_base = ram_vmap(phy_out_base, sharemem_out_size);
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800253 if (!sharemem_out_base) {
qinglin.liafe35bd2022-01-18 16:09:02 +0800254 pr_err("secmon share mem out buffer remap fail!\n");
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800255 return -ENOMEM;
256 }
257 secmon_dev_registered = DEV_REGISTERED;
258 pr_info("share in base: 0x%lx, share out base: 0x%lx\n",
259 (long)sharemem_in_base, (long)sharemem_out_base);
260 pr_info("phy_in_base: 0x%lx, phy_out_base: 0x%lx\n",
261 phy_in_base, phy_out_base);
262
263 return ret;
264}
265
wanwei.jiang24483b32021-12-08 16:57:18 +0800266#ifdef USE_CMA
267void __init secmon_clear_cma_mmu(void)
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800268{
269 struct device_node *np;
270 unsigned int clear[2] = {};
271
272 np = of_find_node_by_name(NULL, "secmon");
273 if (!np)
274 return;
275
276 if (of_property_read_u32_array(np, "clear_range", clear, 2))
277 pr_info("can't fine clear_range\n");
278 else
279 pr_info("clear_range:%x %x\n", clear[0], clear[1]);
280
281 if (clear[0]) {
282 struct page *page = phys_to_page(clear[0]);
283 int cnt = clear[1] / PAGE_SIZE;
284
wanwei.jiang24483b32021-12-08 16:57:18 +0800285 cma_mmu_op(page, cnt, 0); //cma_mmu_op() implemented in kernel
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800286 }
wanwei.jiang24483b32021-12-08 16:57:18 +0800287}
288#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800289
290static const struct of_device_id secmon_dt_match[] = {
291 { .compatible = "amlogic, secmon" },
292 { /* sentinel */ },
293};
294
295static struct platform_driver secmon_platform_driver = {
296 .probe = secmon_probe,
297 .driver = {
298 .owner = THIS_MODULE,
299 .name = "secmon",
300 .of_match_table = secmon_dt_match,
301 },
302};
303
luke.liu824a1772024-09-29 14:04:13 +0800304#ifdef CONFIG_STDSECUMEM
305static int __init setup_secmon_nosave(void)
306{
307 unsigned long start_pfn = virt_to_pfn(secmon_start_virt);
308 unsigned long end_pfn = virt_to_pfn(secmon_start_virt + secmon_size);
309
310 register_nosave_region(start_pfn, end_pfn);
311 return 0;
312}
313#endif
314
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800315int __init meson_secmon_init(void)
316{
317 int ret;
318
319 ret = platform_driver_register(&secmon_platform_driver);
luke.liu824a1772024-09-29 14:04:13 +0800320#ifdef CONFIG_STDSECUMEM
321 setup_secmon_nosave();
322#endif
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800323 WARN((secmon_dev_registered != DEV_REGISTERED),
wanwei.jiang24483b32021-12-08 16:57:18 +0800324 "ERROR: secmon device must be enable!!!\n");
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800325 return ret;
326}
327
Blance Tang063d2ad2023-04-12 15:05:34 +0800328static int __init secmon_buf_device_init(struct reserved_mem *rmem, struct device *dev)
329{
330 return 0;
331}
332
333static const struct reserved_mem_ops secmon_buf_ops = {
334 .device_init = secmon_buf_device_init,
335};
336
337static int __init secmon_mem_setup(struct reserved_mem *rmem)
338{
339 rmem->ops = &secmon_buf_ops;
340 return 0;
341}
342
343RESERVEDMEM_OF_DECLARE(buf, "amlogic, aml_secmon_memory", secmon_mem_setup);
344
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800345void meson_sm_mutex_lock(void)
346{
347 mutex_lock(&sharemem_mutex);
348}
349EXPORT_SYMBOL(meson_sm_mutex_lock);
350
351void meson_sm_mutex_unlock(void)
352{
353 mutex_unlock(&sharemem_mutex);
354}
355EXPORT_SYMBOL(meson_sm_mutex_unlock);
356
357void __iomem *get_meson_sm_input_base(void)
358{
359 return sharemem_in_base;
360}
361EXPORT_SYMBOL(get_meson_sm_input_base);
wanwei.jiangdd140762022-04-27 20:56:00 +0800362
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800363void __iomem *get_meson_sm_output_base(void)
364{
365 return sharemem_out_base;
366}
367EXPORT_SYMBOL(get_meson_sm_output_base);
368
369long get_secmon_phy_input_base(void)
370{
371 return phy_in_base;
372}
373EXPORT_SYMBOL(get_secmon_phy_input_base);
374
375long get_secmon_phy_output_base(void)
376{
377 return phy_out_base;
378}
wanwei.jiangdd140762022-04-27 20:56:00 +0800379EXPORT_SYMBOL(get_secmon_phy_output_base);
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800380
381unsigned int get_secmon_sharemem_in_size(void)
382{
383 return sharemem_in_size;
384}
385EXPORT_SYMBOL(get_secmon_sharemem_in_size);
wanwei.jiangdd140762022-04-27 20:56:00 +0800386
wanwei.jiangd8cfbc12021-12-08 16:32:55 +0800387unsigned int get_secmon_sharemem_out_size(void)
388{
389 return sharemem_out_size;
390}
391EXPORT_SYMBOL(get_secmon_sharemem_out_size);
392