1 /*
2  * Copyright (c) 2022 Andes Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/hwinfo.h>
9 #include <zephyr/drivers/syscon.h>
10 #include <string.h>
11 #include <zephyr/sys/byteorder.h>
12 
13 /*
14  * SMU(System Management Unit) Registers for hwinfo driver
15  */
16 
17 /* Register offset*/
18 #define SMU_SYSTEMVER	0x00
19 #define SMU_WRSR	0x10
20 
21 /* Wake-Up and Reset Status Register bitmask */
22 #define SMU_WRSR_APOR	BIT(0)
23 #define SMU_WRSR_MPOR	BIT(1)
24 #define SMU_WRSR_HW	BIT(2)
25 #define SMU_WRSR_WDT	BIT(3)
26 #define SMU_WRSR_SW	BIT(4)
27 
28 #define ANDES_RESET_STATUS_MASK	BIT_MASK(5)
29 
30 static const struct device *const syscon_dev =
31 			DEVICE_DT_GET(DT_NODELABEL(syscon));
32 
z_impl_hwinfo_get_device_id(uint8_t * buffer,size_t length)33 ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length)
34 {
35 	int ret = 0;
36 	uint8_t id[3];
37 	uint32_t ver;
38 
39 	if (!device_is_ready(syscon_dev)) {
40 		return -ENODEV;
41 	}
42 
43 	ret = syscon_read_reg(syscon_dev, SMU_SYSTEMVER, &ver);
44 	if (ret < 0) {
45 		return ret;
46 	}
47 
48 	if (length > sizeof(id)) {
49 		length = sizeof(id);
50 	}
51 
52 	sys_put_le24(ver, id);
53 
54 	memcpy(buffer, id, length);
55 
56 	return length;
57 }
58 
z_impl_hwinfo_get_reset_cause(uint32_t * cause)59 int z_impl_hwinfo_get_reset_cause(uint32_t *cause)
60 {
61 	int ret = 0;
62 	uint32_t reason, flags = 0;
63 
64 	if (!device_is_ready(syscon_dev)) {
65 		return -ENODEV;
66 	}
67 
68 	ret = syscon_read_reg(syscon_dev, SMU_WRSR, &reason);
69 	if (ret < 0) {
70 		return ret;
71 	}
72 
73 	if (reason & SMU_WRSR_APOR) {
74 		flags |= RESET_POR;
75 	}
76 	if (reason & SMU_WRSR_MPOR) {
77 		flags |= RESET_POR;
78 	}
79 	if (reason & SMU_WRSR_HW) {
80 		flags |= RESET_PIN;
81 	}
82 	if (reason & SMU_WRSR_WDT) {
83 		flags |= RESET_WATCHDOG;
84 	}
85 	if (reason & SMU_WRSR_SW) {
86 		flags |= RESET_SOFTWARE;
87 	}
88 
89 	*cause = flags;
90 
91 	return 0;
92 }
93 
z_impl_hwinfo_clear_reset_cause(void)94 int z_impl_hwinfo_clear_reset_cause(void)
95 {
96 	int ret = 0;
97 	uint32_t reason;
98 
99 	if (!device_is_ready(syscon_dev)) {
100 		return -ENODEV;
101 	}
102 
103 	ret = syscon_write_reg(syscon_dev, SMU_WRSR, ANDES_RESET_STATUS_MASK);
104 	if (ret < 0) {
105 		return ret;
106 	}
107 
108 	do {
109 		ret = syscon_read_reg(syscon_dev, SMU_WRSR, &reason);
110 	} while ((reason & ANDES_RESET_STATUS_MASK) && (!ret));
111 
112 	return ret;
113 }
114 
z_impl_hwinfo_get_supported_reset_cause(uint32_t * supported)115 int z_impl_hwinfo_get_supported_reset_cause(uint32_t *supported)
116 {
117 	*supported = (RESET_PIN
118 		| RESET_WATCHDOG
119 		| RESET_SOFTWARE
120 		| RESET_POR);
121 
122 	return 0;
123 }
124