• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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