1 /*
2 * dump registers sysfs driver
3 *
4 * Copyright(c) 2015-2018 Allwinnertech Co., Ltd.
5 * http://www.allwinnertech.com
6 *
7 * Author: Liugang <liugang@allwinnertech.com>
8 * Xiafeng <xiafeng@allwinnertech.com>
9 * Martin <wuyan@allwinnertech.com>
10 * Lewis <liuyu@allwinnertech.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/device.h>
20 #include <linux/err.h>
21 #include <linux/kdev_t.h>
22 #include <linux/clk.h>
23 #include <linux/io.h>
24 #include <linux/slab.h>
25 #include <linux/miscdevice.h>
26 #include <linux/seq_file.h>
27 #include <linux/platform_device.h>
28 #include <linux/sysfs.h>
29 #include <linux/mod_devicetable.h>
30
31 #include <linux/suspend.h>
32 #include <linux/syscore_ops.h>
33
34 #include "dump_reg.h"
35
36 /* the register and vaule to be test by dump_reg */
37 static u32 test_addr;
38 static u32 test_size;
39 static struct class *dump_class;
40
41 /* Access in byte mode ? 1: byte-mode, 0: word-mode */
42 static unsigned int rw_byte_mode;
43
44 /* for dump_reg class */
45 static struct dump_addr dump_para;
46 static struct write_group *wt_group;
47 static struct compare_group *cmp_group;
48
49 static u32 standby_dump_ctrl;
50 static char *standby_dump_buff;
51
52
53 enum {
54 DUMP_CTRL_DEV_PREPARE = 0,
55 DUMP_CTRL_DEV_SUSPEND,
56 DUMP_CTRL_DEV_SUSPEND_LATE,
57 DUMP_CTRL_DEV_SUSPEND_NOIRQ,
58 DUMP_CTRL_SYSCORE_SUSPEND,
59
60
61 DUMP_CTRL_DEV_COMPLETE = 8,
62 DUMP_CTRL_DEV_RESUME,
63 DUMP_CTRL_DEV_RESUME_EARLY,
64 DUMP_CTRL_DEV_RESUME_NOIRQ,
65 DUMP_CTRL_SYSCORE_RESUME,
66
67 DUMP_CTRL_SUSPEND_WRITE = 16,
68 DUMP_CTRL_RESUME_WRITE = 17,
69 };
70
71
_read(void __iomem * vaddr)72 static u32 _read(void __iomem *vaddr)
73 {
74 if (rw_byte_mode)
75 return (u32)readb(vaddr);
76 else
77 return readl(vaddr);
78 }
79
_write(u32 val,void __iomem * vaddr)80 static void _write(u32 val, void __iomem *vaddr)
81 {
82 if (rw_byte_mode)
83 writeb((u8)val, vaddr);
84 else
85 writel(val, vaddr);
86 }
87
_io_remap(unsigned long paddr,size_t size)88 static void __iomem *_io_remap(unsigned long paddr, size_t size)
89 {
90 return ioremap(paddr, size);
91 }
92
_io_unmap(void __iomem * vaddr)93 static void _io_unmap(void __iomem *vaddr)
94 {
95 iounmap(vaddr);
96 }
97
_mem_remap(unsigned long paddr,size_t size)98 static void __iomem *_mem_remap(unsigned long paddr, size_t size)
99 {
100 return (void __iomem *)phys_to_virt(paddr);
101 }
102
103 /*
104 * Convert a physical address (which is already mapped) to virtual address
105 */
_get_vaddr(struct dump_addr * dump_addr,unsigned long uaddr)106 static void __iomem *_get_vaddr(struct dump_addr *dump_addr, unsigned long uaddr)
107 {
108 unsigned long offset = uaddr - dump_addr->uaddr_start;
109 return (void __iomem *)(dump_addr->vaddr_start + offset);
110 }
111
112 const struct dump_struct dump_table[] = {
113 {
114 .addr_start = SUNXI_IO_PHYS_START,
115 .addr_end = SUNXI_IO_PHYS_END,
116 .remap = _io_remap,
117 .unmap = _io_unmap,
118 .get_vaddr = _get_vaddr,
119 .read = _read,
120 .write = _write,
121 },
122 {
123 .addr_start = SUNXI_PLAT_PHYS_START,
124 .addr_end = SUNXI_PLAT_PHYS_END,
125 .remap = _mem_remap,
126 .unmap = NULL,
127 .get_vaddr = _get_vaddr,
128 .read = _read,
129 .write = _write,
130 },
131 #if defined(SUNXI_IOMEM_START)
132 {
133 .addr_start = SUNXI_IOMEM_START,
134 .addr_end = SUNXI_IOMEM_END,
135 .remap = NULL, /* .remap = NULL: uaddr is a virtual address */
136 .unmap = NULL,
137 .get_vaddr = _get_vaddr,
138 .read = _read,
139 .write = _write,
140 },
141 #endif
142 {
143 .addr_start = SUNXI_MEM_PHYS_START,
144 .addr_end = SUNXI_MEM_PHYS_END,
145 .remap = NULL, /* .remap = NULL: uaddr is a virtual address */
146 .unmap = NULL,
147 .get_vaddr = _get_vaddr,
148 .read = _read,
149 .write = _write,
150 },
151 };
152
153 /**
154 * __addr_valid - check if @uaddr is valid.
155 * @uaddr: addr to judge.
156 *
157 * return index if @addr is valid, -ENXIO if not.
158 */
__addr_valid(unsigned long uaddr)159 static int __addr_valid(unsigned long uaddr)
160 {
161 int i;
162
163 for (i = 0; i < ARRAY_SIZE(dump_table); i++)
164 if (uaddr >= dump_table[i].addr_start &&
165 uaddr <= dump_table[i].addr_end)
166 return i;
167 return -ENXIO;
168 }
169
170 /**
171 * __dump_regs_ex - dump a range of registers' value, copy to buf.
172 * @dump_addr: start and end address of registers.
173 * @buf: store the dump info.
174 * @buf_size: buf size
175 *
176 * return bytes written to buf, <=0 indicate err
177 */
__dump_regs_ex(struct dump_addr * dump_addr,char * buf,ssize_t buf_size)178 static ssize_t __dump_regs_ex(struct dump_addr *dump_addr, char *buf, ssize_t buf_size)
179 {
180 int index;
181 ssize_t cnt = 0;
182 unsigned long uaddr;
183 unsigned long remap_size;
184 const struct dump_struct *dump;
185
186 /* Make the address 4-bytes aligned */
187 dump_addr->uaddr_start &= (~0x3UL);
188 dump_addr->uaddr_end &= (~0x3UL);
189 remap_size = dump_addr->uaddr_end - dump_addr->uaddr_start + 4;
190
191 index = __addr_valid(dump_addr->uaddr_start);
192 if ((index < 0) || (index != __addr_valid(dump_addr->uaddr_end)) ||
193 (buf == NULL)) {
194 pr_err("%s(): Invalid para: index=%d, start=0x%lx, end=0x%lx, buf=0x%p\n",
195 __func__, index, dump_addr->uaddr_start, dump_addr->uaddr_end, buf);
196 return -EIO;
197 }
198
199 dump = &dump_table[index];
200 if (dump->remap) {
201 dump_addr->vaddr_start = dump->remap(dump_addr->uaddr_start, remap_size);
202 if (!dump_addr->vaddr_start) {
203 pr_err("%s(): remap failed\n", __func__);
204 return -EIO;
205 }
206 } else /* if (dump->remap = NULL), then treat uaddr as a virtual address */
207 dump_addr->vaddr_start = (void __iomem *)dump_addr->uaddr_start;
208
209 if (dump_addr->uaddr_start == dump_addr->uaddr_end) {
210 cnt = sprintf(buf, "0x%08x\n", dump->read(dump_addr->vaddr_start));
211 goto out;
212 }
213
214 for (uaddr = (dump_addr->uaddr_start & ~0x0F); uaddr <= dump_addr->uaddr_end;
215 uaddr += 4) {
216 if (!(uaddr & 0x0F))
217 cnt += snprintf(buf + cnt, buf_size - cnt,
218 "\n" PRINT_ADDR_FMT ":", uaddr);
219
220 if (cnt >= buf_size) {
221 pr_warn("Range too large, strings buffer overflow\n");
222 cnt = buf_size;
223 goto out;
224 }
225
226 if (uaddr < dump_addr->uaddr_start) /* Don't show unused uaddr */
227 /* "0x12345678 ", 11 space */
228 cnt += snprintf(buf + cnt, buf_size - cnt, " ");
229 else
230 cnt += snprintf(buf + cnt, buf_size - cnt, " 0x%08x",
231 dump->read(dump->get_vaddr(dump_addr, uaddr)));
232 }
233 cnt += snprintf(buf + cnt, buf_size - cnt, "\n");
234
235 pr_debug("%s(): start=0x%lx, end=0x%lx, return=%zd\n", __func__,
236 dump_addr->uaddr_start, dump_addr->uaddr_end, cnt);
237
238 out:
239 if (dump->unmap)
240 dump->unmap(dump_addr->vaddr_start);
241
242 return cnt;
243 }
244
245 /**
246 * __parse_dump_str - parse the input string for dump attri.
247 * @buf: the input string, eg: "0x01c20000,0x01c20300".
248 * @size: buf size.
249 * @start: store the start reg's addr parsed from buf, eg 0x01c20000.
250 * @end: store the end reg's addr parsed from buf, eg 0x01c20300.
251 *
252 * return 0 if success, otherwise failed.
253 */
__parse_dump_str(const char * buf,size_t size,unsigned long * start,unsigned long * end)254 static int __parse_dump_str(const char *buf, size_t size,
255 unsigned long *start, unsigned long *end)
256 {
257 char *ptr = NULL;
258 char *ptr2 = (char *)buf;
259 int ret = 0, times = 0;
260
261 /* Support single address mode, some time it haven't ',' */
262 next:
263 /*
264 * Default dump only one register(*start =*end).
265 * If ptr is not NULL, we will cover the default value of end.
266 */
267 if (times == 1)
268 *start = *end;
269
270 if (!ptr2 || (ptr2 - buf) >= size)
271 goto out;
272
273 ptr = ptr2;
274 ptr2 = strnchr(ptr, size - (ptr - buf), ',');
275 if (ptr2) {
276 *ptr2 = '\0';
277 ptr2++;
278 }
279
280 ptr = strim(ptr);
281 if (!strlen(ptr))
282 goto next;
283
284 ret = kstrtoul(ptr, 16, end);
285 if (!ret) {
286 times++;
287 goto next;
288 } else
289 pr_warn("String syntax errors: \"%s\"\n", ptr);
290
291 out:
292 return ret;
293 }
294
295 /**
296 * __write_show - dump a register's value, copy to buf.
297 * @pgroup: the addresses to read.
298 * @buf: store the dump info.
299 *
300 * return bytes written to buf, <=0 indicate err.
301 */
__write_show(struct write_group * pgroup,char * buf,ssize_t len)302 static ssize_t __write_show(struct write_group *pgroup, char *buf, ssize_t len)
303 {
304 #define WR_DATA_FMT PRINT_ADDR_FMT" 0x%08x %s"
305
306 int i = 0;
307 ssize_t cnt = 0;
308 unsigned long reg = 0;
309 u32 val;
310 u8 rval_buf[16];
311 struct dump_addr dump_addr;
312
313 if (!pgroup) {
314 pr_err("%s,%d err, pgroup is NULL!\n", __func__, __LINE__);
315 goto end;
316 }
317
318 cnt += snprintf(buf, len - cnt, WR_PRINT_FMT);
319 if (cnt > len) {
320 cnt = -EINVAL;
321 goto end;
322 }
323
324 for (i = 0; i < pgroup->num; i++) {
325 reg = pgroup->pitem[i].reg_addr;
326 val = pgroup->pitem[i].val;
327 dump_addr.uaddr_start = reg;
328 dump_addr.uaddr_end = reg;
329 if (__dump_regs_ex(&dump_addr, rval_buf, sizeof(rval_buf)) < 0)
330 return -EINVAL;
331
332 cnt +=
333 snprintf(buf + cnt, len - cnt, WR_DATA_FMT, reg, val,
334 rval_buf);
335 if (cnt > len) {
336 cnt = len;
337 goto end;
338 }
339 }
340
341 end:
342 return cnt;
343 }
344
345 /**
346 * __parse_write_str - parse the input string for write attri.
347 * @str: string to be parsed, eg: "0x01c20818 0x55555555".
348 * @reg_addr: store the reg address. eg: 0x01c20818.
349 * @val: store the expect value. eg: 0x55555555.
350 *
351 * return 0 if success, otherwise failed.
352 */
__parse_write_str(char * str,unsigned long * reg_addr,u32 * val)353 static int __parse_write_str(char *str, unsigned long *reg_addr, u32 *val)
354 {
355 char *ptr = str;
356 char *tstr = NULL;
357 int ret = 0;
358
359 /*
360 * Skip the leading whitespace, find the true split symbol.
361 * And it must be 'address value'.
362 */
363 tstr = strim(str);
364 ptr = strchr(tstr, ' ');
365 if (!ptr)
366 return -EINVAL;
367
368 /*
369 * Replaced split symbol with a %NUL-terminator temporary.
370 * Will be fixed at end.
371 */
372 *ptr = '\0';
373 ret = kstrtoul(tstr, 16, reg_addr);
374 if (ret)
375 goto out;
376
377 ret = kstrtou32(skip_spaces(ptr + 1), 16, val);
378
379 out:
380 return ret;
381 }
382
383 /**
384 * __write_item_init - init for write attri. parse input string,
385 * and construct write struct.
386 * @ppgroup: store the struct allocated, the struct contains items parsed from
387 * input buf.
388 * @buf: input string, eg: "0x01c20800 0x00000031,0x01c20818 0x55555555,...".
389 * @size: buf size.
390 *
391 * return 0 if success, otherwise failed.
392 */
__write_item_init(struct write_group ** ppgroup,const char * buf,size_t size)393 static int __write_item_init(struct write_group **ppgroup, const char *buf,
394 size_t size)
395 {
396 char *ptr, *ptr2;
397 unsigned long addr = 0;
398 u32 val;
399 struct write_group *pgroup;
400
401 /* alloc item buffer */
402 pgroup = kmalloc(sizeof(struct write_group), GFP_KERNEL);
403 if (!pgroup)
404 return -ENOMEM;
405
406 pgroup->pitem = kmalloc(sizeof(struct write_item) * MAX_WRITE_ITEM,
407 GFP_KERNEL);
408 if (!pgroup->pitem) {
409 kfree(pgroup);
410 return -ENOMEM;
411 }
412
413 pgroup->num = 0;
414 ptr = (char *)buf;
415 do {
416 ptr2 = strchr(ptr, ',');
417 if (ptr2)
418 *ptr2 = '\0';
419
420 if (!__parse_write_str(ptr, &addr, &val)) {
421 pgroup->pitem[pgroup->num].reg_addr = addr;
422 pgroup->pitem[pgroup->num].val = val;
423 pgroup->num++;
424 } else
425 pr_err("%s: Failed to parse string: %s\n", __func__,
426 ptr);
427
428 if (!ptr2)
429 break;
430
431 ptr = ptr2 + 1;
432 *ptr2 = ',';
433
434 } while (pgroup->num <= MAX_WRITE_ITEM);
435
436 /* free buffer if no valid item */
437 if (pgroup->num == 0) {
438 kfree(pgroup->pitem);
439 kfree(pgroup);
440 return -EINVAL;
441 }
442
443 *ppgroup = pgroup;
444 return 0;
445 }
446
447 /**
448 * __write_item_deinit - reled_addrse memory that cred_addrted by
449 * __write_item_init.
450 * @pgroup: the write struct allocated in __write_item_init.
451 */
__write_item_deinit(struct write_group * pgroup)452 static void __write_item_deinit(struct write_group *pgroup)
453 {
454 if (pgroup != NULL) {
455 if (pgroup->pitem != NULL)
456 kfree(pgroup->pitem);
457 kfree(pgroup);
458 }
459 }
460
461 /**
462 * __compare_regs_ex - dump a range of registers' value, copy to buf.
463 * @pgroup: addresses of registers.
464 * @buf: store the dump info.
465 *
466 * return bytes written to buf, <= 0 indicate err.
467 */
__compare_regs_ex(struct compare_group * pgroup,char * buf,ssize_t len)468 static ssize_t __compare_regs_ex(struct compare_group *pgroup, char *buf,
469 ssize_t len)
470 {
471 #define CMP_DATAO_FMT PRINT_ADDR_FMT" 0x%08x 0x%08x 0x%08x OK\n"
472 #define CMP_DATAE_FMT PRINT_ADDR_FMT" 0x%08x 0x%08x 0x%08x ERR\n"
473
474 int i;
475 ssize_t cnt = 0;
476 unsigned long reg;
477 u32 expect, actual, mask;
478 u8 actualb[16];
479 struct dump_addr dump_addr;
480
481 if (!pgroup) {
482 pr_err("%s,%d err, pgroup is NULL!\n", __func__, __LINE__);
483 goto end;
484 }
485
486 cnt += snprintf(buf, len - cnt, CMP_PRINT_FMT);
487 if (cnt > len) {
488 cnt = -EINVAL;
489 goto end;
490 }
491
492 for (i = 0; i < pgroup->num; i++) {
493 reg = pgroup->pitem[i].reg_addr;
494 expect = pgroup->pitem[i].val_expect;
495 dump_addr.uaddr_start = reg;
496 dump_addr.uaddr_end = reg;
497 if (__dump_regs_ex(&dump_addr, actualb, sizeof(actualb)) < 0)
498 return -EINVAL;
499
500 if (kstrtou32(actualb, 16, &actual))
501 return -EINVAL;
502
503 mask = pgroup->pitem[i].val_mask;
504 if ((actual & mask) == (expect & mask))
505 cnt +=
506 snprintf(buf + cnt, len - cnt, CMP_DATAO_FMT, reg,
507 expect, actual, mask);
508 else
509 cnt +=
510 snprintf(buf + cnt, len - cnt, CMP_DATAE_FMT, reg,
511 expect, actual, mask);
512 if (cnt > len) {
513 cnt = -EINVAL;
514 goto end;
515 }
516 }
517
518 end:
519 return cnt;
520 }
521
522 /**
523 * __parse_compare_str - parse the input string for compare attri.
524 * @str: string to be parsed, eg: "0x01c20000 0x80000011 0x00000011".
525 * @reg_addr: store the reg address. eg: 0x01c20000.
526 * @val_expect: store the expect value. eg: 0x80000011.
527 * @val_mask: store the mask value. eg: 0x00000011.
528 *
529 * return 0 if success, otherwise failed.
530 */
__parse_compare_str(char * str,unsigned long * reg_addr,u32 * val_expect,u32 * val_mask)531 static int __parse_compare_str(char *str, unsigned long *reg_addr,
532 u32 *val_expect, u32 *val_mask)
533 {
534 unsigned long result_addr[3] = { 0 };
535 char *ptr = str;
536 char *ptr2 = NULL;
537 int i, ret = 0;
538
539 for (i = 0; i < ARRAY_SIZE(result_addr); i++) {
540 ptr = skip_spaces(ptr);
541 ptr2 = strchr(ptr, ' ');
542 if (ptr2)
543 *ptr2 = '\0';
544
545 ret = kstrtoul(ptr, 16, &result_addr[i]);
546 if (!ptr2)
547 break;
548
549 *ptr2 = ' ';
550
551 if (ret)
552 break;
553
554 ptr = ptr2 + 1;
555 }
556
557 *reg_addr = result_addr[0];
558 *val_expect = (u32) result_addr[1];
559 *val_mask = (u32) result_addr[2];
560
561 return ret;
562 }
563
564 /**
565 * __compare_item_init - init for compare attri. parse input string,
566 * and construct compare struct.
567 * @ppgroup: store the struct allocated, the struct contains items parsed from
568 * input buf.
569 * @buf: input string,
570 * eg: "0x01c20000 0x80000011 0x00000011,0x01c20004 0x0000c0a4 0x0000c0a0,...".
571 * @size: buf size.
572 *
573 * return 0 if success, otherwise failed.
574 */
__compare_item_init(struct compare_group ** ppgroup,const char * buf,size_t size)575 static int __compare_item_init(struct compare_group **ppgroup,
576 const char *buf, size_t size)
577 {
578 char *ptr, *ptr2;
579 unsigned long addr = 0;
580 u32 val_expect = 0, val_mask = 0;
581 struct compare_group *pgroup = NULL;
582
583 /* alloc item buffer */
584 pgroup = kmalloc(sizeof(struct compare_group), GFP_KERNEL);
585 if (pgroup == NULL)
586 return -EINVAL;
587
588 pgroup->pitem = kmalloc(sizeof(struct compare_item) * MAX_COMPARE_ITEM,
589 GFP_KERNEL);
590 if (pgroup->pitem == NULL) {
591 kfree(pgroup);
592 return -EINVAL;
593 }
594
595 pgroup->num = 0;
596
597 /* get item from buf */
598 ptr = (char *)buf;
599 do {
600 ptr2 = strchr(ptr, ',');
601 if (ptr2)
602 *ptr2 = '\0';
603
604 if (!__parse_compare_str(ptr, &addr, &val_expect, &val_mask)) {
605 pgroup->pitem[pgroup->num].reg_addr = addr;
606 pgroup->pitem[pgroup->num].val_expect = val_expect;
607 pgroup->pitem[pgroup->num].val_mask = val_mask;
608 pgroup->num++;
609 } else
610 pr_err("%s: Failed to parse string: %s\n", __func__,
611 ptr);
612
613 if (!ptr2)
614 break;
615
616 *ptr2 = ',';
617 ptr = ptr2 + 1;
618
619 } while (pgroup->num <= MAX_COMPARE_ITEM);
620
621 /* free buffer if no valid item */
622 if (pgroup->num == 0) {
623 kfree(pgroup->pitem);
624 kfree(pgroup);
625 return -EINVAL;
626 }
627 *ppgroup = pgroup;
628
629 return 0;
630 }
631
632 /**
633 * __compare_item_deinit - reled_addrse memory that cred_addrted by
634 * __compare_item_init.
635 * @pgroup: the compare struct allocated in __compare_item_init.
636 */
__compare_item_deinit(struct compare_group * pgroup)637 static void __compare_item_deinit(struct compare_group *pgroup)
638 {
639 if (pgroup) {
640 kfree(pgroup->pitem);
641 kfree(pgroup);
642 }
643 }
644
__write_store(struct write_group * group)645 static int __write_store(struct write_group *group)
646 {
647 int i;
648 int index;
649 unsigned long reg;
650 u32 val;
651 const struct dump_struct *dump;
652 struct dump_addr dump_addr;
653
654
655 if (!group)
656 return -1;
657 /**
658 * write reg
659 * it is better if the regs been remaped and unmaped only once,
660 * but we map everytime for the range between min and max address
661 * maybe too large.
662 */
663 for (i = 0; i < group->num; i++) {
664 reg = group->pitem[i].reg_addr;
665 dump_addr.uaddr_start = reg;
666 val = group->pitem[i].val;
667 index = __addr_valid(reg);
668 dump = &dump_table[index];
669 if (dump->remap)
670 dump_addr.vaddr_start = dump->remap(reg, 4);
671 else
672 dump_addr.vaddr_start = (void __iomem *)reg;
673 dump->write(val, dump->get_vaddr(&dump_addr, reg));
674 if (dump->unmap)
675 dump->unmap(dump_addr.vaddr_start);
676 }
677
678 return 0;
679 }
680
standby_dump_ctrl_show(struct class * class,struct class_attribute * attr,char * buf)681 static ssize_t standby_dump_ctrl_show(struct class *class, struct class_attribute *attr,
682 char *buf)
683 {
684 ssize_t size = 0;
685
686 size = sprintf(buf, "0x%08x\n", standby_dump_ctrl);
687
688 return size;
689 }
690
standby_dump_ctrl_store(struct class * class,struct class_attribute * attr,const char * buf,size_t count)691 static ssize_t standby_dump_ctrl_store(struct class *class, struct class_attribute *attr,
692 const char *buf, size_t count)
693 {
694 u32 value = 0;
695 int ret;
696
697 ret = kstrtou32(buf, 16, &value);
698 if (ret) {
699 pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
700 return -EINVAL;
701 }
702
703 standby_dump_ctrl = value;
704
705 pr_info("standby_dump_ctrl change to 0x%08x\n", standby_dump_ctrl);
706
707 return count;
708 }
709
standby_dump_printk(void)710 static int standby_dump_printk(void)
711 {
712 ssize_t cnt = 0;
713
714 if (!standby_dump_buff)
715 return 0;
716
717 cnt = __dump_regs_ex(&dump_para, standby_dump_buff, PAGE_SIZE);
718
719 if (cnt < 0)
720 return -1;
721
722 pr_alert("%s\n", standby_dump_buff);
723
724 return 0;
725 }
726
standby_dump_dev_prepare(struct device * dev)727 static int standby_dump_dev_prepare(struct device *dev)
728 {
729 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_PREPARE)))
730 return 0;
731
732 return standby_dump_printk();
733 }
734
standby_dump_dev_complete(struct device * dev)735 static void standby_dump_dev_complete(struct device *dev)
736 {
737 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_COMPLETE)))
738 return;
739
740 standby_dump_printk();
741 }
742
743
standby_dump_dev_suspend(struct device * dev)744 static int standby_dump_dev_suspend(struct device *dev)
745 {
746 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_SUSPEND)))
747 return 0;
748
749 return standby_dump_printk();
750 }
751
standby_dump_dev_resume(struct device * dev)752 static int standby_dump_dev_resume(struct device *dev)
753 {
754 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_RESUME)))
755 return 0;
756
757 return standby_dump_printk();
758 }
759
standby_dump_dev_suspend_late(struct device * dev)760 static int standby_dump_dev_suspend_late(struct device *dev)
761 {
762 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_SUSPEND_LATE)))
763 return 0;
764
765 return standby_dump_printk();
766 }
767
standby_dump_dev_resume_early(struct device * dev)768 static int standby_dump_dev_resume_early(struct device *dev)
769 {
770 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_RESUME_EARLY)))
771 return 0;
772
773 return standby_dump_printk();
774 }
775
standby_dump_dev_suspend_noirq(struct device * dev)776 static int standby_dump_dev_suspend_noirq(struct device *dev)
777 {
778 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_SUSPEND_NOIRQ)))
779 return 0;
780
781 return standby_dump_printk();
782 }
783
standby_dump_dev_resume_noirq(struct device * dev)784 static int standby_dump_dev_resume_noirq(struct device *dev)
785 {
786 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_DEV_RESUME_NOIRQ)))
787 return 0;
788
789 return standby_dump_printk();
790 }
791
standby_dump_syscore_suspend(void)792 static int standby_dump_syscore_suspend(void)
793 {
794 int ret = 0;
795
796 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_SYSCORE_SUSPEND)))
797 return 0;
798
799 ret = standby_dump_printk();
800 if (ret)
801 return ret;
802
803 if (standby_dump_ctrl & (0x1<<DUMP_CTRL_SUSPEND_WRITE)) {
804 /* flush to reg */
805 __write_store(wt_group);
806
807 __write_show(wt_group, standby_dump_buff, PAGE_SIZE);
808 pr_alert("%s\n", standby_dump_buff);
809 }
810
811 return ret;
812 }
813
standby_dump_syscore_resume(void)814 static void standby_dump_syscore_resume(void)
815 {
816 int ret = 0;
817
818 if (!(standby_dump_ctrl & (0x1<<DUMP_CTRL_SYSCORE_RESUME)))
819 return;
820
821 ret = standby_dump_printk();
822 if (ret)
823 return;
824
825 if (standby_dump_ctrl & (0x1<<DUMP_CTRL_RESUME_WRITE)) {
826 /* flush to reg */
827 __write_store(wt_group);
828
829 __write_show(wt_group, standby_dump_buff, PAGE_SIZE);
830 pr_alert("%s\n", standby_dump_buff);
831 }
832 }
833
834 static struct dev_pm_ops standby_dump_ops = {
835 .prepare = standby_dump_dev_prepare,
836 .complete = standby_dump_dev_complete,
837 .suspend = standby_dump_dev_suspend,
838 .resume = standby_dump_dev_resume,
839 .suspend_late = standby_dump_dev_suspend_late,
840 .resume_early = standby_dump_dev_resume_early,
841 .suspend_noirq = standby_dump_dev_suspend_noirq,
842 .resume_noirq = standby_dump_dev_resume_noirq,
843 };
844
845 static struct syscore_ops standby_dump_syscore = {
846 .suspend = standby_dump_syscore_suspend,
847 .resume = standby_dump_syscore_resume,
848 };
849
850 /**
851 * dump_show - show func of dump attribute.
852 * @dev: class ptr.
853 * @attr: attribute ptr.
854 * @buf: the input buf which contain the start and end reg.
855 * eg: "0x01c20000,0x01c20100\n".
856 *
857 * return size written to the buf, otherwise failed.
858 */
859 static ssize_t
dump_show(struct class * class,struct class_attribute * attr,char * buf)860 dump_show(struct class *class, struct class_attribute *attr, char *buf)
861 {
862 return __dump_regs_ex(&dump_para, buf, PAGE_SIZE);
863 }
864
865 static ssize_t
dump_store(struct class * class,struct class_attribute * attr,const char * buf,size_t count)866 dump_store(struct class *class, struct class_attribute *attr,
867 const char *buf, size_t count)
868 {
869 int index;
870 unsigned long start_reg = 0;
871 unsigned long end_reg = 0;
872
873 if (__parse_dump_str(buf, count, &start_reg, &end_reg)) {
874 pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
875 goto err;
876 }
877
878 index = __addr_valid(start_reg);
879 if ((index < 0) || (index != __addr_valid(end_reg))) {
880 pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
881 goto err;
882 }
883
884 dump_para.uaddr_start = start_reg;
885 dump_para.uaddr_end = end_reg;
886 pr_debug("%s,%d, start_reg:" PRINT_ADDR_FMT ", end_reg:" PRINT_ADDR_FMT
887 "\n", __func__, __LINE__, start_reg, end_reg);
888
889 return count;
890
891 err:
892 dump_para.uaddr_start = 0;
893 dump_para.uaddr_end = 0;
894
895 return -EINVAL;
896 }
897
898 static ssize_t
write_show(struct class * class,struct class_attribute * attr,char * buf)899 write_show(struct class *class, struct class_attribute *attr, char *buf)
900 {
901 /* display write result */
902 return __write_show(wt_group, buf, PAGE_SIZE);
903 }
904
905
906 static ssize_t
write_store(struct class * class,struct class_attribute * attr,const char * buf,size_t count)907 write_store(struct class *class, struct class_attribute *attr,
908 const char *buf, size_t count)
909 {
910
911 /* free if not NULL */
912 if (wt_group) {
913 __write_item_deinit(wt_group);
914 wt_group = NULL;
915 }
916
917 /* parse input buf for items that will be dumped */
918 if (__write_item_init(&wt_group, buf, count) < 0)
919 return -EINVAL;
920
921 if (!(standby_dump_ctrl & \
922 ((0x1<<DUMP_CTRL_SUSPEND_WRITE) | (0x1<<DUMP_CTRL_RESUME_WRITE)))) {
923 /* flush to reg */
924 __write_store(wt_group);
925 } else {
926 pr_alert("Will write it actually when suspend.\n");
927 }
928
929 return count;
930 }
931
932 static ssize_t
compare_show(struct class * class,struct class_attribute * attr,char * buf)933 compare_show(struct class *class, struct class_attribute *attr, char *buf)
934 {
935 /* dump the items */
936 return __compare_regs_ex(cmp_group, buf, PAGE_SIZE);
937 }
938
939 static ssize_t
compare_store(struct class * class,struct class_attribute * attr,const char * buf,size_t count)940 compare_store(struct class *class, struct class_attribute *attr,
941 const char *buf, size_t count)
942 {
943 /* free if struct not null */
944 if (cmp_group) {
945 __compare_item_deinit(cmp_group);
946 cmp_group = NULL;
947 }
948
949 /* parse input buf for items that will be dumped */
950 if (__compare_item_init(&cmp_group, buf, count) < 0)
951 return -EINVAL;
952
953 return count;
954 }
955
956 static ssize_t
rw_byte_show(struct class * class,struct class_attribute * attr,char * buf)957 rw_byte_show(struct class *class, struct class_attribute *attr, char *buf)
958 {
959 return sprintf(buf, "read/write mode: %u(%s)\n", rw_byte_mode,
960 rw_byte_mode ? "byte" : "word");
961 }
962
963 static ssize_t
rw_byte_store(struct class * class,struct class_attribute * attr,const char * buf,size_t count)964 rw_byte_store(struct class *class, struct class_attribute *attr,
965 const char *buf, size_t count)
966 {
967 unsigned long value;
968 int ret;
969
970 ret = kstrtoul(buf, 10, &value);
971 if (!ret && (value > 1)) {
972 pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
973 goto out;
974 }
975 rw_byte_mode = value;
976 out:
977 return count;
978 }
979
980 static ssize_t
test_show(struct class * class,struct class_attribute * attr,char * buf)981 test_show(struct class *class, struct class_attribute *attr, char *buf)
982 {
983 return sprintf(buf, "addr:0x%08x\nsize:0x%08x\n", test_addr, test_size);
984 }
985
986 static ssize_t
help_show(struct class * class,struct class_attribute * attr,char * buf)987 help_show(struct class *class, struct class_attribute *attr, char *buf)
988 {
989 const char *info =
990 "dump single register: echo {addr} > dump; cat dump\n"
991 "dump multi registers: echo {start-addr},{end-addr} > dump; cat dump\n"
992 "write single register: echo {addr} {val} > write; cat write\n"
993 "write multi registers: echo {addr1} {val1},{addr2} {val2},... > write; cat write\n"
994 "compare single register: echo {addr} {expect-val} {mask} > compare; cat compare\n"
995 "compare multi registers: echo {addr1} {expect-val1} {mask1},{addr2} {expect-val2} {mask2},... > compare; cat compare\n"
996 "byte-access mode: echo 1 > rw_byte\n"
997 "word-access mode (default): echo 0 > rw_byte\n"
998 "show test address info: cat test\n"
999 "abort standby_dump_ctrl, \n"
1000 " If you don't know it, please keep at zero.\n"
1001 " If you want to use it, please read the source code or the wiki first.\n";
1002
1003 return sprintf(buf, info);
1004 }
1005
1006 static struct class_attribute dump_class_attrs[] = {
1007 __ATTR(dump, S_IWUSR | S_IRUGO, dump_show, dump_store),
1008 __ATTR(write, S_IWUSR | S_IRUGO, write_show, write_store),
1009 __ATTR(compare, S_IWUSR | S_IRUGO, compare_show, compare_store),
1010 __ATTR(rw_byte, S_IWUSR | S_IRUGO, rw_byte_show, rw_byte_store),
1011 __ATTR(test, S_IRUGO, test_show, NULL),
1012 __ATTR(help, S_IRUGO, help_show, NULL),
1013 __ATTR(standby_dump_ctrl, S_IWUSR | S_IRUGO, standby_dump_ctrl_show, standby_dump_ctrl_store),
1014 };
1015
1016 static const struct of_device_id sunxi_dump_reg_match[] = {
1017 {.compatible = "allwinner,sunxi-dump-reg", },
1018 {}
1019 };
1020 MODULE_DEVICE_TABLE(of, sunxi_dump_reg_match);
1021
sunxi_dump_reg_probe(struct platform_device * pdev)1022 static int sunxi_dump_reg_probe(struct platform_device *pdev)
1023 {
1024 struct resource *res;
1025 struct device *dev = &pdev->dev;
1026
1027 int err;
1028 int i;
1029
1030 /* sys/class/sunxi_dump */
1031 dump_class = class_create(THIS_MODULE, "sunxi_dump");
1032 if (IS_ERR(dump_class)) {
1033 pr_err("%s:%u class_create() failed\n", __func__, __LINE__);
1034 return PTR_ERR(dump_class);
1035 }
1036
1037 /* sys/class/sunxi_dump/xxx */
1038 for (i = 0; i < ARRAY_SIZE(dump_class_attrs); i++) {
1039 err = class_create_file(dump_class, &dump_class_attrs[i]);
1040 if (err) {
1041 pr_err("%s:%u class_create_file() failed. err=%d\n", __func__, __LINE__, err);
1042 while (i--) {
1043 class_remove_file(dump_class, &dump_class_attrs[i]);
1044 }
1045 class_destroy(dump_class);
1046 dump_class = NULL;
1047 return err;
1048 }
1049 }
1050
1051 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1052 if (!res) {
1053 dev_err(dev, "Fail to get IORESOURCE_MEM \n");
1054 goto error;
1055 }
1056
1057 test_addr = res->start;
1058 test_size = resource_size(res);
1059
1060 standby_dump_buff = devm_kmalloc(dev, PAGE_SIZE, GFP_KERNEL);
1061 if (!standby_dump_buff)
1062 dev_err(dev, "malloc memory failed.\n");
1063
1064 register_syscore_ops(&standby_dump_syscore);
1065
1066 return 0;
1067 error:
1068 dev_err(dev, "sunxi_dump_reg probe error\n");
1069 return -1;
1070 }
1071
sunxi_dump_reg_remove(struct platform_device * pdev)1072 static int sunxi_dump_reg_remove(struct platform_device *pdev)
1073 {
1074 int i;
1075
1076 for (i = 0; i < ARRAY_SIZE(dump_class_attrs); i++) {
1077 class_remove_file(dump_class, &dump_class_attrs[i]);
1078 }
1079
1080 class_destroy(dump_class);
1081 return 0;
1082 }
1083
1084 static struct platform_driver sunxi_dump_reg_driver = {
1085 .probe = sunxi_dump_reg_probe,
1086 .remove = sunxi_dump_reg_remove,
1087 .driver = {
1088 .name = "dump_reg",
1089 .owner = THIS_MODULE,
1090 .of_match_table = sunxi_dump_reg_match,
1091 .pm = &standby_dump_ops,
1092 },
1093 };
1094
1095 module_platform_driver(sunxi_dump_reg_driver);
1096
1097 MODULE_ALIAS("dump reg driver");
1098 MODULE_ALIAS("platform:dump reg");
1099 MODULE_LICENSE("GPL v2");
1100 MODULE_VERSION("1.0.4");
1101 MODULE_AUTHOR("xiafeng <xiafeng@allwinnertech.com>");
1102 MODULE_AUTHOR("Martin <wuyan@allwinnertech.com>");
1103 MODULE_AUTHOR("liuyu <SWCliuyus@allwinnertech.com>");
1104 MODULE_DESCRIPTION("dump registers driver");
1105