sdk-hwV1.3/lichee/brandy-2.0/u-boot-2018/board/sunxi/homlet/ir-recovery.c

292 lines
7.1 KiB
C

/*
* * Copyright 2000-2009
* * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
* *
* * SPDX-License-Identifier: GPL-2.0+
* */
#include <common.h>
#include <asm/arch/cpu.h>
#include <asm/arch/gic.h>
#include <sys_config.h>
#include <fdt_support.h>
#include <malloc.h>
#include <private_uboot.h>
#include <sunxi-ir.h>
#include "asm/arch/timer.h"
DECLARE_GLOBAL_DATA_PTR;
/*define ir or key mode value*/
#define EFEX_VALUE (0x81)
#define SPRITE_RECOVERY_VALUE (0X82)
#define BOOT_RECOVERY_VALUE (0x83)
#define BOOT_FACTORY_VALUE (0x84)
/*ir or key mode in sys_config*/
#define EFEX_MODE_CONFIG (0x0)
#define ONEKEY_SPRITE_RECOVERY_MODE_CONFIG (0x1)
#define RECOVERY_MODE_CONFIG (0x2)
#define FACTORY_MODE_CONFIG (0x3)
struct sunxi_ir_data ir_data;
struct timer_list ir_timer_t;
static int ir_boot_recovery_mode;
extern struct ir_raw_buffer sunxi_ir_raw;
static int ir_detect_time = 1500;
static u32 code_store[32];
static int code_num;
#define FDT_IR_BOOT_SETTINGS_PATH "/soc/ir_boot_recovery"
static int ir_sys_cfg(void)
{
int i, ret;
u32 value = 0;
char addr_name[32];
int detect_time = 0;
int node_offset = 0;
if (uboot_spare_head.boot_data.work_mode != WORK_MODE_BOOT)
return -1;
node_offset = fdt_path_offset(working_fdt, FDT_IR_BOOT_SETTINGS_PATH);
if (node_offset < 0) {
pr_err("%s: error:no node for ir boot recovery settings\n",
__func__);
return -1;
}
char *node_status;
ret = fdt_getprop_string(working_fdt, node_offset, "status",
&node_status);
if ((ret < 0) || (strcmp(node_status, "okay") != 0)) {
pr_notice("ir boot recovery not used\n");
return -1;
}
ret = script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, "ir_detect_time",
(int *)&detect_time, sizeof(int) / 4);
if (ret) {
pr_notice("use default detect time %d\n", ir_detect_time);
detect_time = ir_detect_time;
}
ir_detect_time = detect_time;
for (i = 0; i < MAX_IR_ADDR_NUM; i++) {
sprintf(addr_name, "ir_recovery_key_code%d", i);
if (script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, addr_name,
(int *)&value, 1)) {
pr_notice("node %s get failed!\n", addr_name);
break;
}
code_store[i] = ir_data.ir_recoverykey[i] = value;
sprintf(addr_name, "ir_addr_code%d", i);
if (script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, addr_name,
(int *)&value, 1)) {
break;
}
ir_data.ir_addr[i] = value;
code_num++;
debug("key_code = %s, value = %d\n", addr_name, value);
debug("code num = %d\n", code_num);
}
ir_data.ir_addr_cnt = i;
/*
for (i = 0; i < ir_data.ir_addr_cnt; i++) {
sprintf(addr_name, "ir_addr_code%d", i);
if (script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, addr_name,
(int *)&value, 1)) {
break;
}
ir_data.ir_addr[i] = value;
pr_notice("addr_code = %s, value = %d\n", addr_name, value);
sprintf(addr_name, "ir_recovery_key_code%d", i);
if (script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, addr_name,
(int *)&value, 1)) {
break;
}
code_num++;
code_store[i] = value;
pr_notice("key_code = %s, value = %d\n", addr_name, value);
pr_notice("code num = %d\n", code_num);
}
*/
return 0;
}
static int ir_code_detect_no_duplicate(struct sunxi_ir_data *ir_data, u32 code)
{
int key_no_duplicate;
if (script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, "ir_key_no_duplicate",
(int *)&key_no_duplicate, 1)) {
pr_notice("ir_key_no_duplicate get fail, use defualt mode!\n");
return 0;
}
if (key_no_duplicate == 0) {
pr_notice("[ir recovery]: do not use key duplicate mode!\n");
return 0;
} else {
pr_notice("[ir recovery]: use key duplicate mode!\n");
}
int i;
for (i = 0; i < code_num; i++) {
if ((code & 0xff) == code_store[i]) {
pr_notice("In %s: code_store = %d\n", __func__,
code_store[i]);
code_store[i] = 0;
return 0;
}
}
return -1;
}
static int ir_code_valid(struct sunxi_ir_data *ir_data, u32 code)
{
u32 i, tmp;
tmp = (code >> 8) & 0xffff;
pr_notice("line:%d recved addr=0x%x key=0x%x\n", __LINE__, tmp,
(code & 0xff));
for (i = 0; i < ir_data->ir_addr_cnt; i++) {
pr_notice(
"line:%d try ir_addr[%d] =0x%x, ir_recoverykey[%d]=0x%x\n",
__LINE__, i, ir_data->ir_addr[i], i,
ir_data->ir_recoverykey[i]);
if (ir_data->ir_addr[i] == tmp) {
if ((code & 0xff) == ir_data->ir_recoverykey[i]) {
return ir_code_detect_no_duplicate(ir_data,
code);
}
}
}
pr_notice("ir boot recovery not detect\n");
return -1;
}
int ir_boot_recovery_mode_detect(void)
{
u32 code;
if (ir_boot_recovery_mode) {
code = sunxi_ir_raw.scancode;
pr_notice("line:%d code=0x%x\n", __LINE__, code);
if ((code != 0) && (!ir_code_valid(&ir_data, code))) {
pr_notice("ir boot recovery detect valid.\n");
return 0;
}
}
return -1;
}
static void ir_detect_overtime(void *p)
{
struct timer_list *timer_t;
timer_t = (struct timer_list *)p;
/*ir_disable();*/
del_timer(timer_t);
gd->ir_detect_status = IR_DETECT_END;
}
int check_ir_boot_recovery(void)
{
if (ir_sys_cfg())
return 0;
if (ir_setup())
return 0;
gd->ir_detect_status = IR_DETECT_NULL;
ir_boot_recovery_mode = 1;
ir_timer_t.data = (unsigned long)&ir_timer_t;
ir_timer_t.expires = ir_detect_time;
ir_timer_t.function = ir_detect_overtime;
init_timer(&ir_timer_t);
add_timer(&ir_timer_t);
return 0;
}
int get_ir_work_mode(int *cnt)
{
int i;
s32 tmp = (sunxi_ir_raw.scancode >> 8) & 0xffff;
*cnt = ir_data.ir_addr_cnt;
for (i = 0; i < ir_data.ir_addr_cnt; i++) {
if (ir_data.ir_addr[i] == tmp) {
if ((sunxi_ir_raw.scancode & 0xff) == ir_data.ir_recoverykey[i])
break;
}
}
return i%4;
}
extern int ir_nec_decode(struct ir_raw_buffer *ir_raw, struct ir_raw_event ev);
extern int get_ir_work_mode(int *cnt);
unsigned long ir_packet_handle(struct ir_raw_buffer *ir_raw)
{
int i = 0, ret = 0;
int ir_press_times = 0;
int ir_work_mode = 0;
static uint ir_detect_count;
ret = script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, "ir_press_times",
(int *)&ir_press_times, sizeof(int) / 4);
if (ret) {
printf("ir_press_times not set, use default press time : 1\n");
ir_press_times = 1;
}
for (i = 0; i < ir_raw->dcnt; i++) {
ir_nec_decode(ir_raw, ir_raw->raw[i]);
}
ret = ir_boot_recovery_mode_detect();
if (!ret) {
ir_detect_count++;
}
if ((ir_detect_count == ir_press_times)
&& (gd->ir_detect_status != IR_DETECT_OK)) {
gd->ir_detect_status = IR_DETECT_OK;
#if 1
ret = script_parser_fetch(FDT_IR_BOOT_SETTINGS_PATH, "ir_work_mode",
(int *)&ir_work_mode,
sizeof(int) / 4);
if (ret) {
#else
ir_work_mode = get_ir_work_mode(&ret);
if (ret == ir_work_mode) {
#endif
printf("ir_work_mode not set, use default mode: android recovery mode.\n");
gd->key_pressd_value = BOOT_RECOVERY_VALUE;
} else {
switch (ir_work_mode) {
case EFEX_MODE_CONFIG:
gd->key_pressd_value = EFEX_VALUE;
break;
case ONEKEY_SPRITE_RECOVERY_MODE_CONFIG:
gd->key_pressd_value = SPRITE_RECOVERY_VALUE;
break;
case RECOVERY_MODE_CONFIG:
gd->key_pressd_value = BOOT_RECOVERY_VALUE;
break;
case FACTORY_MODE_CONFIG:
gd->key_pressd_value = BOOT_FACTORY_VALUE;
break;
}
}
}
pr_notice("line:%d gd->key_pressd_value=0x%lx\n", __LINE__,
gd->key_pressd_value);
return 0;
}