xref: /OK3568_Linux_fs/buildroot/package/rockchip/npu_powerctrl/npu_powerctrl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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