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