blob: 2b3ff2c992b8c379bc3cae0a99866cdf50e2f48d [file]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
//#define DEBUG
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/amlogic/gki_module.h>
#include "hdmitx_boot_parameters.h"
static struct hdmitx_boot_param tx_params = {
.fraction_refreshrate = 1,
.edid_chksum = "invalidcrc",
};
struct hdmitx_boot_param *get_hdmitx_boot_params(void)
{
return &tx_params;
}
/* besides characters defined in separator, '\"' are used as separator;
* and any characters in '\"' will not act as separator
*/
static char *next_token_ex(char *separator, char *buf, unsigned int size,
unsigned int offset, unsigned int *token_len,
unsigned int *token_offset)
{
char *token = NULL;
char last_separator = 0;
char trans_char_flag = 0;
if (buf) {
for (; offset < size; offset++) {
int ii = 0;
char ch;
if (buf[offset] == '\\') {
trans_char_flag = 1;
continue;
}
while (((ch = separator[ii++]) != buf[offset]) && (ch))
;
if (ch) {
if (!token) {
continue;
} else {
if (last_separator != '"') {
*token_len = (unsigned int)
(buf + offset - token);
*token_offset = offset;
return token;
}
}
} else if (!token) {
if (trans_char_flag && (buf[offset] == '"'))
last_separator = buf[offset];
token = &buf[offset];
} else if ((trans_char_flag && (buf[offset] == '"')) &&
(last_separator == '"')) {
*token_len = (unsigned int)(buf + offset - token - 2);
*token_offset = offset + 1;
return token + 1;
}
trans_char_flag = 0;
}
if (token) {
*token_len = (unsigned int)(buf + offset - token);
*token_offset = offset;
}
}
return token;
}
/* check the colorattribute from uboot */
static int get_hdmitx_color_attr(char *token, char *color_attr)
{
char attr[16] = {0};
const char * const cs[] = {
"444", "422", "rgb", "420", NULL};
const char * const cd[] = {
"8bit", "10bit", "12bit", "16bit", NULL};
int i;
int ret = -1;
if (!token)
return -1;
for (i = 0; cs[i]; i++) {
if (strstr(token, cs[i])) {
if (strlen(cs[i]) < sizeof(attr))
strcpy(attr, cs[i]);
strcat(attr, ",");
break;
}
}
for (i = 0; cd[i]; i++) {
if (strstr(token, cd[i])) {
if (strlen(cd[i]) < sizeof(attr))
if (strlen(cd[i]) <
(sizeof(attr) - strlen(attr)))
strcat(attr, cd[i]);
if (strlen(attr) >= sizeof(attr)) {
pr_err("get err attr: %zu-%s\n", strlen(attr), attr);
} else {
strncpy(color_attr, attr, strlen(attr));
ret = 0;
}
break;
}
}
return ret;
}
static int parse_hdmitx_boot_para(char *s)
{
char separator[] = {' ', ',', ';', 0x0};
char *token;
unsigned int token_len = 0;
unsigned int token_offset = 0;
unsigned int offset = 0;
int size = strlen(s);
memset(tx_params.color_attr, 0, sizeof(tx_params.color_attr));
tx_params.init_state = 0;
do {
token = next_token_ex(separator, s, size, offset,
&token_len, &token_offset);
if (token) {
if (token_len == 3 &&
strncmp(token, "off", token_len) == 0) {
tx_params.init_state |= INIT_FLAG_NOT_LOAD;
}
if (tx_params.color_attr[0] == 0)
get_hdmitx_color_attr(token, tx_params.color_attr);
}
offset = token_offset;
} while (token);
pr_debug("hdmitx_param:[color_attr]=[%s]\n",
tx_params.color_attr);
pr_debug("hdmitx_param:[init_state]=[%x]\n",
tx_params.init_state);
return 0;
}
__setup("hdmitx=", parse_hdmitx_boot_para);
static int parse_hdmitx_fraction_rate(char *str)
{
if (strncmp("0", str, 1) == 0)
tx_params.fraction_refreshrate = 0;
else
tx_params.fraction_refreshrate = 1;
pr_debug("hdmitx_param:[fraction_rate]=[%d]\n",
tx_params.fraction_refreshrate);
return 0;
}
__setup("frac_rate_policy=", parse_hdmitx_fraction_rate);
static int parse_hdmitx_hdr_priority(char *str)
{
if ((strncmp("1", str, 1) == 0) || (strncmp("2", str, 1) == 0))
tx_params.hdr_mask = str[0] - '0';
else
tx_params.hdr_mask = 0;
pr_debug("hdmitx_param:[hdr_priority]=[%d]\n",
tx_params.hdr_mask);
return 0;
}
__setup("hdr_priority=", parse_hdmitx_hdr_priority);
static int parse_hdmitx_checksum(char *str)
{
snprintf(tx_params.edid_chksum, sizeof(tx_params.edid_chksum), "%s", str);
pr_debug("hdmitx_param:[checksum]=[%s]\n", tx_params.edid_chksum);
return 0;
}
__setup("hdmichecksum=", parse_hdmitx_checksum);
static int hdmitx_config_csc_en(char *str)
{
if (strncmp("1", str, 1) == 0)
tx_params.config_csc = true;
else
tx_params.config_csc = false;
pr_debug("config_csc_en:[config_csc_en]=[%d]\n", tx_params.config_csc);
return 0;
}
__setup("config_csc_en=", hdmitx_config_csc_en);