2025-05-10 21:49:39 +08:00

335 lines
7.6 KiB
C

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
// Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define LOG_TAG "NPU_POWER"
#include <npu_powerctrl.h>
#define VERSION "V1.1"
#define FNAME_SIZE 50
#define GPIO_BASE_PATH "/sys/class/gpio"
#define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
#define GPIO_UNEXPORT_PATH GPIO_BASE_PATH "/unexport"
#define CLKEN_24M_PATH "/sys/kernel/debug/clk/clk_wifi_pmu/clk_enable_count"
#define CLKEN_32k_PATH "/sys/kernel/debug/clk/rk808-clkout2/clk_enable_count"
#define PCIE_RESET_EP "sys/devices/platform/f8000000.pcie/pcie_reset_ep"
#define ACM_HIGHSPEED_ID "/sys/bus/platform/devices/fe380000.usb/usb*/*/idProduct"
#define ACM_FULLSPEED_ID "/sys/bus/platform/devices/fe3a0000.usb/usb*/*/idProduct"
#define NPU_VDD_0V8_GPIO "4" //GPIO0_PA4
#define NPU_VDD_LOG_GPIO "10" //GPIO0_PB2
#define NPU_VCC_1V8_GPIO "11" //GPIO0_PB3
#define NPU_VCC_DDR_GPIO NPU_VCC_1V8_GPIO
#define NPU_VDD_CPU_GPIO "54" //GPIO1_PC6
#define NPU_VCCIO_3V3_GPIO "55" //GPIO1_PC7
#define NPU_VDD_GPIO "56" //GPIO1_PD0
#define CPU_RESET_NPU_GPIO "32" //GPIO1_PA0
#define NPU_PMU_SLEEP_GPIO "35" //GPIO1_A3
#define CPU_INT_NPU_GPIO "36" //GPIO1_A4
static char gpio_list[][4] = {NPU_VDD_0V8_GPIO, NPU_VDD_LOG_GPIO, NPU_VCC_1V8_GPIO, \
NPU_VDD_CPU_GPIO, NPU_VCCIO_3V3_GPIO, NPU_VDD_GPIO, CPU_RESET_NPU_GPIO, \
NPU_PMU_SLEEP_GPIO, CPU_INT_NPU_GPIO};
static int sysfs_write(char *path, char *val) {
char buf[80];
int len;
int fd = open(path, O_WRONLY);
if (fd < 0) {
strerror_r(errno, buf, sizeof(buf));
printf("Error opening %s value=%s:%s\n", path, val, buf);
return -1;
}
len = write(fd, val, sizeof(val));
if (len < 0) {
strerror_r(errno, buf, sizeof(buf));
printf("Error writing to %s value=%s: %s\n", path, val, buf);
return -1;
}
close(fd);
return 0;
}
static void sysfs_read(char *path, char *val)
{
char buf[80];
int len;
int fd = open(path, O_RDONLY);
if (fd < 0) {
strerror_r(errno, buf, sizeof(buf));
printf("Error opening %s value=%s:%s\n", path, val, buf);
return;
}
len = read(fd, val, 1);
if (len < 0) {
strerror_r(errno, buf, sizeof(buf));
printf("Error reading to %s value=%s: %s\n", path, val, buf);
}
close(fd);
}
static int clk_enable(char *enable) {
char val;
sysfs_read(CLKEN_24M_PATH, &val);
if (*enable == val)
return 0;
printf("set clk_en %c to %s\n", val, enable);
sysfs_write(CLKEN_24M_PATH, enable);
return 0;
}
static int request_gpio(char *gpio_num) {
int ret;
ret = sysfs_write(GPIO_EXPORT_PATH, gpio_num);
return ret;
}
static void free_gpio(char *gpio_num) {
sysfs_write(GPIO_UNEXPORT_PATH, gpio_num);
}
static void set_gpio_dir(char *gpio_num, char *dir) {
char gpio_dir_name[FNAME_SIZE];
snprintf(gpio_dir_name, sizeof(gpio_dir_name), "%s/gpio%s/direction",
GPIO_BASE_PATH, gpio_num);
sysfs_write(gpio_dir_name, dir);
}
static int get_gpio(char *gpio_number) {
char gpio_name[FNAME_SIZE];
char value;
snprintf(gpio_name, sizeof(gpio_name), "%s/gpio%s/value",
GPIO_BASE_PATH, gpio_number);
sysfs_read(gpio_name, &value);
if (value == 48 || value == 49)
value -= 48;
else
value = -1;
return (int)value;
}
static int set_gpio(char *gpio_number, char *val) {
char gpio_val_name[FNAME_SIZE];
snprintf(gpio_val_name, sizeof(gpio_val_name), "%s/gpio%s/value",
GPIO_BASE_PATH, gpio_number);
sysfs_write(gpio_val_name, val);
return 0;
}
void npu_power_gpio_init(void) {
int ret, index = 0, gpio_cnt = sizeof(gpio_list)/sizeof(int);
printf("version: %s\n", VERSION);
while (index != gpio_cnt) {
printf("init gpio: %s\n", gpio_list[index]);
ret = request_gpio(gpio_list[index]);
if (ret) {
return;
}
set_gpio_dir(gpio_list[index], "out");
index ++;
}
set_gpio_dir(NPU_PMU_SLEEP_GPIO, "in");
}
void npu_power_gpio_exit(void) {
int index = 0, gpio_cnt = sizeof(gpio_list)/sizeof(int);
while (index != gpio_cnt) {
printf("init gpio: %s\n", gpio_list[index]);
free_gpio(gpio_list[index]);
index ++;
}
}
void npu_reset(void) {
// sysfs_write("/sys/power/wake_lock", "npu_lock");
sysfs_write(CLKEN_32k_PATH, "1");
clk_enable("0");
set_gpio(NPU_VDD_GPIO, "0");
set_gpio(NPU_VCCIO_3V3_GPIO, "0");
set_gpio(NPU_VDD_CPU_GPIO, "0");
set_gpio(NPU_VCC_1V8_GPIO, "0");
set_gpio(NPU_VDD_0V8_GPIO, "0");
set_gpio(NPU_VDD_LOG_GPIO, "0");
set_gpio(CPU_INT_NPU_GPIO, "0");
set_gpio(CPU_RESET_NPU_GPIO, "0");
usleep(2000);
/*power en*/
set_gpio(NPU_VDD_0V8_GPIO, "1");
usleep(2000);
set_gpio(NPU_VDD_LOG_GPIO, "1");
usleep(2000);
set_gpio(NPU_VCC_1V8_GPIO, "1");
usleep(2000);
clk_enable("1");
set_gpio(NPU_VDD_CPU_GPIO, "1");
usleep(2000);
set_gpio(NPU_VCCIO_3V3_GPIO, "1");
usleep(2000);
set_gpio(NPU_VDD_GPIO, "1");
usleep(25000);
set_gpio(CPU_RESET_NPU_GPIO, "1");
}
void npu_poweroff(void) {
set_gpio(NPU_VDD_GPIO, "0");
set_gpio(NPU_VCCIO_3V3_GPIO, "0");
set_gpio(NPU_VDD_CPU_GPIO, "0");
set_gpio(NPU_VCC_1V8_GPIO, "0");
set_gpio(NPU_VDD_0V8_GPIO, "0");
set_gpio(NPU_VDD_LOG_GPIO, "0");
set_gpio(CPU_INT_NPU_GPIO, "0");
set_gpio(CPU_RESET_NPU_GPIO, "0");
clk_enable("0");
// sysfs_write("/sys/power/wake_unlock", "npu_lock");
}
int disconnect_usb_acm(void)
{
FILE *stream;
char buf[100];
int idx = 0, path_idx=0;
memset( buf,'\0',sizeof(buf) );
stream = popen( "cat " ACM_HIGHSPEED_ID, "r" );
if (!stream) {
path_idx=1;
stream = popen( "cat " ACM_FULLSPEED_ID, "r" );
if (!stream)
return -1;
}
fread( buf, sizeof(char), sizeof(buf), stream);
pclose( stream );
printf("ACM idProduct: %s", buf);
if (!strncmp(buf, "1005", 4)) {
if (path_idx)
stream = popen("find /sys/bus/platform/devices/fe3a0000.usb/usb*/*/ -name remove", "r" );
else
stream = popen("find /sys/bus/platform/devices/fe380000.usb/usb*/*/ -name remove", "r" );
fread( buf, sizeof(char), sizeof(buf), stream);
printf("usb remove patch is %s", buf);
/* The path string adds end character */
while(idx < 100) {
if (buf[idx] == '\n') {
buf[idx] = '\0';
break;
}
idx ++;
}
sysfs_write(buf, "0");
pclose( stream );
return 0;
}
return -1;
}
int npu_suspend(void) {
int retry=100;
int is_pcie;
if (get_gpio(NPU_PMU_SLEEP_GPIO)) {
printf("It is sleeping state, noting to do!\n");
return 0;
}
is_pcie = access(PCIE_RESET_EP, R_OK);
if (!is_pcie) {
sysfs_write(PCIE_RESET_EP, "2");
disconnect_usb_acm();
}
set_gpio(CPU_INT_NPU_GPIO, "1");
usleep(20000);
set_gpio(CPU_INT_NPU_GPIO, "0");
/*wait for npu enter sleep*/
while (--retry) {
if (get_gpio(NPU_PMU_SLEEP_GPIO)) {
usleep(10000);
set_gpio(NPU_VDD_CPU_GPIO, "0");
set_gpio(NPU_VDD_GPIO, "0");
clk_enable("0");
/* wait 1s for usb disconnect */
sleep(1);
// sysfs_write("/sys/power/wake_unlock", "npu_lock");
break;
}
usleep(10000);
}
if (!retry) {
printf("npu suspend timeout in one second\n");
return -1;
}
return 0;
}
int npu_resume(void) {
int retry=100;
int is_pcie;
if (!get_gpio(NPU_PMU_SLEEP_GPIO)) {
printf("It is awakening state, noting to do!\n");
return 0;
}
clk_enable("1");
set_gpio(NPU_VDD_CPU_GPIO, "1");
set_gpio(NPU_VDD_GPIO, "1");
usleep(10000);
set_gpio(CPU_INT_NPU_GPIO, "1");
usleep(20000);
set_gpio(CPU_INT_NPU_GPIO, "0");
/*wait for npu wakeup*/
while (--retry) {
if (!get_gpio(NPU_PMU_SLEEP_GPIO)) {
// sysfs_write("/sys/power/wake_lock", "npu_lock");
break;
}
usleep(10000);
}
is_pcie = access(PCIE_RESET_EP, R_OK);
if (!is_pcie)
sysfs_write(PCIE_RESET_EP, "1");
if (!retry) {
printf("npu resume timeout in one second\n");
return -1;
}
//waiting for userspase wakup
/*usleep(500000);*/
/*set_gpio(CPU_INT_NPU_GPIO, "0");*/
return 0;
}