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