1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 // Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
3
4 #include <stdio.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11
12 #include <npu_powerctrl.h>
13
14 #define VERSION "V1.1 for power combine board"
15 #define FNAME_SIZE 50
16 #define GPIO_BASE_PATH "/sys/class/gpio"
17 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
18 #define GPIO_UNEXPORT_PATH GPIO_BASE_PATH "/unexport"
19 #define CLKEN_24M_PATH "/sys/kernel/debug/clk/clk_wifi_pmu/clk_enable_count"
20 #define CLKEN_32k_PATH "/sys/kernel/debug/clk/rk808-clkout2/clk_enable_count"
21 #define PCIE_RESET_EP "/sys/devices/platform/f8000000.pcie/pcie_reset_ep"
22 #define ACM_HIGHSPEED_ID "/sys/bus/platform/devices/fe380000.usb/usb*/*/idProduct"
23 #define ACM_FULLSPEED_ID "/sys/bus/platform/devices/fe3a0000.usb/usb*/*/idProduct"
24
25 #define CPU_RESET_NPU_GPIO "32" //GPIO1_PA0
26 #define NPU_PMU_SLEEP_GPIO "35" //GPIO1_A3
27 #define CPU_INT_NPU_GPIO "36" //GPIO1_A4
28
29 #define NPU_VDD_EN1_GPIO "4" //GPIO0_PA4
30 #define NPU_VDD_EN4_GPIO "54" //GPIO1_PC6 vdd_cpp/vdd
31
32 static char gpio_list[][4] = {NPU_VDD_EN1_GPIO, NPU_VDD_EN4_GPIO, CPU_RESET_NPU_GPIO, \
33 NPU_PMU_SLEEP_GPIO, CPU_INT_NPU_GPIO};
34
sysfs_write(char * path,char * val)35 static int sysfs_write(char *path, char *val) {
36 char buf[80];
37 int len;
38 int fd = open(path, O_WRONLY);
39
40 if (fd < 0) {
41 strerror_r(errno, buf, sizeof(buf));
42 printf("Error opening %s value=%s:%s\n", path, val, buf);
43 return -1;
44 }
45
46 len = write(fd, val, sizeof(val));
47 if (len < 0) {
48 strerror_r(errno, buf, sizeof(buf));
49 printf("Error writing to %s value=%s: %s\n", path, val, buf);
50 return -1;
51 }
52
53 close(fd);
54 return 0;
55 }
56
sysfs_read(char * path,char * val)57 static void sysfs_read(char *path, char *val)
58 {
59 char buf[80];
60 int len;
61 int fd = open(path, O_RDONLY);
62
63 if (fd < 0) {
64 strerror_r(errno, buf, sizeof(buf));
65 printf("Error opening %s value=%s:%s\n", path, val, buf);
66 return;
67 }
68
69 len = read(fd, val, 1);
70 if (len < 0) {
71 strerror_r(errno, buf, sizeof(buf));
72 printf("Error reading to %s value=%s: %s\n", path, val, buf);
73 }
74
75 close(fd);
76 }
77
clk_enable(char * enable)78 static int clk_enable(char *enable) {
79 char val;
80
81 sysfs_read(CLKEN_24M_PATH, &val);
82 if (*enable == val)
83 return 0;
84
85 printf("set clk_en %c to %s\n", val, enable);
86 sysfs_write(CLKEN_24M_PATH, enable);
87 return 0;
88 }
89
request_gpio(char * gpio_num)90 static int request_gpio(char *gpio_num) {
91 int ret;
92 ret = sysfs_write(GPIO_EXPORT_PATH, gpio_num);
93 return ret;
94 }
95
free_gpio(char * gpio_num)96 static void free_gpio(char *gpio_num) {
97 sysfs_write(GPIO_UNEXPORT_PATH, gpio_num);
98 }
99
set_gpio_dir(char * gpio_num,char * dir)100 static void set_gpio_dir(char *gpio_num, char *dir) {
101 char gpio_dir_name[FNAME_SIZE];
102
103 snprintf(gpio_dir_name, sizeof(gpio_dir_name), "%s/gpio%s/direction",
104 GPIO_BASE_PATH, gpio_num);
105 sysfs_write(gpio_dir_name, dir);
106 }
107
get_gpio(char * gpio_number)108 static int get_gpio(char *gpio_number) {
109 char gpio_name[FNAME_SIZE];
110 char value;
111
112 snprintf(gpio_name, sizeof(gpio_name), "%s/gpio%s/value",
113 GPIO_BASE_PATH, gpio_number);
114
115 sysfs_read(gpio_name, &value);
116 if (value == 48 || value == 49)
117 value -= 48;
118 else
119 value = -1;
120 return (int)value;
121 }
122
set_gpio(char * gpio_number,char * val)123 static int set_gpio(char *gpio_number, char *val) {
124 char gpio_val_name[FNAME_SIZE];
125
126 snprintf(gpio_val_name, sizeof(gpio_val_name), "%s/gpio%s/value",
127 GPIO_BASE_PATH, gpio_number);
128 sysfs_write(gpio_val_name, val);
129 return 0;
130 }
131
npu_power_gpio_init(void)132 void npu_power_gpio_init(void) {
133 int ret, index = 0, gpio_cnt = sizeof(gpio_list)/sizeof(int);
134
135 printf("version: %s\n", VERSION);
136 while (index != gpio_cnt) {
137 printf("init gpio: %s\n", gpio_list[index]);
138 ret = request_gpio(gpio_list[index]);
139 if (ret) {
140 return;
141 }
142 set_gpio_dir(gpio_list[index], "out");
143 index ++;
144 }
145 set_gpio_dir(NPU_PMU_SLEEP_GPIO, "in");
146 }
147
npu_power_gpio_exit(void)148 void npu_power_gpio_exit(void) {
149 int index = 0, gpio_cnt = sizeof(gpio_list)/sizeof(int);
150
151 while (index != gpio_cnt) {
152 printf("init gpio: %s\n", gpio_list[index]);
153 free_gpio(gpio_list[index]);
154 index ++;
155 }
156 }
157
npu_reset(void)158 void npu_reset(void) {
159 //sysfs_write("/sys/power/wake_lock", "npu_lock");
160 sysfs_write(CLKEN_32k_PATH, "1");
161 clk_enable("0");
162 set_gpio(NPU_VDD_EN1_GPIO, "0");
163 set_gpio(NPU_VDD_EN4_GPIO, "0");
164 set_gpio(CPU_RESET_NPU_GPIO, "0");
165 usleep(2000);
166
167 /*power en*/
168 set_gpio(NPU_VDD_EN1_GPIO, "1");
169 usleep(2000);
170 clk_enable("1");
171 set_gpio(NPU_VDD_EN4_GPIO, "1");
172
173 usleep(25000);
174 set_gpio(CPU_RESET_NPU_GPIO, "1");
175 }
176
npu_poweroff(void)177 void npu_poweroff(void) {
178 set_gpio(NPU_VDD_EN1_GPIO, "0");
179 set_gpio(NPU_VDD_EN4_GPIO, "0");
180 clk_enable("0");
181 //sysfs_write("/sys/power/wake_unlock", "npu_lock");
182 }
183
disconnect_usb_acm(void)184 int disconnect_usb_acm(void)
185 {
186 FILE *stream;
187 char buf[100];
188 int idx = 0, path_idx=0;
189
190 memset( buf,'\0',sizeof(buf) );
191 stream = popen( "cat " ACM_HIGHSPEED_ID, "r" );
192 if (!stream) {
193 path_idx=1;
194 stream = popen( "cat " ACM_FULLSPEED_ID, "r" );
195 if (!stream)
196 return -1;
197 }
198 fread( buf, sizeof(char), sizeof(buf), stream);
199 pclose( stream );
200 printf("ACM idProduct: %s", buf);
201 if (!strncmp(buf, "1005", 4)) {
202 if (path_idx)
203 stream = popen("find /sys/bus/platform/devices/fe3a0000.usb/usb*/*/ -name remove", "r" );
204 else
205 stream = popen("find /sys/bus/platform/devices/fe380000.usb/usb*/*/ -name remove", "r" );
206 fread( buf, sizeof(char), sizeof(buf), stream);
207 printf("usb remove patch is %s", buf);
208 /* The path string adds end character */
209 while(idx < 100) {
210 if (buf[idx] == '\n') {
211 buf[idx] = '\0';
212 break;
213 }
214 idx ++;
215 }
216 sysfs_write(buf, "0");
217 pclose( stream );
218 return 0;
219 }
220 return -1;
221
222 }
223
npu_suspend(void)224 int npu_suspend(void) {
225 int retry=100;
226 int is_pcie;
227
228 if (get_gpio(NPU_PMU_SLEEP_GPIO)) {
229 printf("It is sleeping state, noting to do!\n");
230 return 0;
231 }
232
233 is_pcie = access(PCIE_RESET_EP, R_OK);
234 if (!is_pcie) {
235 sysfs_write(PCIE_RESET_EP, "2");
236 disconnect_usb_acm();
237 }
238
239 set_gpio(CPU_INT_NPU_GPIO, "1");
240 usleep(20000);
241 set_gpio(CPU_INT_NPU_GPIO, "0");
242
243 /*wait for npu enter sleep*/
244 while (--retry) {
245 if (get_gpio(NPU_PMU_SLEEP_GPIO)) {
246 usleep(10000);
247 set_gpio(NPU_VDD_EN4_GPIO, "0");
248 clk_enable("0");
249 /* wait 1s for usb disconnect */
250 sleep(1);
251 //sysfs_write("/sys/power/wake_unlock", "npu_lock");
252 break;
253 }
254 usleep(10000);
255 }
256
257 if (!retry) {
258 printf("npu suspend timeout in one second\n");
259 return -1;
260 }
261 return 0;
262 }
263
npu_resume(void)264 int npu_resume(void) {
265 int retry=100;
266 int is_pcie;
267
268 if (!get_gpio(NPU_PMU_SLEEP_GPIO)) {
269 printf("It is awakening state, noting to do!\n");
270 return 0;
271 }
272
273 clk_enable("1");
274 set_gpio(NPU_VDD_EN4_GPIO, "1");
275
276 usleep(10000);
277
278 set_gpio(CPU_INT_NPU_GPIO, "1");
279 usleep(20000);
280 set_gpio(CPU_INT_NPU_GPIO, "0");
281
282 /*wait for npu wakeup*/
283 while (--retry) {
284 if (!get_gpio(NPU_PMU_SLEEP_GPIO)) {
285 // sysfs_write("/sys/power/wake_lock", "npu_lock");
286 break;
287 }
288 usleep(10000);
289 }
290
291 is_pcie = access(PCIE_RESET_EP, R_OK);
292 if (!is_pcie)
293 sysfs_write(PCIE_RESET_EP, "1");
294
295 if (!retry) {
296 printf("npu resume timeout in one second\n");
297 return -1;
298 }
299 //waiting for userspase wakup
300 /*usleep(500000);*/
301 /*set_gpio(CPU_INT_NPU_GPIO, "0");*/
302
303 return 0;
304 }
305