mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2025-09-16 03:59:21 +00:00
2241 lines
64 KiB
C
2241 lines
64 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2021 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
#include <linux/of.h>
|
|
#include <linux/types.h>
|
|
#include "mtk_drm_panel_helper.h"
|
|
|
|
unsigned long long mtk_lcm_total_size;
|
|
|
|
/* read u32 array and parsing into u32 buffer */
|
|
int mtk_lcm_dts_read_u32_array(struct device_node *np, char *prop,
|
|
u32 *out, int min_len, int max_len)
|
|
{
|
|
int len = 0;
|
|
|
|
if (IS_ERR_OR_NULL(prop) ||
|
|
IS_ERR_OR_NULL(np) ||
|
|
IS_ERR_OR_NULL(out) ||
|
|
max_len == 0)
|
|
return 0;
|
|
|
|
len = of_property_read_variable_u32_array(np,
|
|
prop, out, min_len, max_len);
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
if (len == 1)
|
|
DDPMSG("%s: %s = %u\n", __func__, prop, *out);
|
|
else if (len > 0)
|
|
DDPMSG("%s: %s array of %d data\n", __func__, prop, len);
|
|
else if (len == 0)
|
|
DDPMSG("%s: %s is empty\n", __func__, prop);
|
|
else
|
|
DDPMSG("%s: %s is not existed or overflow, %d\n",
|
|
__func__, prop, len);
|
|
#endif
|
|
|
|
return len;
|
|
}
|
|
|
|
void mtk_lcm_dts_read_u32(struct device_node *np, char *prop,
|
|
u32 *out)
|
|
{
|
|
mtk_lcm_dts_read_u32_array(np, prop, out, 0, 1);
|
|
}
|
|
|
|
void mtk_lcm_dts_read_u8(struct device_node *np, char *prop,
|
|
u8 *out)
|
|
{
|
|
int ret = 0;
|
|
u32 data = 0;
|
|
|
|
ret = mtk_lcm_dts_read_u32_array(np, prop, &data, 0, 1);
|
|
if (ret == 0)
|
|
*out = (u8)data;
|
|
}
|
|
|
|
/* read u32 array and parsing into u8 buffer */
|
|
int mtk_lcm_dts_read_u8_array_from_u32(struct device_node *np, char *prop,
|
|
u8 *out, int min_len, int max_len)
|
|
{
|
|
int len = 0, i = 0;
|
|
u32 *data = NULL;
|
|
|
|
if (IS_ERR_OR_NULL(prop) ||
|
|
IS_ERR_OR_NULL(np) ||
|
|
IS_ERR_OR_NULL(out) ||
|
|
max_len == 0)
|
|
return 0;
|
|
|
|
LCM_KZALLOC(data, sizeof(u32) * max_len, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(data)) {
|
|
DDPMSG("%s, failed to allocate buffer\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
len = of_property_read_variable_u32_array(np,
|
|
prop, data, min_len, max_len);
|
|
if (len == 1) {
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("%s: %s = 0x%x\n", __func__, prop, *data);
|
|
#endif
|
|
*out = (u8)(*data);
|
|
} else if (len > 0) {
|
|
for (i = 0; i < len; i++)
|
|
out[i] = (u8)data[i];
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("%s: %s array of %d data\n", __func__, prop, len);
|
|
} else if (len == 0) {
|
|
DDPMSG("%s: %s is empty\n", __func__, prop);
|
|
} else {
|
|
DDPMSG("%s: %s is not existed or overflow, %d\n",
|
|
__func__, prop, len);
|
|
#endif
|
|
}
|
|
|
|
LCM_KFREE(data, sizeof(u32) * max_len);
|
|
return len;
|
|
}
|
|
|
|
/* read u8 array and parsing into u8 buffer */
|
|
int mtk_lcm_dts_read_u8_array(struct device_node *np, char *prop,
|
|
u8 *out, int min_len, int max_len)
|
|
{
|
|
int len = 0;
|
|
|
|
if (IS_ERR_OR_NULL(prop) ||
|
|
IS_ERR_OR_NULL(np) ||
|
|
IS_ERR_OR_NULL(out) ||
|
|
max_len == 0)
|
|
return 0;
|
|
|
|
len = of_property_read_variable_u8_array(np,
|
|
prop, out, min_len, max_len);
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
if (len == 1) {
|
|
DDPMSG("%s: %s = 0x%x\n", __func__, prop, *out);
|
|
} else if (len > 0) {
|
|
int i = 0;
|
|
|
|
DDPMSG("%s: %s array of %d data\n", __func__, prop, len);
|
|
for (i = 0; i < len - 8; i += 8)
|
|
DDPMSG("data%u: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
|
i, out[i], out[i+1], out[i+2], out[i+3],
|
|
out[i+4], out[i+5], out[i+6], out[i+7]);
|
|
} else if (len == 0) {
|
|
DDPMSG("%s: %s is empty\n", __func__, prop);
|
|
} else {
|
|
DDPMSG("%s: %s is not existed or overflow, %d\n",
|
|
__func__, prop, len);
|
|
}
|
|
#endif
|
|
|
|
return len;
|
|
}
|
|
|
|
static int parse_lcm_params_dt_node(struct device_node *np,
|
|
struct mtk_lcm_params *params)
|
|
{
|
|
struct device_node *type_np = NULL;
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(params)) {
|
|
DDPPR_ERR("%s: invalid lcm params\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
memset(params, 0x0, sizeof(struct mtk_lcm_params));
|
|
|
|
ret = of_property_read_string(np, "lcm-params-name",
|
|
¶ms->name);
|
|
DDPMSG("%s, lcm name:%s\n", __func__, params->name);
|
|
|
|
mtk_lcm_dts_read_u32(np, "lcm-params-types",
|
|
¶ms->type);
|
|
mtk_lcm_dts_read_u32_array(np, "lcm-params-resolution",
|
|
¶ms->resolution[0], 0, 2);
|
|
mtk_lcm_dts_read_u32(np, "lcm-params-physical_width",
|
|
¶ms->physical_width);
|
|
mtk_lcm_dts_read_u32(np, "lcm-params-physical_height",
|
|
¶ms->physical_height);
|
|
dump_lcm_params_basic(params);
|
|
|
|
switch (params->type) {
|
|
case MTK_LCM_FUNC_DBI:
|
|
for_each_available_child_of_node(np, type_np) {
|
|
if (of_device_is_compatible(type_np,
|
|
"mediatek,lcm-params-dbi")) {
|
|
ret = parse_lcm_params_dbi(type_np,
|
|
¶ms->dbi_params);
|
|
if (ret >= 0)
|
|
dump_lcm_params_dbi(¶ms->dbi_params, NULL);
|
|
}
|
|
}
|
|
break;
|
|
case MTK_LCM_FUNC_DPI:
|
|
for_each_available_child_of_node(np, type_np) {
|
|
if (of_device_is_compatible(type_np,
|
|
"mediatek,lcm-params-dpi")) {
|
|
ret = parse_lcm_params_dpi(type_np,
|
|
¶ms->dpi_params);
|
|
if (ret >= 0)
|
|
dump_lcm_params_dpi(¶ms->dpi_params, NULL);
|
|
}
|
|
}
|
|
break;
|
|
case MTK_LCM_FUNC_DSI:
|
|
for_each_available_child_of_node(np, type_np) {
|
|
if (of_device_is_compatible(type_np,
|
|
"mediatek,lcm-params-dsi")) {
|
|
ret = parse_lcm_params_dsi(type_np,
|
|
¶ms->dsi_params);
|
|
if (ret >= 0)
|
|
dump_lcm_params_dsi(¶ms->dsi_params, NULL);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DDPPR_ERR("%s, invalid lcm type:%d\n",
|
|
__func__, params->type);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#define MTK_LCM_DATA_OFFSET (2)
|
|
static int parse_lcm_ops_func_util(struct mtk_lcm_ops_data *lcm_op, u8 *dts,
|
|
unsigned int len)
|
|
{
|
|
if (IS_ERR_OR_NULL(lcm_op) ||
|
|
IS_ERR_OR_NULL(dts)) {
|
|
DDPMSG("%s,%d: invalid parameters\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_UTIL_TYPE_RESET:
|
|
/* func type size data */
|
|
lcm_op->param.util_data = (unsigned int)dts[MTK_LCM_DATA_OFFSET];
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_MDELAY:
|
|
case MTK_LCM_UTIL_TYPE_UDELAY:
|
|
/* func type size data */
|
|
lcm_op->param.util_data = (unsigned int)dts[MTK_LCM_DATA_OFFSET];
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_VOLTAGE:
|
|
/* func type size addr level */
|
|
lcm_op->param.util_data = (unsigned int)dts[MTK_LCM_DATA_OFFSET];
|
|
break;
|
|
default:
|
|
DDPPR_ERR("%s/%d: invalid type:%d\n",
|
|
__func__, __LINE__, lcm_op->type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_lcm_ops_func_cmd(struct mtk_lcm_ops_data *lcm_op, u8 *dts,
|
|
unsigned int len)
|
|
{
|
|
if (IS_ERR_OR_NULL(lcm_op) ||
|
|
IS_ERR_OR_NULL(dts)) {
|
|
DDPMSG("%s,%d: invalid parameters\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER:
|
|
/* func type size data0 data1 ... */
|
|
LCM_KZALLOC(lcm_op->param.buffer_data, lcm_op->size + 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.buffer_data)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(lcm_op->param.buffer_data,
|
|
dts + MTK_LCM_DATA_OFFSET, lcm_op->size);
|
|
*(lcm_op->param.buffer_data + lcm_op->size) = '\0';
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_CONDITION:
|
|
/* func type size input_type condition data0 data1 ... */
|
|
LCM_KZALLOC(lcm_op->param.buf_con_data.data, lcm_op->size - 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.buf_con_data.data)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
lcm_op->param.buf_con_data.name = dts[MTK_LCM_DATA_OFFSET];
|
|
lcm_op->param.buf_con_data.condition = dts[MTK_LCM_DATA_OFFSET + 1];
|
|
lcm_op->param.buf_con_data.data_len = lcm_op->size - 2;
|
|
memcpy(lcm_op->param.buf_con_data.data,
|
|
dts + MTK_LCM_DATA_OFFSET + 2,
|
|
lcm_op->param.buf_con_data.data_len);
|
|
*(lcm_op->param.buf_con_data.data +
|
|
lcm_op->param.buf_con_data.data_len) = '\0';
|
|
DDPMSG("%s, condition, %u, %u, %u\n", __func__,
|
|
lcm_op->param.buf_con_data.name,
|
|
lcm_op->param.buf_con_data.condition,
|
|
(unsigned int)lcm_op->param.buf_con_data.data_len);
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_RUNTIME_INPUT:
|
|
/* func type size input_type id data0 data1 ... */
|
|
LCM_KZALLOC(lcm_op->param.buf_runtime_data.data, lcm_op->size - 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.buf_runtime_data.data)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
lcm_op->param.buf_runtime_data.name = dts[MTK_LCM_DATA_OFFSET];
|
|
lcm_op->param.buf_runtime_data.id = dts[MTK_LCM_DATA_OFFSET + 1];
|
|
lcm_op->param.buf_runtime_data.data_len = lcm_op->size - 2;
|
|
if (lcm_op->param.buf_runtime_data.data_len <=
|
|
lcm_op->param.buf_runtime_data.id) {
|
|
DDPMSG("%s, %d, runtime data index:%u is invalid, %u\n",
|
|
__func__, __LINE__,
|
|
lcm_op->param.buf_runtime_data.id,
|
|
(unsigned int)lcm_op->param.buf_runtime_data.data_len);
|
|
LCM_KFREE(lcm_op->param.buf_runtime_data.data,
|
|
lcm_op->param.buf_runtime_data.data_len + 1);
|
|
return -EINVAL;
|
|
}
|
|
memcpy(lcm_op->param.buf_runtime_data.data,
|
|
dts + MTK_LCM_DATA_OFFSET + 2,
|
|
lcm_op->param.buf_runtime_data.data_len);
|
|
*(lcm_op->param.buf_runtime_data.data +
|
|
lcm_op->param.buf_runtime_data.data_len) = '\0';
|
|
DDPMSG("%s, runtime, %u, %u, %u\n", __func__,
|
|
lcm_op->param.buf_runtime_data.name,
|
|
lcm_op->param.buf_runtime_data.id,
|
|
(unsigned int)lcm_op->param.buf_runtime_data.data_len);
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_CMD:
|
|
/* func type size cmd data0 data1 ... */
|
|
LCM_KZALLOC(lcm_op->param.cmd_data.data, lcm_op->size, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cmd_data.data)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
lcm_op->param.cmd_data.cmd = dts[MTK_LCM_DATA_OFFSET];
|
|
lcm_op->param.cmd_data.data_len = lcm_op->size - 1;
|
|
memcpy(lcm_op->param.cmd_data.data,
|
|
dts + MTK_LCM_DATA_OFFSET + 1,
|
|
lcm_op->size - 1);
|
|
*(lcm_op->param.cmd_data.data + lcm_op->size - 1) = '\0';
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_BUFFER:
|
|
/* func type size data0 data1 ... */
|
|
LCM_KZALLOC(lcm_op->param.cmd_data.data, lcm_op->size - 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cmd_data.data)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
lcm_op->param.cmd_data.start_id = dts[MTK_LCM_DATA_OFFSET];
|
|
lcm_op->param.cmd_data.data_len = dts[MTK_LCM_DATA_OFFSET + 1];
|
|
memcpy(lcm_op->param.cmd_data.data,
|
|
dts + MTK_LCM_DATA_OFFSET + 2,
|
|
lcm_op->size - 2);
|
|
*(lcm_op->param.cmd_data.data + lcm_op->size - 2) = '\0';
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_CMD:
|
|
/* func type size cmd data0 data1 ... */
|
|
LCM_KZALLOC(lcm_op->param.cmd_data.data, lcm_op->size - 2, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cmd_data.data)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
lcm_op->param.cmd_data.start_id = dts[MTK_LCM_DATA_OFFSET];
|
|
lcm_op->param.cmd_data.data_len = dts[MTK_LCM_DATA_OFFSET + 1];
|
|
lcm_op->param.cmd_data.cmd = dts[MTK_LCM_DATA_OFFSET + 2];
|
|
*(lcm_op->param.cmd_data.data) = '\0';
|
|
break;
|
|
default:
|
|
DDPPR_ERR("%s/%d: invalid type:%d\n",
|
|
__func__, __LINE__, lcm_op->type);
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int parse_lcm_ops_func_cb(struct mtk_lcm_ops_data *lcm_op, u8 *dts,
|
|
unsigned int len)
|
|
{
|
|
if (IS_ERR_OR_NULL(lcm_op) ||
|
|
IS_ERR_OR_NULL(dts)) {
|
|
DDPMSG("%s,%d: invalid parameters\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_CB_TYPE_RUNTIME:
|
|
/* func type size data0 data1 ... */
|
|
LCM_KZALLOC(lcm_op->param.cb_id_data.buffer_data, lcm_op->size + 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cb_id_data.buffer_data)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
lcm_op->param.cb_id_data.data_count = lcm_op->size;
|
|
memcpy(lcm_op->param.cb_id_data.buffer_data,
|
|
dts + MTK_LCM_DATA_OFFSET, lcm_op->size);
|
|
*(lcm_op->param.cb_id_data.buffer_data + lcm_op->size) = '\0';
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT:
|
|
/* func type size data0 data1 ... */
|
|
lcm_op->param.cb_id_data.id_count = 1;
|
|
lcm_op->param.cb_id_data.data_count = lcm_op->size - 1;
|
|
LCM_KZALLOC(lcm_op->param.cb_id_data.buffer_data,
|
|
lcm_op->param.cb_id_data.data_count + 1, GFP_KERNEL);
|
|
LCM_KZALLOC(lcm_op->param.cb_id_data.id,
|
|
lcm_op->param.cb_id_data.id_count + 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cb_id_data.buffer_data) ||
|
|
IS_ERR_OR_NULL(lcm_op->param.cb_id_data.id)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
lcm_op->param.cb_id_data.id[0] = dts[MTK_LCM_DATA_OFFSET];
|
|
lcm_op->param.cb_id_data.id[1] = '\0';
|
|
memcpy(lcm_op->param.cb_id_data.buffer_data,
|
|
dts + MTK_LCM_DATA_OFFSET + 1,
|
|
lcm_op->param.cb_id_data.data_count);
|
|
*(lcm_op->param.cb_id_data.buffer_data +
|
|
lcm_op->param.cb_id_data.data_count) = '\0';
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT_MULTIPLE:
|
|
/* func type size id_count id0, id1 ... data_count data0 data1 ... */
|
|
lcm_op->param.cb_id_data.id_count = dts[MTK_LCM_DATA_OFFSET];
|
|
LCM_KZALLOC(lcm_op->param.cb_id_data.id,
|
|
lcm_op->param.cb_id_data.id_count + 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cb_id_data.id)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate id\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
memcpy(lcm_op->param.cb_id_data.id,
|
|
dts + MTK_LCM_DATA_OFFSET + 1,
|
|
lcm_op->param.cb_id_data.id_count);
|
|
*(lcm_op->param.cb_id_data.id +
|
|
lcm_op->param.cb_id_data.id_count) = '\0';
|
|
|
|
lcm_op->param.cb_id_data.data_count = dts[MTK_LCM_DATA_OFFSET +
|
|
lcm_op->param.cb_id_data.id_count + 1];
|
|
LCM_KZALLOC(lcm_op->param.cb_id_data.buffer_data,
|
|
lcm_op->param.cb_id_data.data_count + 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cb_id_data.id)) {
|
|
DDPPR_ERR("%s,%d: failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
memcpy(lcm_op->param.cb_id_data.buffer_data,
|
|
dts + MTK_LCM_DATA_OFFSET +
|
|
lcm_op->param.cb_id_data.id_count + 2,
|
|
lcm_op->param.cb_id_data.data_count);
|
|
*(lcm_op->param.cb_id_data.buffer_data +
|
|
lcm_op->param.cb_id_data.data_count) = '\0';
|
|
break;
|
|
default:
|
|
DDPPR_ERR("%s/%d: invalid type:%d\n",
|
|
__func__, __LINE__, lcm_op->type);
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int parse_lcm_ops_func_gpio(struct mtk_lcm_ops_data *lcm_op, u8 *dts,
|
|
unsigned int len)
|
|
{
|
|
if (IS_ERR_OR_NULL(lcm_op) ||
|
|
IS_ERR_OR_NULL(dts)) {
|
|
DDPMSG("%s,%d: invalid parameters\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_GPIO_TYPE_MODE:
|
|
case MTK_LCM_GPIO_TYPE_DIR_OUTPUT:
|
|
case MTK_LCM_GPIO_TYPE_DIR_INPUT:
|
|
case MTK_LCM_GPIO_TYPE_OUT:
|
|
if (lcm_op->size != 2) {
|
|
DDPMSG("%s,%d: invalid gpio size %u\n",
|
|
__func__, __LINE__, lcm_op->size);
|
|
return -EINVAL;
|
|
}
|
|
lcm_op->param.gpio_data.gpio_id = dts[MTK_LCM_DATA_OFFSET];
|
|
lcm_op->param.gpio_data.data = dts[MTK_LCM_DATA_OFFSET + 1];
|
|
break;
|
|
default:
|
|
DDPPR_ERR("%s/%d: invalid type:%d\n",
|
|
__func__, __LINE__, lcm_op->type);
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int parse_lcm_ops_func_cust(struct mtk_lcm_ops_data *lcm_op,
|
|
u8 *dts, struct mtk_panel_cust *cust)
|
|
{
|
|
if (IS_ERR_OR_NULL(lcm_op) ||
|
|
IS_ERR_OR_NULL(dts) || IS_ERR_OR_NULL(cust))
|
|
return -EINVAL;
|
|
|
|
if (atomic_read(&cust->cust_enabled) == 0 ||
|
|
IS_ERR_OR_NULL(cust->parse_ops))
|
|
return -EINVAL;
|
|
|
|
cust->parse_ops(lcm_op->func, lcm_op->type,
|
|
dts, lcm_op->size, lcm_op->param.cust_data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_lcm_ops_basic(struct mtk_lcm_ops_data *lcm_op, u8 *dts,
|
|
struct mtk_panel_cust *cust, unsigned int len)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op) || IS_ERR_OR_NULL(dts) || len == 0) {
|
|
DDPPR_ERR("%s %d: invalid cmd\n", __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (len - lcm_op->size < MTK_LCM_DATA_OFFSET) {
|
|
DDPMSG("%s,%d: dts length is not enough %u,%u\n",
|
|
__func__, __LINE__, len, lcm_op->size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (lcm_op->type > MTK_LCM_UTIL_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_UTIL_TYPE_END)
|
|
ret = parse_lcm_ops_func_util(lcm_op, dts, len);
|
|
else if (lcm_op->type > MTK_LCM_CMD_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_CMD_TYPE_END)
|
|
ret = parse_lcm_ops_func_cmd(lcm_op, dts, len);
|
|
else if (lcm_op->type > MTK_LCM_LK_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_LK_TYPE_END)
|
|
ret = parse_lcm_ops_func_cmd(lcm_op, dts, len);
|
|
else if (lcm_op->type > MTK_LCM_CB_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_CB_TYPE_END)
|
|
ret = parse_lcm_ops_func_cb(lcm_op, dts, len);
|
|
else if (lcm_op->type > MTK_LCM_GPIO_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_GPIO_TYPE_END)
|
|
ret = parse_lcm_ops_func_gpio(lcm_op, dts, len);
|
|
else if (lcm_op->type > MTK_LCM_CUST_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_CUST_TYPE_END)
|
|
ret = parse_lcm_ops_func_cust(lcm_op,
|
|
dts, cust);
|
|
else {
|
|
DDPPR_ERR("%s/%d: invalid type:0x%x\n",
|
|
__func__, __LINE__, lcm_op->type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int parse_lcm_ops_check(struct mtk_lcm_ops_data *ops, u8 *dts,
|
|
unsigned int len, int curr_status, unsigned int phase)
|
|
{
|
|
unsigned int i = 0, phase_tmp = 0;
|
|
int phase_skip_flag = curr_status;
|
|
|
|
if (IS_ERR_OR_NULL(ops) || IS_ERR_OR_NULL(dts)) {
|
|
DDPMSG("%s,%d: invalid parameters, len:%u\n",
|
|
__func__, __LINE__, len);
|
|
return phase_skip_flag;
|
|
}
|
|
|
|
if (len - ops->size < MTK_LCM_DATA_OFFSET) {
|
|
DDPMSG("%s,%d: dts length is not enough %u,%u\n",
|
|
__func__, __LINE__, len, ops->size);
|
|
return phase_skip_flag;
|
|
}
|
|
|
|
if (ops->type == MTK_LCM_PHASE_TYPE_START &&
|
|
curr_status != MTK_LCM_PHASE_TYPE_START) {
|
|
for (i = 0; i < ops->size; i++)
|
|
phase_tmp |= dts[i + MTK_LCM_DATA_OFFSET];
|
|
|
|
if ((phase_tmp & phase) != phase)
|
|
phase_skip_flag = MTK_LCM_PHASE_TYPE_START;
|
|
} else if (ops->type == MTK_LCM_PHASE_TYPE_END &&
|
|
curr_status == MTK_LCM_PHASE_TYPE_START) {
|
|
for (i = 0; i < ops->size; i++)
|
|
phase_tmp |= dts[i + MTK_LCM_DATA_OFFSET];
|
|
|
|
if ((phase_tmp & phase) != phase)
|
|
phase_skip_flag = MTK_LCM_PHASE_TYPE_END;
|
|
} else if (curr_status == MTK_LCM_PHASE_TYPE_END) {
|
|
phase_skip_flag = 0;
|
|
}
|
|
|
|
return phase_skip_flag;
|
|
}
|
|
|
|
u8 table_dts_buf[MTK_PANEL_TABLE_OPS_COUNT * 1024];
|
|
int parse_lcm_ops_func(struct device_node *np,
|
|
struct mtk_lcm_ops_table *table, char *func,
|
|
unsigned int panel_type,
|
|
struct mtk_panel_cust *cust, unsigned int phase)
|
|
{
|
|
unsigned int i = 0, skip_count = 0;
|
|
u8 *tmp;
|
|
int len = 0, tmp_len = 0, ret = 0;
|
|
int phase_skip_flag = 0;
|
|
struct mtk_lcm_ops_data *op = NULL;
|
|
|
|
if (IS_ERR_OR_NULL(func) ||
|
|
IS_ERR_OR_NULL(table) ||
|
|
panel_type >= MTK_LCM_FUNC_END) {
|
|
DDPMSG("%s:%d: invalid parameters\n", __func__, __LINE__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
memset(table_dts_buf, 0, sizeof(table_dts_buf));
|
|
len = mtk_lcm_dts_read_u8_array(np,
|
|
func, &table_dts_buf[0], 0, sizeof(table_dts_buf));
|
|
if (len == 0) {
|
|
return 0;
|
|
} else if (len < 0) {
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("%s, failed to get table dts, len:%d\n",
|
|
__func__, len);
|
|
#endif
|
|
return 0;
|
|
} else if ((unsigned int)len < sizeof(table_dts_buf)) {
|
|
table_dts_buf[len] = '\0';
|
|
DDPINFO("%s: start to parse:%s, dts_len:%d, phase:0x%x\n",
|
|
__func__, func, len, phase);
|
|
} else {
|
|
table_dts_buf[sizeof(table_dts_buf) - 1] = '\0';
|
|
DDPMSG("%s: start to parse:%s, len:%d has out of size:%lu\n",
|
|
__func__, func, len, sizeof(table_dts_buf));
|
|
len = sizeof(table_dts_buf);
|
|
}
|
|
|
|
INIT_LIST_HEAD(&table->list);
|
|
tmp = &table_dts_buf[0];
|
|
while (len > MTK_LCM_DATA_OFFSET) {
|
|
LCM_KZALLOC(op, sizeof(struct mtk_lcm_ops_data), GFP_KERNEL);
|
|
if (op == NULL) {
|
|
DDPPR_ERR("%s, %d, failed to allocate op\n", __func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
op->func = panel_type;
|
|
op->type = tmp[0];
|
|
if (op->type == MTK_LCM_TYPE_END) {
|
|
DDPINFO("%s: parsing end of %s, len:%d\n", __func__, func, len);
|
|
LCM_KFREE(op, sizeof(struct mtk_lcm_ops_data));
|
|
len = 0;
|
|
break;
|
|
}
|
|
|
|
op->size = tmp[1];
|
|
tmp_len = MTK_LCM_DATA_OFFSET + op->size;
|
|
phase_skip_flag = parse_lcm_ops_check(op,
|
|
tmp, len, phase_skip_flag, phase);
|
|
|
|
if (phase_skip_flag == 0 &&
|
|
op->type != MTK_LCM_PHASE_TYPE_START &&
|
|
op->type != MTK_LCM_PHASE_TYPE_END) {
|
|
ret = parse_lcm_ops_basic(op, tmp, cust, len);
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG(
|
|
"[%s+%d] >>>func:%u,type:%u,size:%u,dts:%u,op:%u,ret:%d,phase:0x%x,skip:%d\n",
|
|
func, i, op->func, op->type,
|
|
op->size, len, tmp_len, ret,
|
|
phase, phase_skip_flag);
|
|
#endif
|
|
if (ret < 0) {
|
|
DDPMSG("[%s+%d] >>>func:%u,type:%u,size:%u,dts:%u,fail:%d\n",
|
|
func, i, op->func, op->type,
|
|
op->size, len, ret);
|
|
LCM_KFREE(op, sizeof(struct mtk_lcm_ops_data));
|
|
return ret;
|
|
}
|
|
list_add_tail(&op->node, &table->list);
|
|
table->size++;
|
|
} else {
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("[%s+%d] >>>func:%u,type:%u skipped:0x%x,phase:0x%x\n",
|
|
func, i, op->func, op->type,
|
|
phase_skip_flag, phase);
|
|
#endif
|
|
LCM_KFREE(op, sizeof(struct mtk_lcm_ops_data));
|
|
skip_count++;
|
|
}
|
|
|
|
if (tmp_len <= len) {
|
|
tmp = tmp + tmp_len;
|
|
len = len - tmp_len;
|
|
} else {
|
|
DDPMSG("%s: parsing warning of %s, len:%d, tmp:%d\n",
|
|
__func__, func, len, tmp_len);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (len >= MTK_LCM_DATA_OFFSET)
|
|
DDPMSG("%s:%d: %s, total:%u,parsing:%u,skip:%u,last_dts:%u,last_ops%u\n",
|
|
__func__, __LINE__, func, i, table->size,
|
|
skip_count, len, tmp_len);
|
|
|
|
return table->size;
|
|
}
|
|
EXPORT_SYMBOL(parse_lcm_ops_func);
|
|
|
|
static int parse_lcm_ops_dt_node(struct device_node *np,
|
|
struct mtk_lcm_ops *ops, struct mtk_lcm_params *params,
|
|
struct mtk_panel_cust *cust)
|
|
{
|
|
struct device_node *type_np = NULL;
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(ops) ||
|
|
IS_ERR_OR_NULL(params) ||
|
|
IS_ERR_OR_NULL(np)) {
|
|
DDPPR_ERR("%s: invalid lcm ops\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
//DDPMSG("%s ++\n", __func__);
|
|
switch (params->type) {
|
|
case MTK_LCM_FUNC_DBI:
|
|
for_each_available_child_of_node(np, type_np) {
|
|
if (of_device_is_compatible(type_np,
|
|
"mediatek,lcm-ops-dbi")) {
|
|
LCM_KZALLOC(ops->dbi_ops,
|
|
sizeof(struct mtk_lcm_ops_dbi), GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(ops->dbi_ops)) {
|
|
DDPMSG("%s, %d, failed\n", __func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
DDPMSG("%s, LCM parse dbi params\n", __func__);
|
|
ret = parse_lcm_ops_dbi(type_np,
|
|
ops->dbi_ops, ¶ms->dbi_params, cust);
|
|
if (ret >= 0)
|
|
dump_lcm_ops_dbi(ops->dbi_ops, ¶ms->dbi_params, NULL);
|
|
}
|
|
}
|
|
break;
|
|
case MTK_LCM_FUNC_DPI:
|
|
for_each_available_child_of_node(np, type_np) {
|
|
if (of_device_is_compatible(type_np,
|
|
"mediatek,lcm-ops-dpi")) {
|
|
LCM_KZALLOC(ops->dpi_ops,
|
|
sizeof(struct mtk_lcm_ops_dpi), GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(ops->dpi_ops)) {
|
|
DDPMSG("%s, %d, failed\n", __func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
DDPMSG("%s, LCM parse dpi params\n", __func__);
|
|
ret = parse_lcm_ops_dpi(type_np,
|
|
ops->dpi_ops, ¶ms->dpi_params, cust);
|
|
if (ret >= 0)
|
|
dump_lcm_ops_dpi(ops->dpi_ops, ¶ms->dpi_params, NULL);
|
|
}
|
|
}
|
|
break;
|
|
case MTK_LCM_FUNC_DSI:
|
|
for_each_available_child_of_node(np, type_np) {
|
|
if (of_device_is_compatible(type_np,
|
|
"mediatek,lcm-ops-dsi")) {
|
|
LCM_KZALLOC(ops->dsi_ops,
|
|
sizeof(struct mtk_lcm_ops_dsi), GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(ops->dsi_ops)) {
|
|
DDPMSG("%s, %d, failed\n", __func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
ret = parse_lcm_ops_dsi(type_np,
|
|
ops->dsi_ops, ¶ms->dsi_params, cust);
|
|
if (ret >= 0)
|
|
dump_lcm_ops_dsi(ops->dsi_ops, ¶ms->dsi_params, NULL);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DDPPR_ERR("%s, invalid lcm type:%d\n",
|
|
__func__, params->type);
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
DDPMSG("%s -- ret:%d\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
int load_panel_resource_from_dts(struct device_node *lcm_np,
|
|
struct mtk_panel_resource *data)
|
|
{
|
|
struct device_node *np = NULL;
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(lcm_np) || IS_ERR_OR_NULL(data)) {
|
|
DDPPR_ERR("%s:%d: invalid lcm node\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mtk_lcm_dts_read_u32(lcm_np, "lcm-version", &data->version);
|
|
|
|
/* Load LCM parameters from DT */
|
|
for_each_available_child_of_node(lcm_np, np) {
|
|
if (of_device_is_compatible(np, "mediatek,lcm-params")) {
|
|
ret = parse_lcm_params_dt_node(np, &data->params);
|
|
if (ret < 0)
|
|
return ret;
|
|
DDPMSG("%s: parsing lcm-params, total_size:%lluByte\n",
|
|
__func__, mtk_lcm_total_size);
|
|
|
|
if (atomic_read(&data->cust.cust_enabled) == 1 &&
|
|
data->cust.parse_params != NULL) {
|
|
DDPMSG("%s: parsing cust settings, enable:%d, func:0x%lx\n",
|
|
__func__, atomic_read(&data->cust.cust_enabled),
|
|
(unsigned long)data->cust.parse_params);
|
|
ret = data->cust.parse_params(np);
|
|
if (ret < 0)
|
|
DDPMSG("%s, failed at cust parsing, %d\n",
|
|
__func__, ret);
|
|
DDPMSG("%s: parsing lcm-params-cust, total_size:%lluByte\n",
|
|
__func__, mtk_lcm_total_size);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Load LCM ops from DT */
|
|
for_each_available_child_of_node(lcm_np, np) {
|
|
if (of_device_is_compatible(np, "mediatek,lcm-ops")) {
|
|
ret = parse_lcm_ops_dt_node(np, &data->ops,
|
|
&data->params, &data->cust);
|
|
if (ret < 0) {
|
|
DDPMSG("%s, failed to parse operations, %d\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
DDPMSG("%s: parsing lcm-ops, total_size:%lluByte\n",
|
|
__func__, mtk_lcm_total_size);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(load_panel_resource_from_dts);
|
|
|
|
static void mtk_get_func_name(char func, char *out)
|
|
{
|
|
char name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(out)) {
|
|
DDPMSG("%s: invalid out buffer\n", __func__);
|
|
return;
|
|
}
|
|
|
|
switch (func) {
|
|
case MTK_LCM_FUNC_DBI:
|
|
ret = snprintf(&name[0], MTK_LCM_NAME_LENGTH - 1, "DBI");
|
|
break;
|
|
case MTK_LCM_FUNC_DPI:
|
|
ret = snprintf(&name[0], MTK_LCM_NAME_LENGTH - 1, "DPI");
|
|
break;
|
|
case MTK_LCM_FUNC_DSI:
|
|
ret = snprintf(&name[0], MTK_LCM_NAME_LENGTH - 1, "DSI");
|
|
break;
|
|
default:
|
|
ret = snprintf(&name[0], MTK_LCM_NAME_LENGTH - 1, "unknown");
|
|
break;
|
|
}
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, %d, snprintf failed\n", __func__, __LINE__);
|
|
|
|
ret = snprintf(out, MTK_LCM_NAME_LENGTH - 1, &name[0]);
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, %d, snprintf failed\n", __func__, __LINE__);
|
|
}
|
|
|
|
static void mtk_get_type_name(unsigned int type, char *out)
|
|
{
|
|
char name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(out)) {
|
|
DDPMSG("%s: invalid out buffer\n", __func__);
|
|
return;
|
|
}
|
|
|
|
switch (type) {
|
|
case MTK_LCM_UTIL_TYPE_RESET:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "RESET");
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_MDELAY:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "MDELAY");
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_UDELAY:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "UDELAY");
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_TDELAY:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "TICK_DELAY");
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_VOLTAGE:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "POWER_VOLTAGE");
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_ON:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "POWER_ON");
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_OFF:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "POWER_OFF");
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "WRITE_BUF");
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_CONDITION:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "WRITE_BUF_CON");
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_RUNTIME_INPUT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "WRITE_BUF_RUNTIME");
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_CMD:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "WRITE_CMD");
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_BUFFER:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "READ_BUF");
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_CMD:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "READ_CMD");
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "CB_RUNTIME");
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "CB_RUNTIME_INOUT");
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT_MULTIPLE:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "CB_RUNTIME_INOUT_MUL");
|
|
break;
|
|
case MTK_LCM_GPIO_TYPE_MODE:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "GPIO_MODE");
|
|
break;
|
|
case MTK_LCM_GPIO_TYPE_DIR_OUTPUT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "GPIO_DIR_OUT");
|
|
break;
|
|
case MTK_LCM_GPIO_TYPE_DIR_INPUT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "GPIO_DIR_IN");
|
|
break;
|
|
case MTK_LCM_GPIO_TYPE_OUT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "GPIO_OUT");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_COUNT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_COUNT");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_PARAM");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_FIX_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_FIX");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_X0_MSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_X0_MSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_X0_LSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_X0_LSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_X1_MSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_X1_MSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_X1_LSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_X1_LSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_Y0_MSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_Y0_MSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_Y0_LSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_Y0_LSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_Y1_MSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_Y1_MSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_PREPARE_PARAM_Y1_LSB_BIT:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_PREPARE_Y1_LSB");
|
|
break;
|
|
case MTK_LCM_LK_TYPE_WRITE_PARAM:
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1, "LK_WRITE_PARAM");
|
|
break;
|
|
default:
|
|
if (type > MTK_LCM_CUST_TYPE_START &&
|
|
type < MTK_LCM_CUST_TYPE_END)
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1,
|
|
"CUST-%d", type);
|
|
ret = snprintf(name, MTK_LCM_NAME_LENGTH - 1,
|
|
"unknown");
|
|
break;
|
|
}
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, %d, snprintf failed\n", __func__, __LINE__);
|
|
|
|
ret = snprintf(out, MTK_LCM_NAME_LENGTH - 1, &name[0]);
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, %d, snprintf failed\n", __func__, __LINE__);
|
|
}
|
|
|
|
static void dump_lcm_ops_func_util(struct mtk_lcm_ops_data *lcm_op,
|
|
const char *owner, unsigned int id)
|
|
{
|
|
char func_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
char type_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op) || IS_ERR_OR_NULL(owner))
|
|
return;
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_UTIL_TYPE_RESET:
|
|
case MTK_LCM_UTIL_TYPE_MDELAY:
|
|
case MTK_LCM_UTIL_TYPE_UDELAY:
|
|
case MTK_LCM_UTIL_TYPE_POWER_VOLTAGE:
|
|
mtk_get_func_name(lcm_op->func, &func_name[0]);
|
|
mtk_get_type_name(lcm_op->type, &type_name[0]);
|
|
DDPDUMP("[%s-%u]: func:%s, type:%s, dts_size:%u, data:%u\n",
|
|
owner, id, func_name, type_name,
|
|
lcm_op->size, lcm_op->param.util_data);
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_ON:
|
|
case MTK_LCM_UTIL_TYPE_POWER_OFF:
|
|
break;
|
|
default:
|
|
DDPDUMP("%s: [%s-%u]: invalid type:%u\n",
|
|
__func__, owner, id, lcm_op->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void dump_lcm_ops_func_cmd(struct mtk_lcm_ops_data *lcm_op,
|
|
const char *owner, unsigned int id)
|
|
{
|
|
char func_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
char type_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
unsigned int i = 0;
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op) || IS_ERR_OR_NULL(owner))
|
|
return;
|
|
|
|
mtk_get_func_name(lcm_op->func, &func_name[0]);
|
|
mtk_get_type_name(lcm_op->type, &type_name[0]);
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER:
|
|
DDPDUMP("[%s-%u]: func:%s, type:%s, dts_size:%u, para_count:%u\n",
|
|
owner, id, func_name, type_name,
|
|
lcm_op->size,
|
|
lcm_op->size);
|
|
for (i = 0; i < lcm_op->size; i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.buffer_data[i],
|
|
lcm_op->param.buffer_data[i + 1],
|
|
lcm_op->param.buffer_data[i + 2],
|
|
lcm_op->param.buffer_data[i + 3]);
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_CONDITION:
|
|
DDPDUMP("[%s-%u]:%s,%s,name:0x%x,con:0x%x,dts_size:%u,para_count:%u\n",
|
|
owner, id, func_name, type_name,
|
|
lcm_op->param.buf_con_data.name,
|
|
lcm_op->param.buf_con_data.condition,
|
|
lcm_op->size,
|
|
(unsigned int)lcm_op->param.buf_con_data.data_len);
|
|
for (i = 0; i < (unsigned int)lcm_op->param.buf_con_data.data_len; i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.buf_con_data.data[i],
|
|
lcm_op->param.buf_con_data.data[i + 1],
|
|
lcm_op->param.buf_con_data.data[i + 2],
|
|
lcm_op->param.buf_con_data.data[i + 3]);
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_RUNTIME_INPUT:
|
|
DDPDUMP("[%s-%u]:%s,%s,name:0x%x,id:0x%x,dts_size:%u,para_count:%u\n",
|
|
owner, id, func_name, type_name,
|
|
lcm_op->param.buf_runtime_data.name,
|
|
lcm_op->param.buf_runtime_data.id,
|
|
lcm_op->size,
|
|
(unsigned int)lcm_op->param.buf_runtime_data.data_len);
|
|
for (i = 0; i < (unsigned int)lcm_op->param.buf_runtime_data.data_len; i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.buf_runtime_data.data[i],
|
|
lcm_op->param.buf_runtime_data.data[i + 1],
|
|
lcm_op->param.buf_runtime_data.data[i + 2],
|
|
lcm_op->param.buf_runtime_data.data[i + 3]);
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_CMD:
|
|
DDPDUMP("[%s-%u]:%s,%s,dts:%u,cmd:0x%x,data_len:%u,startid:%u\n",
|
|
owner, id, func_name, type_name, lcm_op->size,
|
|
lcm_op->param.cmd_data.cmd,
|
|
(unsigned int)lcm_op->param.cmd_data.data_len,
|
|
lcm_op->param.cmd_data.start_id);
|
|
for (i = 0; i < (unsigned int)lcm_op->param.cmd_data.data_len; i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.cmd_data.data[i],
|
|
lcm_op->param.cmd_data.data[i + 1],
|
|
lcm_op->param.cmd_data.data[i + 2],
|
|
lcm_op->param.cmd_data.data[i + 3]);
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_BUFFER:
|
|
DDPDUMP("[%s-%u]:%s,%s,dts:%u,data_len:%u,startid:%u\n",
|
|
owner, id, func_name, type_name, lcm_op->size,
|
|
(unsigned int)lcm_op->param.cmd_data.data_len,
|
|
lcm_op->param.cmd_data.start_id);
|
|
for (i = 0; i < (unsigned int)lcm_op->param.cmd_data.data_len; i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.cmd_data.data[i],
|
|
lcm_op->param.cmd_data.data[i + 1],
|
|
lcm_op->param.cmd_data.data[i + 2],
|
|
lcm_op->param.cmd_data.data[i + 3]);
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_CMD:
|
|
DDPDUMP("[%s-%u]:%s,%s,dts:%u,cmd:0x%x,data_len:%u,startid:%u\n",
|
|
owner, id, func_name, type_name, lcm_op->size,
|
|
lcm_op->param.cmd_data.cmd,
|
|
(unsigned int)lcm_op->param.cmd_data.data_len,
|
|
lcm_op->param.cmd_data.start_id);
|
|
break;
|
|
default:
|
|
DDPDUMP("%s: [%s-%u]: invalid type:%u\n",
|
|
__func__, owner, id, lcm_op->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void dump_lcm_ops_func_cb(struct mtk_lcm_ops_data *lcm_op,
|
|
const char *owner, unsigned int id)
|
|
{
|
|
char func_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
char type_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
unsigned int i = 0;
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op) || IS_ERR_OR_NULL(owner))
|
|
return;
|
|
|
|
mtk_get_func_name(lcm_op->func, &func_name[0]);
|
|
mtk_get_type_name(lcm_op->type, &type_name[0]);
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_CB_TYPE_RUNTIME:
|
|
DDPDUMP("[%s-%u]: func:%s, type:%s, dts_size:%u\n",
|
|
owner, id, func_name, type_name, lcm_op->size);
|
|
for (i = 0; i < roundup(lcm_op->size, 4); i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.cb_id_data.buffer_data[i],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 1],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 2],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 3]);
|
|
}
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT:
|
|
DDPDUMP("[%s-%u]: func:%s, type:%s, dts_size:%u, id:%u\n",
|
|
owner, id, func_name, type_name,
|
|
lcm_op->size, lcm_op->param.cb_id_data.id[0]);
|
|
for (i = 0; i < roundup(lcm_op->size - 1, 4); i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.cb_id_data.buffer_data[i],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 1],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 2],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 3]);
|
|
}
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT_MULTIPLE:
|
|
DDPDUMP("[%s-%u]: func:%s, type:%s, dts_size:%u, id_count:%u, data_count:%u\n",
|
|
owner, id, func_name, type_name,
|
|
lcm_op->size, lcm_op->param.cb_id_data.id_count,
|
|
lcm_op->param.cb_id_data.data_count);
|
|
for (i = 0; i < roundup(lcm_op->param.cb_id_data.id_count, 4); i += 4) {
|
|
DDPDUMP("[%s-%u][input_id%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.cb_id_data.id[i],
|
|
lcm_op->param.cb_id_data.id[i + 1],
|
|
lcm_op->param.cb_id_data.id[i + 2],
|
|
lcm_op->param.cb_id_data.id[i + 3]);
|
|
}
|
|
for (i = 0; i < roundup(lcm_op->param.cb_id_data.data_count, 4); i += 4) {
|
|
DDPDUMP("[%s-%u][data%u~%u]>>> 0x%x 0x%x 0x%x 0x%x\n",
|
|
owner, id, i, i + 3,
|
|
lcm_op->param.cb_id_data.buffer_data[i],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 1],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 2],
|
|
lcm_op->param.cb_id_data.buffer_data[i + 3]);
|
|
}
|
|
break;
|
|
default:
|
|
DDPDUMP("%s: [%s-%u]: invalid type:%u\n",
|
|
__func__, owner, id, lcm_op->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void dump_lcm_ops_func_gpio(struct mtk_lcm_ops_data *lcm_op,
|
|
const char *owner, unsigned int id)
|
|
{
|
|
char func_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
char type_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op) || IS_ERR_OR_NULL(owner))
|
|
return;
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_GPIO_TYPE_MODE:
|
|
case MTK_LCM_GPIO_TYPE_DIR_OUTPUT:
|
|
case MTK_LCM_GPIO_TYPE_DIR_INPUT:
|
|
case MTK_LCM_GPIO_TYPE_OUT:
|
|
mtk_get_func_name(lcm_op->func, &func_name[0]);
|
|
mtk_get_type_name(lcm_op->type, &type_name[0]);
|
|
DDPDUMP("[%s-%u]: func:%s, type:%s, dts_size:%u, gpio:%u, data:0x%x\n",
|
|
owner, id, func_name, type_name, lcm_op->size,
|
|
lcm_op->param.gpio_data.gpio_id,
|
|
lcm_op->param.gpio_data.data);
|
|
break;
|
|
default:
|
|
DDPDUMP("[%s-%u]: invalid type:%u\n",
|
|
owner, id, lcm_op->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void dump_lcm_ops_func(struct mtk_lcm_ops_table *table,
|
|
struct mtk_panel_cust *cust,
|
|
const char *owner)
|
|
{
|
|
struct mtk_lcm_ops_data *lcm_op = NULL;
|
|
char owner_tmp[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
unsigned int i = 0;
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(owner))
|
|
ret = snprintf(&owner_tmp[0], MTK_LCM_NAME_LENGTH - 1, "unknown");
|
|
else
|
|
ret = snprintf(&owner_tmp[0], MTK_LCM_NAME_LENGTH - 1, owner);
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, %d, snprintf failed\n", __func__, __LINE__);
|
|
|
|
if (IS_ERR_OR_NULL(table) || table->size == 0) {
|
|
DDPDUMP("%s: \"%s\" is empty\n", __func__, owner_tmp);
|
|
return;
|
|
}
|
|
|
|
DDPDUMP("-------------%s(%u): 0x%lx-----------\n",
|
|
owner_tmp, table->size, (unsigned long)table);
|
|
list_for_each_entry(lcm_op, &table->list, node) {
|
|
if (lcm_op->type > MTK_LCM_UTIL_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_UTIL_TYPE_END)
|
|
dump_lcm_ops_func_util(lcm_op, owner_tmp, i);
|
|
else if (lcm_op->type > MTK_LCM_CMD_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_CMD_TYPE_END)
|
|
dump_lcm_ops_func_cmd(lcm_op, owner_tmp, i);
|
|
else if (lcm_op->type > MTK_LCM_CB_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_CB_TYPE_END)
|
|
dump_lcm_ops_func_cb(lcm_op, owner_tmp, i);
|
|
else if (lcm_op->type > MTK_LCM_GPIO_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_GPIO_TYPE_END)
|
|
dump_lcm_ops_func_gpio(lcm_op, owner_tmp, i);
|
|
else if (lcm_op->type > MTK_LCM_CUST_TYPE_START &&
|
|
lcm_op->type < MTK_LCM_CUST_TYPE_END) {
|
|
if (cust != NULL &&
|
|
atomic_read(&cust->cust_enabled) != 0 &&
|
|
cust->dump_ops != NULL)
|
|
cust->dump_ops(lcm_op, owner, i);
|
|
} else
|
|
DDPDUMP("[%s-%d]: invalid func:%u\n",
|
|
owner, i, lcm_op->func);
|
|
i++;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(dump_lcm_ops_func);
|
|
|
|
int mtk_lcm_create_input_packet(struct mtk_lcm_ops_input_packet *input,
|
|
unsigned int data_count, unsigned int condition_count)
|
|
{
|
|
if (IS_ERR_OR_NULL(input))
|
|
return -EINVAL;
|
|
|
|
if (condition_count > 0) {
|
|
LCM_KZALLOC(input->condition,
|
|
sizeof(struct mtk_lcm_ops_input) *
|
|
condition_count, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(input->condition)) {
|
|
DDPMSG("%s, %d, failed to allocate condition\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
} else {
|
|
input->condition = NULL;
|
|
}
|
|
input->condition_count = condition_count;
|
|
|
|
if (data_count > 0) {
|
|
LCM_KZALLOC(input->data,
|
|
sizeof(struct mtk_lcm_ops_input) *
|
|
data_count, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(input->data)) {
|
|
DDPMSG("%s, %d, failed to allocate data\n",
|
|
__func__, __LINE__);
|
|
if (condition_count > 0) {
|
|
LCM_KFREE(input->condition,
|
|
sizeof(struct mtk_lcm_ops_input) *
|
|
condition_count);
|
|
input->condition_count = 0;
|
|
}
|
|
return -ENOMEM;
|
|
}
|
|
} else {
|
|
input->data = NULL;
|
|
}
|
|
input->data_count = data_count;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mtk_lcm_create_input_packet);
|
|
|
|
void mtk_lcm_destroy_input_packet(struct mtk_lcm_ops_input_packet *input)
|
|
{
|
|
if (IS_ERR_OR_NULL(input))
|
|
return;
|
|
|
|
if (input->data_count > 0) {
|
|
if (input->data != NULL)
|
|
LCM_KFREE(input->data,
|
|
sizeof(struct mtk_lcm_ops_input) *
|
|
input->data_count);
|
|
input->data = NULL;
|
|
input->data_count = 0;
|
|
}
|
|
|
|
if (input->condition_count > 0) {
|
|
if (input->condition != NULL)
|
|
LCM_KFREE(input->condition,
|
|
sizeof(struct mtk_lcm_ops_input) *
|
|
input->condition_count);
|
|
input->condition = NULL;
|
|
input->condition_count = 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(mtk_lcm_destroy_input_packet);
|
|
|
|
int mtk_lcm_create_input(struct mtk_lcm_ops_input *input,
|
|
unsigned int data_len, u8 name)
|
|
{
|
|
if (IS_ERR_OR_NULL(input) || data_len == 0)
|
|
return -EINVAL;
|
|
|
|
LCM_KZALLOC(input->data, data_len, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(input->data)) {
|
|
DDPMSG("%s, %d, failed to allocate input data\n",
|
|
__func__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
input->length = data_len;
|
|
input->name = name;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mtk_lcm_create_input);
|
|
|
|
void mtk_lcm_destroy_input(struct mtk_lcm_ops_input *input)
|
|
{
|
|
if (IS_ERR_OR_NULL(input) || input->length == 0)
|
|
return;
|
|
|
|
LCM_KFREE(input->data, input->length);
|
|
input->data = NULL;
|
|
input->length = 0;
|
|
}
|
|
EXPORT_SYMBOL(mtk_lcm_destroy_input);
|
|
|
|
static inline int mtk_lcm_get_input_data(
|
|
struct mtk_lcm_ops_input_packet *input,
|
|
unsigned int name)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < input->data_count; i++) {
|
|
if (input->data[i].name == name) {
|
|
if (IS_ERR_OR_NULL(input->data[i].data))
|
|
return -EINVAL;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -EFAULT;
|
|
}
|
|
|
|
static inline int mtk_lcm_get_input_condition(
|
|
struct mtk_lcm_ops_input_packet *input,
|
|
unsigned int name)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < input->condition_count; i++) {
|
|
if (input->condition[i].name == name) {
|
|
if (IS_ERR_OR_NULL(input->condition[i].data))
|
|
return -EINVAL;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -EFAULT;
|
|
}
|
|
|
|
static int mtk_lcm_create_operation_group(struct mtk_panel_para_table *group,
|
|
u8 *input_data, unsigned int input_count,
|
|
struct mtk_lcm_ops_table *table)
|
|
{
|
|
struct mtk_lcm_ops_data *op = NULL;
|
|
size_t size = 0, count = 0;
|
|
u8 *data = NULL;
|
|
unsigned int id = 0, j = 0, index = 0;
|
|
|
|
if (IS_ERR_OR_NULL(group)) {
|
|
DDPMSG("%s, %d, invalid group\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
if (IS_ERR_OR_NULL(table) ||
|
|
table->size == 0 || table->size >= MTK_PANEL_TABLE_OPS_COUNT) {
|
|
DDPMSG("%s, %d, invalid table\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
list_for_each_entry(op, &table->list, node) {
|
|
count = op->param.cb_id_data.id_count;
|
|
data = op->param.cb_id_data.buffer_data;
|
|
size = op->param.cb_id_data.data_count;
|
|
if (size > ARRAY_SIZE(group[id].para_list)) {
|
|
DDPPR_ERR("%s: invalid size:%lu\n",
|
|
__func__, size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (op->type) {
|
|
case MTK_LCM_CB_TYPE_RUNTIME:
|
|
group[id].count = size;
|
|
memcpy(group[id].para_list, data, size);
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT:
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT_MULTIPLE:
|
|
if (count == 0) {
|
|
DDPPR_ERR("%s:invalid func:%u of count:%lu\n",
|
|
__func__, op->type, count);
|
|
break;
|
|
} else if (count != input_count) {
|
|
DDPMSG("%s, %d, invalid count:%lu, expect:%u\n",
|
|
__func__, __LINE__, count, input_count);
|
|
break;
|
|
} else if (IS_ERR_OR_NULL(input_data)) {
|
|
DDPMSG("%s, %d, invalid data\n", __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
group[id].count = size;
|
|
memcpy(group[id].para_list, data, size);
|
|
for (j = 0; j < count; j++) {
|
|
index = op->param.cb_id_data.id[j];
|
|
if (index >= size) {
|
|
DDPPR_ERR("%s:invalid id:%u of table:%u\n",
|
|
__func__, index, size);
|
|
return -EINVAL;
|
|
}
|
|
group[id].para_list[index] &= input_data[j];
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("%s, %d, j:%u, index:%u, para:0x%x\n",
|
|
__func__, __LINE__, j, index,
|
|
group[id].para_list[index]);
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
DDPMSG("%s: invalid cmd:%u\n", __func__, op->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mtk_panel_execute_callback(void *dsi, dcs_write_gce cb,
|
|
void *handle, u8 *input_data, unsigned int input_count,
|
|
struct mtk_lcm_ops_table *table, const char *master)
|
|
{
|
|
u8 *data = NULL;
|
|
struct mtk_lcm_ops_data *op = NULL;
|
|
unsigned int id = -1, j = 0;
|
|
size_t size = 0, count = 0;
|
|
unsigned int *mask = NULL;
|
|
char owner[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(table) ||
|
|
table->size == 0 || table->size >= MTK_PANEL_TABLE_OPS_COUNT) {
|
|
DDPMSG("%s, %d, invalid table\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (IS_ERR_OR_NULL(master))
|
|
ret = snprintf(owner, MTK_LCM_NAME_LENGTH - 1, "unknown");
|
|
else
|
|
ret = snprintf(owner, MTK_LCM_NAME_LENGTH - 1, master);
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, failed at snprintf, %d", __func__, ret);
|
|
ret = 0;
|
|
|
|
if (input_count > 0) {
|
|
LCM_KZALLOC(mask, input_count, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(mask)) {
|
|
DDPPR_ERR("%s:failed to allocate mask buffer, count:%u\n",
|
|
__func__, input_count);
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
list_for_each_entry(op, &table->list, node) {
|
|
count = op->param.cb_id_data.id_count;
|
|
data = op->param.cb_id_data.buffer_data;
|
|
size = op->param.cb_id_data.data_count;
|
|
switch (op->type) {
|
|
case MTK_LCM_CB_TYPE_RUNTIME:
|
|
cb(dsi, handle, data, size);
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT:
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT_MULTIPLE:
|
|
if (count == 0) {
|
|
DDPPR_ERR("%s:invalid func:%u of count:%lu\n",
|
|
__func__, op->type, count);
|
|
break;
|
|
} else if (count != input_count) {
|
|
DDPMSG("%s, %d, func:%s, invalid count:%lu, expect:%u\n",
|
|
__func__, __LINE__, owner, count, input_count);
|
|
cb(dsi, handle, data, size);
|
|
break;
|
|
} else if (IS_ERR_OR_NULL(input_data)) {
|
|
DDPMSG("%s, %d, func:%s, invalid data\n",
|
|
__func__, __LINE__, owner);
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
for (j = 0; j < count; j++) {
|
|
id = op->param.cb_id_data.id[j];
|
|
if (id >= size) {
|
|
DDPPR_ERR("%s: func:%s, invalid id:%u of table:%lu\n",
|
|
__func__, owner, id, size);
|
|
LCM_KFREE(mask, count);
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
if (!mask) {
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
mask[j] = data[id]; //backup backlight mask
|
|
data[id] &= input_data[j];
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("%s, %d, i:%u, mask:0x%x, data:0x%x, id:%u\n",
|
|
__func__, __LINE__, j, mask[j], data[id], id);
|
|
#endif
|
|
}
|
|
|
|
cb(dsi, handle, data, size);
|
|
|
|
/* restore backlight mask*/
|
|
for (j = 0; j < count; j++) {
|
|
id = op->param.cb_id_data.id[j];
|
|
if (id >= size)
|
|
continue;
|
|
data[id] = mask[j];
|
|
}
|
|
break;
|
|
default:
|
|
DDPMSG("%s: func:%s, invalid cmd:%u\n",
|
|
__func__, owner, op->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("%s, %d, func:%s, count:%u, ret:%d\n",
|
|
__func__, __LINE__, owner, input_count, ret);
|
|
#endif
|
|
if (input_count > 0)
|
|
LCM_KFREE(mask, input_count);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(mtk_panel_execute_callback);
|
|
|
|
int mtk_panel_execute_callback_group(void *dsi, dcs_grp_write_gce cb,
|
|
void *handle, u8 *input_data, unsigned int input_count,
|
|
struct mtk_lcm_ops_table *table, const char *master)
|
|
{
|
|
struct mtk_panel_para_table *group = NULL;
|
|
char owner[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(table) ||
|
|
table->size == 0 || table->size >= MTK_PANEL_TABLE_OPS_COUNT) {
|
|
DDPMSG("%s, %d, invalid table\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (IS_ERR_OR_NULL(master))
|
|
ret = snprintf(owner, MTK_LCM_NAME_LENGTH - 1, "unknown");
|
|
else
|
|
ret = snprintf(owner, MTK_LCM_NAME_LENGTH - 1, master);
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, failed at snprintf, %d", __func__, ret);
|
|
ret = 0;
|
|
|
|
LCM_KZALLOC(group, sizeof(struct mtk_panel_para_table) *
|
|
table->size, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(group)) {
|
|
DDPPR_ERR("%s:failed to allocate group, count:%u\n",
|
|
__func__, table->size);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = mtk_lcm_create_operation_group(group,
|
|
input_data, input_count, table);
|
|
if (ret < 0) {
|
|
DDPPR_ERR("%s:failed to create group, ret:%d\n",
|
|
__func__, ret);
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
cb(dsi, handle, group, table->size);
|
|
|
|
out:
|
|
LCM_KFREE(group, sizeof(struct mtk_panel_para_table) *
|
|
table->size);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(mtk_panel_execute_callback_group);
|
|
|
|
int mtk_execute_func_cmd(void *dev,
|
|
struct mtk_lcm_ops_data *lcm_op,
|
|
struct mtk_lcm_ops_input_packet *input)
|
|
{
|
|
int ret = 0, index = 0;
|
|
unsigned int rid = 0;
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op)) {
|
|
DDPPR_ERR("%s %d: invalid cmd\n", __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER:
|
|
if (IS_ERR_OR_NULL(lcm_op->param.buffer_data) ||
|
|
lcm_op->size <= 0)
|
|
return -EINVAL;
|
|
ret = mtk_panel_dsi_dcs_write_buffer(
|
|
(struct mipi_dsi_device *)dev,
|
|
lcm_op->param.buffer_data,
|
|
lcm_op->size);
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_CONDITION:
|
|
if (IS_ERR_OR_NULL(lcm_op->param.buf_con_data.data) ||
|
|
IS_ERR_OR_NULL(input) ||
|
|
IS_ERR_OR_NULL(input->condition))
|
|
return -EINVAL;
|
|
index = mtk_lcm_get_input_condition(input,
|
|
lcm_op->param.buf_con_data.name);
|
|
if (index < 0 || index >= input->condition_count) {
|
|
DDPMSG("%s, %d, failed to get input, %d\n",
|
|
__func__, __LINE__, index);
|
|
return -EINVAL;
|
|
}
|
|
if (lcm_op->param.buf_con_data.condition ==
|
|
*(u8 *)input->condition[index].data) {
|
|
DDPMSG("%s,%d, name:0x%x, condition:%u, %u\n", __func__, __LINE__,
|
|
lcm_op->param.buf_con_data.name,
|
|
lcm_op->param.buf_con_data.condition,
|
|
*(u8 *)input->condition[index].data);
|
|
ret = mtk_panel_dsi_dcs_write_buffer(
|
|
(struct mipi_dsi_device *)dev,
|
|
lcm_op->param.buf_con_data.data,
|
|
lcm_op->param.buf_con_data.data_len);
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_RUNTIME_INPUT:
|
|
if (IS_ERR_OR_NULL(lcm_op->param.buf_runtime_data.data) ||
|
|
IS_ERR_OR_NULL(input) ||
|
|
IS_ERR_OR_NULL(input->data))
|
|
return -EINVAL;
|
|
|
|
rid = lcm_op->param.buf_runtime_data.id;
|
|
index = mtk_lcm_get_input_data(input,
|
|
lcm_op->param.buf_runtime_data.name);
|
|
if (index < 0 || index >= input->data_count) {
|
|
DDPMSG("%s, %d, failed to get input, %d\n",
|
|
__func__, __LINE__, index);
|
|
return -EINVAL;
|
|
}
|
|
DDPMSG("%s,%d, name:0x%x, id:%u, value:0x%x\n", __func__, __LINE__,
|
|
lcm_op->param.buf_runtime_data.name, rid,
|
|
*(u8 *)input->data[index].data);
|
|
lcm_op->param.buf_runtime_data.data[rid] =
|
|
*(u8 *)input->data[index].data;
|
|
ret = mtk_panel_dsi_dcs_write_buffer(
|
|
(struct mipi_dsi_device *)dev,
|
|
lcm_op->param.buf_runtime_data.data,
|
|
lcm_op->param.buf_runtime_data.data_len);
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_BUFFER:
|
|
{
|
|
unsigned int offset = lcm_op->param.cmd_data.start_id;
|
|
unsigned int len = lcm_op->param.cmd_data.data_len;
|
|
|
|
if (IS_ERR_OR_NULL(input) ||
|
|
IS_ERR_OR_NULL(input->data)) {
|
|
DDPMSG("%s: err input\n", __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
index = mtk_lcm_get_input_data(input,
|
|
MTK_LCM_INPUT_TYPE_READBACK);
|
|
if (index < 0 || index >= input->data_count) {
|
|
DDPMSG("%s, %d, failed to get input, %d\n",
|
|
__func__, __LINE__, index);
|
|
return -EINVAL;
|
|
}
|
|
if (input->data[index].length < offset + len) {
|
|
DDPMSG("%s: err, data_count:%u,off:%u,len:%u\n",
|
|
__func__, input->data_count, offset, len);
|
|
return -ENOMEM;
|
|
}
|
|
ret = mtk_panel_dsi_dcs_read_buffer(
|
|
(struct mipi_dsi_device *)dev,
|
|
lcm_op->param.cmd_data.data,
|
|
lcm_op->size,
|
|
&input->data[index].data[lcm_op->param.cmd_data.start_id],
|
|
lcm_op->param.cmd_data.data_len);
|
|
break;
|
|
}
|
|
case MTK_LCM_CMD_TYPE_WRITE_CMD:
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cmd_data.data) ||
|
|
lcm_op->param.cmd_data.data_len <= 0)
|
|
return -EINVAL;
|
|
ret = mtk_panel_dsi_dcs_write(
|
|
(struct mipi_dsi_device *)dev,
|
|
lcm_op->param.cmd_data.cmd,
|
|
lcm_op->param.cmd_data.data,
|
|
lcm_op->param.cmd_data.data_len);
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_CMD:
|
|
{
|
|
unsigned int offset = lcm_op->param.cmd_data.start_id;
|
|
unsigned int len = lcm_op->param.cmd_data.data_len;
|
|
|
|
if (IS_ERR_OR_NULL(input) ||
|
|
IS_ERR_OR_NULL(input->data)) {
|
|
DDPMSG("%s: %d, err input\n", __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
index = mtk_lcm_get_input_data(input,
|
|
MTK_LCM_INPUT_TYPE_READBACK);
|
|
if (index < 0 || index >= input->data_count) {
|
|
DDPMSG("%s, %d, failed to get input, %d\n",
|
|
__func__, __LINE__, index);
|
|
return -EINVAL;
|
|
}
|
|
if (input->data[index].length < offset + len) {
|
|
DDPMSG("%s: err, data_count:%u,off:%u,len:%u\n",
|
|
__func__, input->data_count, offset, len);
|
|
return -ENOMEM;
|
|
}
|
|
LCM_KZALLOC(lcm_op->param.cmd_data.data, len + 1, GFP_KERNEL);
|
|
if (IS_ERR_OR_NULL(lcm_op->param.cmd_data.data)) {
|
|
DDPMSG("%s,%d: failed to allocate data, len:%u\n",
|
|
__func__, __LINE__, len);
|
|
return -ENOMEM;
|
|
}
|
|
ret = mtk_panel_dsi_dcs_read(
|
|
(struct mipi_dsi_device *)dev,
|
|
lcm_op->param.cmd_data.cmd,
|
|
&input->data[index].data[lcm_op->param.cmd_data.start_id],
|
|
lcm_op->param.cmd_data.data_len);
|
|
break;
|
|
}
|
|
default:
|
|
ret = -EINVAL;
|
|
DDPMSG("%s: invalid func:%u\n", __func__, lcm_op->func);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mtk_execute_func_util(struct mtk_lcm_ops_data *lcm_op)
|
|
{
|
|
unsigned int data = 0;
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op)) {
|
|
DDPPR_ERR("%s %d: invalid cmd\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
data = lcm_op->param.util_data;
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_UTIL_TYPE_RESET:
|
|
ret = mtk_drm_gateic_reset(data, lcm_op->func);
|
|
if (ret < 0)
|
|
DDPMSG("%s, reset failed, %d\n",
|
|
__func__, ret);
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_ON:
|
|
ret = mtk_drm_gateic_power_on(lcm_op->func);
|
|
if (ret < 0)
|
|
DDPMSG("%s, power on failed, %d\n",
|
|
__func__, ret);
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_OFF:
|
|
ret = mtk_drm_gateic_power_off(lcm_op->func);
|
|
if (ret < 0)
|
|
DDPMSG("%s, power off failed, %d\n",
|
|
__func__, ret);
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_POWER_VOLTAGE:
|
|
ret = mtk_drm_gateic_set_voltage(data, lcm_op->func);
|
|
if (ret < 0)
|
|
DDPMSG("%s, set voltage:%u failed, %d\n",
|
|
__func__, data, ret);
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_MDELAY:
|
|
mdelay(lcm_op->param.util_data);
|
|
break;
|
|
case MTK_LCM_UTIL_TYPE_UDELAY:
|
|
udelay(lcm_op->param.util_data);
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
DDPMSG("%s: invalid func:%u\n",
|
|
__func__, lcm_op->func);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mtk_execute_func_gpio(struct mtk_lcm_ops_data *lcm_op,
|
|
const struct device *device,
|
|
const char **lcm_pinctrl_name,
|
|
unsigned int pinctrl_count)
|
|
{
|
|
struct pinctrl *pctrl = NULL;
|
|
struct pinctrl_state *state = NULL;
|
|
struct gpio_desc *gpiod = NULL;
|
|
unsigned int id = 0, data = 0;
|
|
int ret = 0;
|
|
const char *name = NULL;
|
|
struct device dev;
|
|
|
|
if (IS_ERR_OR_NULL(lcm_op)) {
|
|
DDPPR_ERR("%s %d: invalid cmd\n",
|
|
__func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
id = lcm_op->param.gpio_data.gpio_id;
|
|
data = lcm_op->param.gpio_data.data;
|
|
if (IS_ERR_OR_NULL(lcm_pinctrl_name) ||
|
|
id >= pinctrl_count ||
|
|
IS_ERR_OR_NULL(device)) {
|
|
DDPPR_ERR("%s %d: invalid parameter:%u-%u\n",
|
|
__func__, __LINE__, id, pinctrl_count);
|
|
return -EINVAL;
|
|
}
|
|
|
|
memcpy(&dev, device, sizeof(struct device));
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_GPIO_TYPE_MODE:
|
|
name = lcm_pinctrl_name[id];
|
|
if (IS_ERR_OR_NULL(name)) {
|
|
DDPPR_ERR("%s: invalid pinctrl name:%u\n", __func__, id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pctrl = devm_pinctrl_get(&dev);
|
|
if (IS_ERR_OR_NULL(pctrl)) {
|
|
DDPPR_ERR("%s: invalid pinctrl:%u\n", __func__, id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
state = pinctrl_lookup_state(pctrl, name);
|
|
if (IS_ERR_OR_NULL(state)) {
|
|
DDPPR_ERR("%s: invalid state:%u\n", __func__, id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = pinctrl_select_state(pctrl, state);
|
|
break;
|
|
case MTK_LCM_GPIO_TYPE_DIR_OUTPUT:
|
|
gpiod = devm_gpiod_get_index(&dev,
|
|
"lcm_gpio_list", id, GPIOD_OUT_HIGH);
|
|
if (IS_ERR_OR_NULL(gpiod)) {
|
|
DDPPR_ERR("%s: invalid gpiod:%u\n", __func__, id);
|
|
return PTR_ERR(gpiod);
|
|
}
|
|
|
|
ret = gpiod_direction_output(gpiod, !!data);
|
|
devm_gpiod_put(&dev, gpiod);
|
|
break;
|
|
case MTK_LCM_GPIO_TYPE_DIR_INPUT:
|
|
gpiod = devm_gpiod_get_index(&dev,
|
|
"lcm_gpio_list", id, GPIOD_OUT_HIGH);
|
|
if (IS_ERR_OR_NULL(gpiod)) {
|
|
DDPPR_ERR("%s: invalid gpiod:%u\n", __func__, id);
|
|
return PTR_ERR(gpiod);
|
|
}
|
|
|
|
ret = gpiod_direction_input(gpiod);
|
|
devm_gpiod_put(&dev, gpiod);
|
|
break;
|
|
case MTK_LCM_GPIO_TYPE_OUT:
|
|
gpiod = devm_gpiod_get_index(&dev,
|
|
"lcm_gpio_list", id, GPIOD_OUT_HIGH);
|
|
if (IS_ERR_OR_NULL(gpiod)) {
|
|
DDPPR_ERR("%s: invalid gpiod:%u\n", __func__, id);
|
|
return PTR_ERR(gpiod);
|
|
}
|
|
|
|
gpiod_set_value(gpiod, !!data);
|
|
devm_gpiod_put(&dev, gpiod);
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
DDPMSG("%s: invalid type:%u\n",
|
|
__func__, lcm_op->type);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mtk_is_lcm_read_ops(unsigned int type)
|
|
{
|
|
if (type == MTK_LCM_CMD_TYPE_READ_CMD ||
|
|
type == MTK_LCM_CMD_TYPE_READ_BUFFER)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mtk_is_lcm_read_ops);
|
|
|
|
int mtk_panel_execute_operation(void *dev,
|
|
struct mtk_lcm_ops_table *table,
|
|
const struct mtk_panel_resource *panel_resource,
|
|
struct mtk_lcm_ops_input_packet *input,
|
|
const char *owner)
|
|
{
|
|
struct mtk_lcm_ops_data *op = NULL;
|
|
unsigned int i = 0;
|
|
char owner_tmp[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
char func_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
char type_name[MTK_LCM_NAME_LENGTH] = { 0 };
|
|
int ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(owner))
|
|
ret = snprintf(&owner_tmp[0], MTK_LCM_NAME_LENGTH - 1, "unknown");
|
|
else
|
|
ret = snprintf(&owner_tmp[0], MTK_LCM_NAME_LENGTH - 1, owner);
|
|
if (ret < 0 || ret >= MTK_LCM_NAME_LENGTH)
|
|
DDPMSG("%s, %d, snprintf failed\n", __func__, __LINE__);
|
|
ret = 0;
|
|
|
|
if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(table) ||
|
|
table->size == 0 || table->size >= MTK_PANEL_TABLE_OPS_COUNT) {
|
|
DDPINFO("%s: \"%s\" is empty, size:%u\n",
|
|
__func__, owner_tmp, table->size);
|
|
return 0;
|
|
}
|
|
|
|
list_for_each_entry(op, &table->list, node) {
|
|
if (IS_ERR_OR_NULL(op)) {
|
|
DDPMSG("%s: owner:%s, invalid op\n",
|
|
__func__, owner_tmp);
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
mtk_get_func_name(op->func, &func_name[0]);
|
|
if (op->func != MTK_LCM_FUNC_DSI) {
|
|
DDPMSG("%s, %d, not support:%s-%d\n",
|
|
__func__, __LINE__, func_name, op->func);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mtk_get_type_name(op->type, &type_name[0]);
|
|
#if MTK_LCM_DEBUG_DUMP
|
|
DDPMSG("%s: [%s+%u]: func:%s/%u, type:%s/%u\n",
|
|
__func__, owner_tmp, i,
|
|
func_name, op->func,
|
|
type_name, op->type);
|
|
#endif
|
|
|
|
if (op->type > MTK_LCM_UTIL_TYPE_START &&
|
|
op->type < MTK_LCM_UTIL_TYPE_END)
|
|
ret = mtk_execute_func_util(op);
|
|
else if (op->type > MTK_LCM_CMD_TYPE_START &&
|
|
op->type < MTK_LCM_CMD_TYPE_END)
|
|
ret = mtk_execute_func_cmd(dev, op, input);
|
|
else if (op->type > MTK_LCM_GPIO_TYPE_START &&
|
|
op->type < MTK_LCM_GPIO_TYPE_END)
|
|
mtk_execute_func_gpio(op,
|
|
&panel_resource->params.dsi_params.lcm_gpio_dev,
|
|
panel_resource->params.dsi_params.lcm_pinctrl_name,
|
|
panel_resource->params.dsi_params.lcm_pinctrl_count);
|
|
else if (op->type > MTK_LCM_CUST_TYPE_START &&
|
|
op->type < MTK_LCM_CUST_TYPE_END) {
|
|
if (atomic_read(
|
|
&panel_resource->cust.cust_enabled) == 0 ||
|
|
IS_ERR_OR_NULL(panel_resource->cust.func))
|
|
return -EINVAL;
|
|
|
|
ret = panel_resource->cust.func(op, input);
|
|
} else {
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
if (ret < 0) {
|
|
DDPMSG("%s: [%s+%u] func:%s/%u, type:%s/%u, failed:%d\n",
|
|
__func__, owner_tmp, i,
|
|
func_name, op->func,
|
|
type_name, op->type, ret);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(mtk_panel_execute_operation);
|
|
|
|
void dump_lcm_params_basic(struct mtk_lcm_params *params)
|
|
{
|
|
if (IS_ERR_OR_NULL(params)) {
|
|
DDPDUMP("%s: invalid lcm params\n", __func__);
|
|
return;
|
|
}
|
|
|
|
DDPDUMP("=========== LCM DUMP: basic params ==============\n");
|
|
DDPDUMP("lcm name=%s, type=%u, resolution=(%u,%u)\n",
|
|
params->name, params->type,
|
|
params->resolution[0], params->resolution[1]);
|
|
DDPDUMP("physical=(%u,%u)\n",
|
|
params->physical_width, params->physical_height);
|
|
DDPDUMP("================================================\n");
|
|
}
|
|
|
|
void mtk_lcm_dump_all(char func, struct mtk_panel_resource *resource,
|
|
struct mtk_panel_cust *cust)
|
|
{
|
|
dump_lcm_params_basic(&resource->params);
|
|
|
|
switch (func) {
|
|
case MTK_LCM_FUNC_DBI:
|
|
dump_lcm_params_dbi(&resource->params.dbi_params, &resource->cust);
|
|
dump_lcm_ops_dbi(resource->ops.dbi_ops,
|
|
&resource->params.dbi_params, &resource->cust);
|
|
break;
|
|
case MTK_LCM_FUNC_DPI:
|
|
dump_lcm_params_dpi(&resource->params.dpi_params, &resource->cust);
|
|
dump_lcm_ops_dpi(resource->ops.dpi_ops,
|
|
&resource->params.dpi_params, &resource->cust);
|
|
break;
|
|
case MTK_LCM_FUNC_DSI:
|
|
dump_lcm_params_dsi(&resource->params.dsi_params, &resource->cust);
|
|
dump_lcm_ops_dsi(resource->ops.dsi_ops,
|
|
&resource->params.dsi_params, &resource->cust);
|
|
break;
|
|
default:
|
|
DDPDUMP("%s, invalid func:%d\n", __func__, func);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void free_lcm_ops_data(struct mtk_lcm_ops_data *lcm_op)
|
|
{
|
|
if (IS_ERR_OR_NULL(lcm_op))
|
|
return;
|
|
|
|
switch (lcm_op->type) {
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER:
|
|
if (lcm_op->param.buffer_data != NULL &&
|
|
lcm_op->size > 0) {
|
|
LCM_KFREE(lcm_op->param.buffer_data,
|
|
lcm_op->size + 1);
|
|
lcm_op->size = 0;
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_CONDITION:
|
|
if (lcm_op->param.buf_con_data.data != NULL &&
|
|
lcm_op->param.buf_con_data.data_len > 0) {
|
|
LCM_KFREE(lcm_op->param.buf_con_data.data,
|
|
lcm_op->param.buf_con_data.data_len + 1);
|
|
lcm_op->param.buf_con_data.data_len = 0;
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_BUFFER_RUNTIME_INPUT:
|
|
if (lcm_op->param.buf_runtime_data.data != NULL &&
|
|
lcm_op->param.buf_runtime_data.data_len > 0) {
|
|
LCM_KFREE(lcm_op->param.buf_runtime_data.data,
|
|
lcm_op->param.buf_runtime_data.data_len + 1);
|
|
lcm_op->param.buf_runtime_data.data_len = 0;
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_WRITE_CMD:
|
|
if (lcm_op->param.cmd_data.data != NULL &&
|
|
lcm_op->size > 0) {
|
|
LCM_KFREE(lcm_op->param.cmd_data.data,
|
|
lcm_op->size);
|
|
lcm_op->size = 0;
|
|
}
|
|
break;
|
|
case MTK_LCM_CMD_TYPE_READ_BUFFER:
|
|
case MTK_LCM_CMD_TYPE_READ_CMD:
|
|
if (lcm_op->param.cmd_data.data != NULL &&
|
|
lcm_op->param.cmd_data.data_len > 0) {
|
|
LCM_KFREE(lcm_op->param.cmd_data.data,
|
|
lcm_op->param.cmd_data.data_len + 1);
|
|
lcm_op->param.cmd_data.data_len = 0;
|
|
}
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME:
|
|
if (lcm_op->param.cb_id_data.buffer_data != NULL &&
|
|
lcm_op->size > 0) {
|
|
LCM_KFREE(lcm_op->param.cb_id_data.buffer_data,
|
|
lcm_op->size + 1);
|
|
lcm_op->size = 0;
|
|
}
|
|
break;
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT:
|
|
case MTK_LCM_CB_TYPE_RUNTIME_INPUT_MULTIPLE:
|
|
if (lcm_op->param.cb_id_data.id != NULL &&
|
|
lcm_op->param.cb_id_data.id_count > 0) {
|
|
LCM_KFREE(lcm_op->param.cb_id_data.id,
|
|
lcm_op->param.cb_id_data.id_count + 1);
|
|
lcm_op->param.cb_id_data.id_count = 0;
|
|
}
|
|
if (lcm_op->param.cb_id_data.buffer_data != NULL &&
|
|
lcm_op->param.cb_id_data.data_count > 0) {
|
|
LCM_KFREE(lcm_op->param.cb_id_data.buffer_data,
|
|
lcm_op->param.cb_id_data.data_count + 1);
|
|
lcm_op->param.cb_id_data.data_count = 0;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void free_lcm_ops_table(struct mtk_lcm_ops_table *table)
|
|
{
|
|
struct mtk_lcm_ops_data *op = NULL, *tmp = NULL;
|
|
|
|
if (IS_ERR_OR_NULL(table) || table->size == 0)
|
|
return;
|
|
|
|
list_for_each_entry_safe(op, tmp, &table->list, node) {
|
|
list_del(&op->node);
|
|
free_lcm_ops_data(op);
|
|
LCM_KFREE(op, sizeof(struct mtk_lcm_ops_data));
|
|
}
|
|
table->size = 0;
|
|
}
|
|
|
|
static void free_lcm_params(char func, struct mtk_lcm_params *params)
|
|
{
|
|
if (IS_ERR_OR_NULL(params))
|
|
return;
|
|
|
|
switch (func) {
|
|
case MTK_LCM_FUNC_DBI:
|
|
free_lcm_params_dbi(¶ms->dbi_params);
|
|
break;
|
|
case MTK_LCM_FUNC_DPI:
|
|
free_lcm_params_dpi(¶ms->dpi_params);
|
|
break;
|
|
case MTK_LCM_FUNC_DSI:
|
|
free_lcm_params_dsi(¶ms->dsi_params);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void free_lcm_ops(char func, struct mtk_lcm_ops *ops)
|
|
{
|
|
if (ops == NULL)
|
|
return;
|
|
|
|
switch (func) {
|
|
case MTK_LCM_FUNC_DBI:
|
|
free_lcm_ops_dbi(ops->dbi_ops);
|
|
ops->dbi_ops = NULL;
|
|
break;
|
|
case MTK_LCM_FUNC_DPI:
|
|
free_lcm_ops_dpi(ops->dpi_ops);
|
|
ops->dpi_ops = NULL;
|
|
break;
|
|
case MTK_LCM_FUNC_DSI:
|
|
free_lcm_ops_dsi(ops->dsi_ops);
|
|
ops->dsi_ops = NULL;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void free_lcm_resource(char func, struct mtk_panel_resource *data)
|
|
{
|
|
if (IS_ERR_OR_NULL(data))
|
|
return;
|
|
|
|
DDPMSG("%s, %d\n", __func__, __LINE__);
|
|
free_lcm_ops(func, &data->ops);
|
|
free_lcm_params(func, &data->params);
|
|
|
|
if (atomic_read(&data->cust.cust_enabled) == 1) {
|
|
if (data->cust.free_ops != NULL)
|
|
data->cust.free_ops(func);
|
|
if (data->cust.free_params != NULL)
|
|
data->cust.free_params(func);
|
|
}
|
|
LCM_KFREE(data, sizeof(struct mtk_panel_resource));
|
|
}
|