blob: 015c357bf3f88c27050dd21c5fbfe5a8a7582be2 [file] [log] [blame]
/*
* drivers/amlogic/media/vout/lcd/lcd_unifykey.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/init.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/reset.h>
#include <linux/amlogic/media/vout/lcd/lcd_unifykey.h>
#include <linux/amlogic/media/vout/lcd/lcd_vout.h>
#define LCDUKEY(fmt, args...) pr_info("lcd ukey: "fmt"", ## args)
#define LCDUKEYERR(fmt, args...) pr_info("lcd ukey err: error: "fmt"", ## args)
#ifdef CONFIG_AMLOGIC_UNIFYKEY
static unsigned int cal_crc32(unsigned int crc, const unsigned char *buf,
int buf_len) {
unsigned int s_crc32[16] = {
0, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
};
unsigned int crcu32 = crc;
unsigned char b;
if (buf_len <= 0)
return 0;
if (!buf)
return 0;
crcu32 = ~crcu32;
while (buf_len--) {
b = *buf++;
crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
}
return ~crcu32;
}
int lcd_unifykey_len_check(int key_len, int len)
{
if (key_len < len) {
LCDUKEYERR("invalid unifykey length %d, need %d\n",
key_len, len);
return -1;
}
return 0;
}
int lcd_unifykey_header_check(unsigned char *buf,
struct aml_lcd_unifykey_header_s *header)
{
header->crc32 = (buf[0] | (buf[1] << 8) |
(buf[2] << 16) | (buf[3] << 24));
header->data_len = (buf[4] | (buf[5] << 8));
header->version = (buf[6] | (buf[7] << 8));
header->reserved = (buf[8] | (buf[9] << 8));
return 0;
}
int lcd_unifykey_check(char *key_name)
{
unsigned int key_exist, keypermit, key_len;
unsigned char *buf;
struct aml_lcd_unifykey_header_s key_header;
int retry_cnt = 0;
unsigned int key_crc32;
int ret;
if (key_name == NULL) {
LCDUKEYERR("%s: key_name is null\n", __func__);
return -1;
}
key_exist = 0;
key_len = 0;
ret = key_unify_query(get_ukdev(), key_name, &key_exist, &keypermit);
if (ret < 0) {
if (lcd_debug_print_flag)
LCDUKEYERR("%s query exist error\n", key_name);
return -1;
}
if (key_exist == 0) {
if (lcd_debug_print_flag)
LCDUKEYERR("%s is not exist\n", key_name);
return -1;
}
ret = key_unify_size(get_ukdev(), key_name, &key_len);
if (ret < 0) {
LCDUKEYERR("%s query size error\n", key_name);
return -1;
}
if (key_len == 0) {
if (lcd_debug_print_flag)
LCDUKEY("%s size is zero\n", key_name);
return -1;
}
if (lcd_debug_print_flag)
LCDUKEY("%s size: %d\n", key_name, key_len);
buf = kzalloc((sizeof(unsigned char) * key_len), GFP_KERNEL);
if (!buf) {
LCDUKEYERR("%s: Not enough memory\n", __func__);
return -1;
}
lcd_unifykey_check_read:
ret = key_unify_read(get_ukdev(), key_name, buf, key_len, &key_len);
if (ret < 0) {
LCDUKEYERR("%s unify read error\n", key_name);
goto lcd_unifykey_check_err;
}
/* check header */
if (key_len <= LCD_UKEY_HEAD_SIZE) {
LCDUKEYERR("%s unify key_len %d error\n", key_name, key_len);
goto lcd_unifykey_check_err;
}
lcd_unifykey_header_check(buf, &key_header);
if (key_len != key_header.data_len) { /* length check */
if (lcd_debug_print_flag) {
LCDUKEYERR("data_len %d is not match key_len %d\n",
key_header.data_len, key_len);
}
if (retry_cnt < LCD_UKEY_RETRY_CNT_MAX) {
retry_cnt++;
memset(buf, 0, key_len);
goto lcd_unifykey_check_read;
}
LCDUKEYERR("%s: load unifykey failed\n", key_name);
goto lcd_unifykey_check_err;
}
key_crc32 = cal_crc32(0, &buf[4], (key_len - 4)); /* except crc32 */
if (lcd_debug_print_flag) {
LCDUKEY("crc32: 0x%08x, header_crc32: 0x%08x\n",
key_crc32, key_header.crc32);
}
if (key_crc32 != key_header.crc32) { /* crc32 check */
LCDUKEYERR("crc32 0x%08x is not match header_crc32 0x%08x\n",
key_header.crc32, key_crc32);
if (retry_cnt < LCD_UKEY_RETRY_CNT_MAX) {
retry_cnt++;
memset(buf, 0, key_len);
goto lcd_unifykey_check_read;
}
LCDUKEYERR("%s: load unifykey failed\n", key_name);
goto lcd_unifykey_check_err;
}
kfree(buf);
return 0;
lcd_unifykey_check_err:
kfree(buf);
return -1;
}
int lcd_unifykey_get(char *key_name, unsigned char *buf, int *len)
{
int key_len;
int ret;
key_len = 0;
ret = lcd_unifykey_check(key_name);
if (ret < 0)
return -1;
ret = key_unify_size(get_ukdev(), key_name, &key_len);
if (key_len > *len) {
LCDUKEYERR("%s size(%d) is bigger than buf_size(%d)\n",
key_name, key_len, *len);
return -1;
}
*len = key_len;
ret = key_unify_read(get_ukdev(), key_name, buf, key_len, &key_len);
if (ret < 0) {
LCDUKEYERR("%s unify read error\n", key_name);
return -1;
}
return 0;
}
int lcd_unifykey_check_no_header(char *key_name)
{
unsigned int key_exist, keypermit, key_len;
int ret;
key_exist = 0;
key_len = 0;
ret = key_unify_query(get_ukdev(), key_name, &key_exist, &keypermit);
if (ret < 0) {
if (lcd_debug_print_flag)
LCDUKEYERR("%s query exist error\n", key_name);
return -1;
}
if (key_exist == 0) {
if (lcd_debug_print_flag)
LCDUKEYERR("%s is not exist\n", key_name);
return -1;
}
ret = key_unify_size(get_ukdev(), key_name, &key_len);
if (ret < 0) {
LCDUKEYERR("%s query size error\n", key_name);
return -1;
}
if (key_len == 0) {
if (lcd_debug_print_flag)
LCDUKEY("%s size is zero\n", key_name);
return -1;
}
if (lcd_debug_print_flag)
LCDUKEY("%s size: %d\n", key_name, key_len);
return 0;
}
int lcd_unifykey_get_no_header(char *key_name, unsigned char *buf, int *len)
{
int key_len;
int ret;
key_len = 0;
ret = lcd_unifykey_check_no_header(key_name);
if (ret < 0)
return -1;
ret = key_unify_size(get_ukdev(), key_name, &key_len);
if (key_len > *len) {
LCDUKEYERR("%s size(%d) is bigger than buf_size(%d)\n",
key_name, key_len, *len);
return -1;
}
*len = key_len;
ret = key_unify_read(get_ukdev(), key_name, buf, key_len, &key_len);
if (ret < 0) {
LCDUKEYERR("%s unify read error\n", key_name);
return -1;
}
return 0;
}
void lcd_unifykey_print(void)
{
unsigned char *buf;
char *key_name;
unsigned int key_len;
int i, j;
int ret;
buf = kmalloc(600*sizeof(unsigned char), GFP_KERNEL);
if (buf == NULL) {
LCDUKEY("lcd_unifykey buf malloc error\n");
return;
}
key_name = "lcd";
key_len = LCD_UKEY_LCD_SIZE;
ret = lcd_unifykey_get(key_name, buf, &key_len);
if (ret < 0)
goto exit_print_backlight;
LCDUKEY("%s: %s: %d\n", __func__, key_name, key_len);
i = 0;
while (1) {
pr_info("0x%08x: ", (i * 16));
for (j = 0; j < 16; j++) {
if ((i*16+j) < key_len) {
pr_info("0x%02x ", buf[i*16+j]);
} else {
pr_info("\n");
goto exit_print_lcd;
}
}
pr_info("\n");
i++;
}
exit_print_lcd:
key_name = "lcd_extern";
key_len = LCD_UKEY_LCD_EXT_SIZE;
ret = lcd_unifykey_get(key_name, buf, &key_len);
if (ret < 0)
goto exit_print_backlight;
LCDUKEY("%s: %s: %d\n", __func__, key_name, key_len);
i = 0;
while (1) {
pr_info("0x%08x: ", (i * 16));
for (j = 0; j < 16; j++) {
if ((i*16+j) < key_len) {
pr_info("0x%02x ", buf[i*16+j]);
} else {
pr_info("\n");
goto exit_print_lcd_ext;
}
}
pr_info("\n");
i++;
}
exit_print_lcd_ext:
key_name = "backlight";
key_len = LCD_UKEY_BL_SIZE;
ret = lcd_unifykey_get(key_name, buf, &key_len);
if (ret < 0)
goto exit_print_backlight;
LCDUKEY("%s: %s: %d\n", __func__, key_name, key_len);
i = 0;
while (1) {
pr_info("0x%08x: ", (i * 16));
for (j = 0; j < 16; j++) {
if ((i*16+j) < key_len) {
pr_info("0x%02x ", buf[i*16+j]);
} else {
pr_info("\n");
goto exit_print_backlight;
}
}
pr_info("\n");
i++;
}
exit_print_backlight:
kfree(buf);
}
#else
/* dummy driver */
int lcd_unifykey_len_check(int key_len, int len)
{
LCDUKEYERR("Don't support unifykey\n");
return -1;
}
int lcd_unifykey_header_check(unsigned char *buf,
struct aml_lcd_unifykey_header_s *header)
{
LCDUKEYERR("Don't support unifykey\n");
return -1;
}
int lcd_unifykey_check(char *key_name)
{
LCDUKEYERR("Don't support unifykey\n");
return -1;
}
int lcd_unifykey_get(char *key_name, unsigned char *buf, int *len)
{
LCDUKEYERR("Don't support unifykey\n");
return -1;
}
int lcd_unifykey_check_no_header(char *key_name)
{
LCDUKEYERR("Don't support unifykey\n");
return -1;
}
int lcd_unifykey_get_no_header(char *key_name, unsigned char *buf, int *len)
{
LCDUKEYERR("Don't support unifykey\n");
return -1;
}
void lcd_unifykey_print(void)
{
LCDUKEYERR("Don't support unifykey\n");
}
#endif