[RAMEN9610-15045] [COMMON] ASoC: abox: remove unused memory
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / sound / soc / samsung / abox / abox_dbg.c
CommitLineData
18a6abd7
S
1/* sound/soc/samsung/abox/abox_dbg.c
2 *
3 * ALSA SoC Audio Layer - Samsung Abox Debug driver
4 *
5 * Copyright (c) 2016 Samsung Electronics Co. Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11/* #define DEBUG */
12#include <linux/io.h>
13#include <linux/device.h>
14#include <linux/debugfs.h>
15#include <linux/module.h>
16#include <linux/iommu.h>
17#include <linux/of_reserved_mem.h>
18#include <linux/pm_runtime.h>
19#include <linux/sched/clock.h>
54cba7b8
HK
20#include <linux/mm_types.h>
21#include <asm/cacheflush.h>
18a6abd7
S
22#include "abox_dbg.h"
23#include "abox_gic.h"
24
25static struct dentry *abox_dbg_root_dir __read_mostly;
26
27struct dentry *abox_dbg_get_root_dir(void)
28{
29 pr_debug("%s\n", __func__);
30
31 if (abox_dbg_root_dir == NULL)
32 abox_dbg_root_dir = debugfs_create_dir("abox", NULL);
33
34 return abox_dbg_root_dir;
35}
36
37void abox_dbg_print_gpr_from_addr(struct device *dev, struct abox_data *data,
38 unsigned int *addr)
39{
40 int i;
41 char version[4];
42
43 memcpy(version, &data->calliope_version, sizeof(version));
44
45 dev_info(dev, "========================================\n");
46 dev_info(dev, "A-Box CPU register dump (%c%c%c%c)\n",
47 version[3], version[2], version[1], version[0]);
48 dev_info(dev, "----------------------------------------\n");
49 for (i = 0; i <= 14; i++)
50 dev_info(dev, "CA7_R%02d : %08x\n", i, *addr++);
51 dev_info(dev, "CA7_PC : %08x\n", *addr++);
52 dev_info(dev, "========================================\n");
53}
54
55void abox_dbg_print_gpr(struct device *dev, struct abox_data *data)
56{
57 int i;
58 char version[4];
59
60 memcpy(version, &data->calliope_version, sizeof(version));
61
62 dev_info(dev, "========================================\n");
63 dev_info(dev, "A-Box CPU register dump (%c%c%c%c)\n",
64 version[3], version[2], version[1], version[0]);
65 dev_info(dev, "----------------------------------------\n");
66 for (i = 0; i <= 14; i++) {
67 dev_info(dev, "CA7_R%02d : %08x\n", i,
68 readl(data->sfr_base + ABOX_CPU_R(i)));
69 }
70 dev_info(dev, "CA7_PC : %08x\n",
71 readl(data->sfr_base + ABOX_CPU_PC));
72 dev_info(dev, "CA7_L2C_STATUS : %08x\n",
73 readl(data->sfr_base + ABOX_CPU_L2C_STATUS));
74 dev_info(dev, "========================================\n");
75}
76
77struct abox_dbg_dump {
78 char sram[SZ_512K];
18a6abd7
S
79 char dram[DRAM_FIRMWARE_SIZE];
80 u32 sfr[SZ_64K / sizeof(u32)];
81 u32 sfr_gic_gicd[SZ_4K / sizeof(u32)];
82 unsigned int gpr[17];
83 long long time;
84 char reason[SZ_32];
85};
86
87struct abox_dbg_dump_min {
88 char sram[SZ_512K];
54cba7b8
HK
89 void *dram;
90 struct page **pages;
18a6abd7
S
91 u32 sfr[SZ_64K / sizeof(u32)];
92 u32 sfr_gic_gicd[SZ_4K / sizeof(u32)];
93 unsigned int gpr[17];
94 long long time;
95 char reason[SZ_32];
96};
97
98static struct abox_dbg_dump (*p_abox_dbg_dump)[ABOX_DBG_DUMP_COUNT];
99static struct abox_dbg_dump_min (*p_abox_dbg_dump_min)[ABOX_DBG_DUMP_COUNT];
100static struct reserved_mem *abox_rmem;
101
102static int __init abox_rmem_setup(struct reserved_mem *rmem)
103{
104 pr_info("%s: base=%pa, size=%pa\n", __func__, &rmem->base, &rmem->size);
105
106 abox_rmem = rmem;
107 if (sizeof(*p_abox_dbg_dump) <= abox_rmem->size)
108 p_abox_dbg_dump = phys_to_virt(abox_rmem->base);
109 else if (sizeof(*p_abox_dbg_dump_min) <= abox_rmem->size)
110 p_abox_dbg_dump_min = phys_to_virt(abox_rmem->base);
111
112 return 0;
113}
114
115RESERVEDMEM_OF_DECLARE(abox_rmem, "exynos,abox_rmem", abox_rmem_setup);
116
54cba7b8
HK
117static void *abox_dbg_alloc_mem_atomic(struct device *dev, struct abox_dbg_dump_min *p_dump)
118{
119 int i, j;
120 int npages = DRAM_FIRMWARE_SIZE / PAGE_SIZE;
121 struct page **tmp;
fcf9747a 122 gfp_t alloc_gfp_flag = GFP_ATOMIC;
54cba7b8
HK
123
124 p_dump->pages = kzalloc(sizeof(struct page *) * npages, alloc_gfp_flag);
125 if (!p_dump->pages) {
126 dev_info(dev, "Failed to allocate array of struct pages\n");
127 return NULL;
128 }
129
130 tmp = p_dump->pages;
131 for (i = 0; i < npages; i++, tmp++) {
132 *tmp = alloc_page(alloc_gfp_flag);
133 if (*tmp == NULL) {
134 pr_err("Failed to allocate pages for abox debug\n");
135 goto free_pg;
136 }
137 }
138
139 return vm_map_ram(p_dump->pages, npages, -1, PAGE_KERNEL);
140
141free_pg:
142 tmp = p_dump->pages;
143 for (j = 0; j < i; j++, tmp++)
144 __free_pages(*tmp, 0);
145 kfree(p_dump->pages);
146 p_dump->pages = NULL;
147 return NULL;
148}
149
18a6abd7
S
150void abox_dbg_dump_gpr_from_addr(struct device *dev, unsigned int *addr,
151 enum abox_dbg_dump_src src, const char *reason)
152{
153 int i;
154
155 dev_dbg(dev, "%s\n", __func__);
156
157 if (!abox_is_on()) {
158 dev_info(dev, "%s is skipped due to no power\n", __func__);
159 return;
160 }
161
162 if (p_abox_dbg_dump) {
163 struct abox_dbg_dump *p_dump = &(*p_abox_dbg_dump)[src];
164
165 p_dump->time = sched_clock();
166 strncpy(p_dump->reason, reason, sizeof(p_dump->reason) - 1);
167 for (i = 0; i <= 14; i++)
168 p_dump->gpr[i] = *addr++;
169 p_dump->gpr[i++] = *addr++;
170 } else if (p_abox_dbg_dump_min) {
171 struct abox_dbg_dump_min *p_dump = &(*p_abox_dbg_dump_min)[src];
172
173 p_dump->time = sched_clock();
174 strncpy(p_dump->reason, reason, sizeof(p_dump->reason) - 1);
175 for (i = 0; i <= 14; i++)
176 p_dump->gpr[i] = *addr++;
177 p_dump->gpr[i++] = *addr++;
178 }
179}
180
181void abox_dbg_dump_gpr(struct device *dev, struct abox_data *data,
182 enum abox_dbg_dump_src src, const char *reason)
183{
184 int i;
185
186 dev_dbg(dev, "%s\n", __func__);
187
188 if (!abox_is_on()) {
189 dev_info(dev, "%s is skipped due to no power\n", __func__);
190 return;
191 }
192
193 if (p_abox_dbg_dump) {
194 struct abox_dbg_dump *p_dump = &(*p_abox_dbg_dump)[src];
195
196 p_dump->time = sched_clock();
197 strncpy(p_dump->reason, reason, sizeof(p_dump->reason) - 1);
198 for (i = 0; i <= 14; i++)
199 p_dump->gpr[i] = readl(data->sfr_base + ABOX_CPU_R(i));
200 p_dump->gpr[i++] = readl(data->sfr_base + ABOX_CPU_PC);
201 p_dump->gpr[i++] = readl(data->sfr_base + ABOX_CPU_L2C_STATUS);
202 } else if (p_abox_dbg_dump_min) {
203 struct abox_dbg_dump_min *p_dump = &(*p_abox_dbg_dump_min)[src];
204
205 p_dump->time = sched_clock();
206 strncpy(p_dump->reason, reason, sizeof(p_dump->reason) - 1);
207 for (i = 0; i <= 14; i++)
208 p_dump->gpr[i] = readl(data->sfr_base + ABOX_CPU_R(i));
209 p_dump->gpr[i++] = readl(data->sfr_base + ABOX_CPU_PC);
210 p_dump->gpr[i++] = readl(data->sfr_base + ABOX_CPU_L2C_STATUS);
211 }
212}
213
214void abox_dbg_dump_mem(struct device *dev, struct abox_data *data,
215 enum abox_dbg_dump_src src, const char *reason)
216{
217 struct abox_gic_data *gic_data = dev_get_drvdata(data->dev_gic);
218
219 dev_dbg(dev, "%s\n", __func__);
220
221 if (!abox_is_on()) {
222 dev_info(dev, "%s is skipped due to no power\n", __func__);
223 return;
224 }
225
226 if (p_abox_dbg_dump) {
227 struct abox_dbg_dump *p_dump = &(*p_abox_dbg_dump)[src];
228
229 p_dump->time = sched_clock();
230 strncpy(p_dump->reason, reason, sizeof(p_dump->reason) - 1);
231 memcpy_fromio(p_dump->sram, data->sram_base, data->sram_size);
18a6abd7
S
232 memcpy(p_dump->dram, data->dram_base, sizeof(p_dump->dram));
233 memcpy_fromio(p_dump->sfr, data->sfr_base, sizeof(p_dump->sfr));
234 memcpy_fromio(p_dump->sfr_gic_gicd, gic_data->gicd_base,
235 sizeof(p_dump->sfr_gic_gicd));
236 } else if (p_abox_dbg_dump_min) {
237 struct abox_dbg_dump_min *p_dump = &(*p_abox_dbg_dump_min)[src];
18a6abd7
S
238 p_dump->time = sched_clock();
239 strncpy(p_dump->reason, reason, sizeof(p_dump->reason) - 1);
240 memcpy_fromio(p_dump->sram, data->sram_base, data->sram_size);
18a6abd7
S
241 memcpy_fromio(p_dump->sfr, data->sfr_base, sizeof(p_dump->sfr));
242 memcpy_fromio(p_dump->sfr_gic_gicd, gic_data->gicd_base,
243 sizeof(p_dump->sfr_gic_gicd));
9a1fe33c
PJ
244 if (!p_dump->dram)
245 p_dump->dram = abox_dbg_alloc_mem_atomic(dev, p_dump);
246
54cba7b8
HK
247 if (!IS_ERR_OR_NULL(p_dump->dram)) {
248 memcpy(p_dump->dram, data->dram_base, DRAM_FIRMWARE_SIZE);
249 flush_cache_all();
250 } else {
251 dev_info(dev, "Failed to save ABOX dram\n");
252 }
18a6abd7
S
253 }
254}
255
256void abox_dbg_dump_gpr_mem(struct device *dev, struct abox_data *data,
257 enum abox_dbg_dump_src src, const char *reason)
258{
259 abox_dbg_dump_gpr(dev, data, src, reason);
260 abox_dbg_dump_mem(dev, data, src, reason);
261}
262
263struct abox_dbg_dump_simple {
264 char sram[SZ_512K];
18a6abd7
S
265 u32 sfr[SZ_64K / sizeof(u32)];
266 u32 sfr_gic_gicd[SZ_4K / sizeof(u32)];
267 unsigned int gpr[17];
268 long long time;
269 char reason[SZ_32];
270};
271
272static struct abox_dbg_dump_simple abox_dump_simple;
273
274void abox_dbg_dump_simple(struct device *dev, struct abox_data *data,
275 const char *reason)
276{
277 struct abox_gic_data *gic_data = dev_get_drvdata(data->dev_gic);
278 int i;
279
280 dev_info(dev, "%s\n", __func__);
281
282 if (!abox_is_on()) {
283 dev_info(dev, "%s is skipped due to no power\n", __func__);
284 return;
285 }
286
287 abox_dump_simple.time = sched_clock();
288 strncpy(abox_dump_simple.reason, reason,
289 sizeof(abox_dump_simple.reason) - 1);
290 for (i = 0; i <= 14; i++)
291 abox_dump_simple.gpr[i] = readl(data->sfr_base + ABOX_CPU_R(i));
292 abox_dump_simple.gpr[i++] = readl(data->sfr_base + ABOX_CPU_PC);
293 abox_dump_simple.gpr[i++] = readl(data->sfr_base + ABOX_CPU_L2C_STATUS);
294 memcpy_fromio(abox_dump_simple.sram, data->sram_base, data->sram_size);
18a6abd7
S
295 memcpy_fromio(abox_dump_simple.sfr, data->sfr_base,
296 sizeof(abox_dump_simple.sfr));
297 memcpy_fromio(abox_dump_simple.sfr_gic_gicd, gic_data->gicd_base,
298 sizeof(abox_dump_simple.sfr_gic_gicd));
299}
300
301static atomic_t abox_error_count = ATOMIC_INIT(0);
302
303void abox_dbg_report_status(struct device *dev, bool ok)
304{
305 char env[32] = {0,};
306 char *envp[2] = {env, NULL};
307
308 dev_info(dev, "%s\n", __func__);
309
310 if (ok)
311 atomic_set(&abox_error_count, 0);
312 else
313 atomic_inc(&abox_error_count);
314
315 snprintf(env, sizeof(env), "ERR_CNT=%d",
316 atomic_read(&abox_error_count));
317 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
318}
319
320int abox_dbg_get_error_count(struct device *dev)
321{
322 int count = atomic_read(&abox_error_count);
323
324 dev_dbg(dev, "%s: %d\n", __func__, count);
325
326 return count;
327}
328
329static ssize_t calliope_sram_read(struct file *file, struct kobject *kobj,
330 struct bin_attribute *battr, char *buf,
331 loff_t off, size_t size)
332{
333 struct device *dev = kobj_to_dev(kobj);
334 struct device *dev_abox = dev->parent;
335
336 dev_dbg(dev, "%s(%lld, %zu)\n", __func__, off, size);
337
338 if (pm_runtime_get_if_in_use(dev_abox) > 0) {
339 memcpy_fromio(buf, battr->private + off, size);
340 pm_runtime_put(dev_abox);
341 } else {
342 memset(buf, 0x0, size);
343 }
344
345 return size;
346}
347
18a6abd7
S
348static ssize_t calliope_dram_read(struct file *file, struct kobject *kobj,
349 struct bin_attribute *battr, char *buf,
350 loff_t off, size_t size)
351{
352 struct device *dev = kobj_to_dev(kobj);
353
354 dev_dbg(dev, "%s(%lld, %zu)\n", __func__, off, size);
355
356 memcpy(buf, battr->private + off, size);
357 return size;
358}
359
360/* size will be updated later */
361static BIN_ATTR_RO(calliope_sram, 0);
18a6abd7
S
362static BIN_ATTR_RO(calliope_dram, DRAM_FIRMWARE_SIZE);
363static struct bin_attribute *calliope_bin_attrs[] = {
364 &bin_attr_calliope_sram,
18a6abd7
S
365 &bin_attr_calliope_dram,
366};
367
368static ssize_t gpr_show(struct device *dev,
369 struct device_attribute *attr, char *buf)
370{
371 struct abox_data *data = dev_get_drvdata(dev->parent);
372 char version[4];
373 char *pbuf = buf;
374 int i;
375
376 if (!abox_is_on()) {
377 dev_info(dev, "%s is skipped due to no power\n", __func__);
378 return -EFAULT;
379 }
380
381 memcpy(version, &data->calliope_version, sizeof(version));
382
383 pbuf += sprintf(pbuf, "========================================\n");
384 pbuf += sprintf(pbuf, "A-Box CPU register dump (%c%c%c%c)\n",
385 version[3], version[2], version[1], version[0]);
386 pbuf += sprintf(pbuf, "----------------------------------------\n");
387 for (i = 0; i <= 14; i++) {
388 pbuf += sprintf(pbuf, "CA7_R%02d : %08x\n", i,
389 readl(data->sfr_base + ABOX_CPU_R(i)));
390 }
391 pbuf += sprintf(pbuf, "CA7_PC : %08x\n",
392 readl(data->sfr_base + ABOX_CPU_PC));
393 pbuf += sprintf(pbuf, "CA7_L2C_STATUS : %08x\n",
394 readl(data->sfr_base + ABOX_CPU_L2C_STATUS));
395 pbuf += sprintf(pbuf, "========================================\n");
396
397 return pbuf - buf;
398}
399
400static DEVICE_ATTR_RO(gpr);
401
402static int samsung_abox_debug_probe(struct platform_device *pdev)
403{
404 struct device *dev = &pdev->dev;
405 struct device *abox_dev = dev->parent;
406 struct abox_data *data = dev_get_drvdata(abox_dev);
407 int i, ret;
408
409 dev_dbg(dev, "%s\n", __func__);
410
411 if (abox_rmem == NULL)
412 return -ENOMEM;
413
414 dev_info(dev, "%s(%pa) is mapped on %p with size of %pa\n",
415 "dump buffer", &abox_rmem->base,
416 phys_to_virt(abox_rmem->base), &abox_rmem->size);
417 iommu_map(data->iommu_domain, IOVA_DUMP_BUFFER, abox_rmem->base,
418 abox_rmem->size, 0);
419 data->dump_base = phys_to_virt(abox_rmem->base);
420 data->dump_base_phys = abox_rmem->base;
54cba7b8 421 memset(data->dump_base, 0x0, abox_rmem->size);
18a6abd7
S
422 ret = device_create_file(dev, &dev_attr_gpr);
423 bin_attr_calliope_sram.size = data->sram_size;
424 bin_attr_calliope_sram.private = data->sram_base;
18a6abd7
S
425 bin_attr_calliope_dram.private = data->dram_base;
426 for (i = 0; i < ARRAY_SIZE(calliope_bin_attrs); i++) {
427 struct bin_attribute *battr = calliope_bin_attrs[i];
428
429 ret = device_create_bin_file(dev, battr);
430 if (ret < 0)
431 dev_warn(dev, "Failed to create file: %s\n",
432 battr->attr.name);
433 }
434
435 return ret;
436}
437
438static int samsung_abox_debug_remove(struct platform_device *pdev)
439{
440 struct device *dev = &pdev->dev;
54cba7b8 441 int i;
18a6abd7
S
442
443 dev_dbg(dev, "%s\n", __func__);
54cba7b8 444 for (i = 0; i < ABOX_DBG_DUMP_COUNT; i++) {
9a1fe33c
PJ
445 struct page **tmp = p_abox_dbg_dump_min[i]->pages;
446
447 if (p_abox_dbg_dump_min[i]->dram)
448 vm_unmap_ram(p_abox_dbg_dump_min[i]->dram,
449 DRAM_FIRMWARE_SIZE);
450 if (tmp) {
451 int j;
452
453 for (j = 0; j < DRAM_FIRMWARE_SIZE / PAGE_SIZE; j++, tmp++)
454 __free_pages(*tmp, 0);
455 kfree(p_abox_dbg_dump_min[i]->pages);
456 p_abox_dbg_dump_min[i]->pages = NULL;
54cba7b8
HK
457 }
458 }
18a6abd7
S
459
460 return 0;
461}
462
463static const struct of_device_id samsung_abox_debug_match[] = {
464 {
465 .compatible = "samsung,abox-debug",
466 },
467 {},
468};
469MODULE_DEVICE_TABLE(of, samsung_abox_debug_match);
470
471static struct platform_driver samsung_abox_debug_driver = {
472 .probe = samsung_abox_debug_probe,
473 .remove = samsung_abox_debug_remove,
474 .driver = {
475 .name = "samsung-abox-debug",
476 .owner = THIS_MODULE,
477 .of_match_table = of_match_ptr(samsung_abox_debug_match),
478 },
479};
480
481module_platform_driver(samsung_abox_debug_driver);
482
483MODULE_AUTHOR("Gyeongtaek Lee, <gt82.lee@samsung.com>");
484MODULE_DESCRIPTION("Samsung ASoC A-Box Debug Driver");
485MODULE_ALIAS("platform:samsung-abox-debug");
486MODULE_LICENSE("GPL");