kernel_samsung_a53x/drivers/gpu/drm/samsung/panel/maptbl.c
2024-06-15 16:02:09 -03:00

583 lines
14 KiB
C
Executable file

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) Samsung Electronics Co., Ltd.
* Gwanghui Lee <gwanghui.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <asm-generic/errno-base.h>
#include <linux/string.h>
#include "maptbl.h"
#include "panel_debug.h"
int maptbl_alloc_buffer(struct maptbl *m, size_t size)
{
if (!m || !size)
return -EINVAL;
m->arr = kzalloc(size, GFP_KERNEL);
if (!m->arr)
return -ENOMEM;
return 0;
}
void maptbl_free_buffer(struct maptbl *m)
{
if (!m)
return;
kfree(m->arr);
m->arr = NULL;
}
void maptbl_set_shape(struct maptbl *m, struct maptbl_shape *shape)
{
if (!m || !shape)
return;
memcpy(&m->shape, shape, sizeof(*shape));
}
void maptbl_set_ops(struct maptbl *m, struct maptbl_ops *ops)
{
if (!m || !ops)
return;
memcpy(&m->ops, ops, sizeof(*ops));
}
void maptbl_set_initialized(struct maptbl *m, bool initialized)
{
if (!m)
return;
m->initialized = initialized;
}
void maptbl_set_private_data(struct maptbl *m, void *priv)
{
if (!m)
return;
m->pdata = priv;
}
void *maptbl_get_private_data(struct maptbl *m)
{
if (!m)
return NULL;
return m->pdata;
}
/**
* maptbl_create - create a struct maptbl structure
* @name: pointer to a string for the name of this maptbl.
* @shape: pointer to struct maptbl_shape for the shape of this maptbl.
* @ops: pointer to struct maptbl_ops for the operations of this maptbl.
* @init_data: pointer to buffer to initialize array buffer to be allocated.
* @priv: pointer to private_data; passing when maptbl_init() invoked.
*
* This is used to create a struct maptbl pointer.
*
* Returns &struct maptbl pointer on success, or NULL on error.
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to maptbl_destroy().
*/
struct maptbl *maptbl_create(char *name, struct maptbl_shape *shape,
struct maptbl_ops *ops, void *init_data, void *priv)
{
struct maptbl *m;
int ret;
m = kzalloc(sizeof(*m), GFP_KERNEL);
if (!m)
return NULL;
m->type = CMD_TYPE_MAP;
m->name = name;
maptbl_set_shape(m, shape);
maptbl_set_ops(m, ops);
maptbl_set_private_data(m, priv);
if (!maptbl_get_sizeof_maptbl(m))
return m;
ret = maptbl_alloc_buffer(m, maptbl_get_sizeof_maptbl(m));
if (ret < 0) {
panel_err("failed to alloc maptbl buffer(ret:%d)\n", ret);
goto err;
}
memcpy(m->arr, init_data, maptbl_get_sizeof_maptbl(m));
return m;
err:
kfree(m);
return NULL;
}
EXPORT_SYMBOL(maptbl_create);
/**
* maptbl_clone - create a struct maptbl structure by source maptbl
* @src: pointer to struct maptbl; used by passing argument to maptbl_create() function.
*
* This is used to create a struct maptbl pointer by source maptbl.
*
* Returns &struct maptbl pointer on success, or NULL on error.
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to maptbl_destroy().
*/
struct maptbl *maptbl_clone(struct maptbl *src)
{
if (!src)
return NULL;
return maptbl_create(src->name, &src->shape, &src->ops,
src->arr, maptbl_get_private_data(src));
}
EXPORT_SYMBOL(maptbl_clone);
/**
* maptbl_deepcopy - copy members of struct maptbl structure from maptbl
* @dst: pointer to destination struct maptbl
* @src: pointer to source struct maptbl
*
* This is used to copy to destination maptbl from source maptbl.
*
* Returns &struct maptbl pointer to destination maptbl on success, or NULL on error.
*
* Note, the pointer to be free when finished by making a call to maptbl_free_buffer().
*/
struct maptbl *maptbl_deepcopy(struct maptbl *dst, struct maptbl *src)
{
int ret;
if (!dst || !src)
return NULL;
if (dst == src)
return dst;
dst->type = src->type;
dst->name = src->name;
maptbl_set_shape(dst, &src->shape);
maptbl_set_ops(dst, &src->ops);
maptbl_set_private_data(dst, maptbl_get_private_data(src));
maptbl_free_buffer(dst);
if (!src->arr || !maptbl_get_sizeof_maptbl(src))
return dst;
ret = maptbl_alloc_buffer(dst, maptbl_get_sizeof_maptbl(src));
if (ret < 0) {
panel_err("failed to alloc maptbl buffer(ret:%d)\n", ret);
return NULL;
}
memcpy(dst->arr, src->arr, maptbl_get_sizeof_maptbl(src));
return dst;
}
EXPORT_SYMBOL(maptbl_deepcopy);
/**
* maptbl_destroy - destroys a struct maptbl structure
* @m: pointer to the struct maptbl that is to be destroyed
*
* Note, the pointer to be destroyed must have been created with a call
* to maptbl_create().
*/
void maptbl_destroy(struct maptbl *m)
{
maptbl_free_buffer(m);
kfree(m);
}
EXPORT_SYMBOL(maptbl_destroy);
int maptbl_get_indexof_n_dimen_element(struct maptbl *tbl, enum ndarray_dimen dimen, unsigned int indexof_element)
{
if (!tbl)
return -EINVAL;
if (indexof_element >= maptbl_get_countof_n_dimen_element(tbl, dimen)) {
panel_err("%s: out of bound(indexof_%dD_element:%d >= countof_%dD_element:%d)\n",
tbl->name, dimen + 1, indexof_element,
dimen + 1, maptbl_get_countof_n_dimen_element(tbl, dimen));
return -EINVAL;
}
return maptbl_get_sizeof_n_dimen_element(tbl, dimen) * indexof_element;
}
EXPORT_SYMBOL(maptbl_get_indexof_n_dimen_element);
int maptbl_get_indexof_box(struct maptbl *tbl, unsigned int indexof_element)
{
return maptbl_get_indexof_n_dimen_element(tbl, NDARR_4D, indexof_element);
}
EXPORT_SYMBOL(maptbl_get_indexof_box);
int maptbl_get_indexof_layer(struct maptbl *tbl, unsigned int indexof_element)
{
return maptbl_get_indexof_n_dimen_element(tbl, NDARR_3D, indexof_element);
}
EXPORT_SYMBOL(maptbl_get_indexof_layer);
int maptbl_get_indexof_row(struct maptbl *tbl, unsigned int indexof_element)
{
return maptbl_get_indexof_n_dimen_element(tbl, NDARR_2D, indexof_element);
}
EXPORT_SYMBOL(maptbl_get_indexof_row);
int maptbl_get_indexof_col(struct maptbl *tbl, unsigned int indexof_element)
{
return maptbl_get_indexof_n_dimen_element(tbl, NDARR_1D, indexof_element);
}
EXPORT_SYMBOL(maptbl_get_indexof_col);
int maptbl_4d_index(struct maptbl *tbl, int box, int layer, int row, int col)
{
int dimen, res = 0;
int index, indexof_element;
if (!tbl)
return -EINVAL;
maptbl_for_each_dimen(tbl, dimen) {
if (dimen == NDARR_1D)
indexof_element = col;
else if (dimen == NDARR_2D)
indexof_element = row;
else if (dimen == NDARR_3D)
indexof_element = layer;
else if (dimen == NDARR_4D)
indexof_element = box;
index = maptbl_get_indexof_n_dimen_element(tbl, dimen, indexof_element);
if (index < 0)
return -EINVAL;
res += index;
}
return res;
}
EXPORT_SYMBOL(maptbl_4d_index);
int maptbl_index(struct maptbl *tbl, int layer, int row, int col)
{
if (!tbl)
return -EINVAL;
return maptbl_4d_index(tbl, 0, layer, row, col);
}
EXPORT_SYMBOL(maptbl_index);
int maptbl_pos_to_index(struct maptbl *tbl, struct maptbl_pos *pos)
{
int dimen, res = 0;
int indexof_element;
if (!tbl || !pos)
return -EINVAL;
maptbl_for_each_dimen(tbl, dimen) {
indexof_element = maptbl_get_indexof_n_dimen_element(tbl,
dimen, pos->index[dimen]);
if (indexof_element < 0)
return -EINVAL;
res += indexof_element;
}
return res;
}
EXPORT_SYMBOL(maptbl_pos_to_index);
int maptbl_index_to_pos(struct maptbl *tbl, unsigned int index, struct maptbl_pos *pos)
{
int dimen;
int sizeof_element;
if (!tbl || !pos)
return -EINVAL;
if (index >= maptbl_get_sizeof_maptbl(tbl))
return -EINVAL;
maptbl_for_each_dimen_reverse(tbl, dimen) {
sizeof_element = maptbl_get_sizeof_n_dimen_element(tbl, dimen);
if (sizeof_element <= 0)
return -EINVAL;
pos->index[dimen] = index / sizeof_element;
index = index % sizeof_element;
}
return 0;
}
EXPORT_SYMBOL(maptbl_index_to_pos);
bool maptbl_is_initialized(struct maptbl *tbl)
{
return (tbl && tbl->initialized);
}
EXPORT_SYMBOL(maptbl_is_initialized);
bool maptbl_is_index_in_bound(struct maptbl *tbl, unsigned int index)
{
return (tbl && (index + maptbl_get_sizeof_copy(tbl) <= maptbl_get_sizeof_maptbl(tbl)));
}
EXPORT_SYMBOL(maptbl_is_index_in_bound);
int maptbl_init(struct maptbl *tbl)
{
int ret;
if (!tbl)
return -EINVAL;
if (!tbl->name)
return -ENODATA;
if (!tbl->ops.init) {
panel_err("%s:no init callback\n", tbl->name);
return -EINVAL;
}
ret = tbl->ops.init(tbl);
if (ret < 0) {
panel_err("%s:failed to init(ret:%d)\n", tbl->name, ret);
return ret;
}
maptbl_set_initialized(tbl, true);
return 0;
}
EXPORT_SYMBOL(maptbl_init);
int maptbl_getidx(struct maptbl *tbl)
{
int index;
if (!tbl)
return -EINVAL;
if (!tbl->ops.getidx) {
panel_err("%s:no getidx callback\n", tbl->name);
return -EINVAL;
}
if (!maptbl_is_initialized(tbl)) {
panel_err("%s:not initialized\n", tbl->name);
return -EINVAL;
}
index = tbl->ops.getidx(tbl);
if (index < 0) {
panel_err("%s:failed to getidx(ret:%d)\n", tbl->name, index);
return -EINVAL;
}
if (!maptbl_is_index_in_bound(tbl, index)) {
panel_err("%s:out of bound(index:%d, sizeof_copy:%d, sizeof_maptbl:%d)\n",
tbl->name, index, maptbl_get_sizeof_copy(tbl), maptbl_get_sizeof_maptbl(tbl));
return -EINVAL;
}
return index;
}
EXPORT_SYMBOL(maptbl_getidx);
int maptbl_copy(struct maptbl *tbl, u8 *dst)
{
if (!tbl || !dst)
return -EINVAL;
if (!tbl->ops.copy) {
panel_err("%s:no copy callback\n", tbl->name);
return -EINVAL;
}
if (!maptbl_is_initialized(tbl)) {
panel_err("%s:not initialized\n", tbl->name);
return -EINVAL;
}
tbl->ops.copy(tbl, dst);
return 0;
}
EXPORT_SYMBOL(maptbl_copy);
int maptbl_fill(struct maptbl *tbl, struct maptbl_pos *pos, u8 *src, size_t n)
{
u32 index;
if (!tbl || !tbl->arr || !pos || !src || !n) {
panel_err("invalid parameter\n");
return -EINVAL;
}
index = maptbl_pos_to_index(tbl, pos);
if (maptbl_get_sizeof_maptbl(tbl) <= index) {
panel_err("index(%d) exceed maptbl size\n", index);
return -EINVAL;
}
if (maptbl_get_sizeof_row(tbl) < n) {
panel_err("size(%ld) exceed row(%d) size\n",
n, maptbl_get_sizeof_row(tbl));
return -EINVAL;
}
memcpy(tbl->arr + index, src, n);
return 0;
}
EXPORT_SYMBOL(maptbl_fill);
int maptbl_cmp_shape(struct maptbl *m1, struct maptbl *m2)
{
int dimen, res = 0;
if (m1 == m2)
return 0;
if (!m1 || !m2)
return !m1 ? -1 : 1;
if ((res = maptbl_get_countof_dimen(m1) -
maptbl_get_countof_dimen(m2)) != 0)
return res;
maptbl_for_each_dimen_reverse(m1, dimen)
if ((res = maptbl_get_countof_n_dimen_element(m1, dimen) -
maptbl_get_countof_n_dimen_element(m2, dimen)) != 0)
break;
return res;
}
EXPORT_SYMBOL(maptbl_cmp_shape);
struct maptbl *maptbl_memcpy(struct maptbl *dst, struct maptbl *src)
{
if (!src || !dst)
return NULL;
if (!src->arr || !dst->arr)
return NULL;
if (maptbl_cmp_shape(src, dst)) {
panel_err("failed to copy different shape of maptbl, src:%s(%d), dst:%s(%d)\n",
src->name, maptbl_get_sizeof_maptbl(src),
dst->name, maptbl_get_sizeof_maptbl(dst));
return NULL;
}
memcpy(dst->arr, src->arr, maptbl_get_sizeof_maptbl(dst));
return dst;
}
EXPORT_SYMBOL(maptbl_memcpy);
int maptbl_snprintf_head(struct maptbl *tbl, char *buf, size_t size)
{
int i, len;
if (!tbl || !buf || !size)
return 0;
len = snprintf(buf, size, "%dD-MAPTBL:%s",
maptbl_get_countof_dimen(tbl), tbl->name);
maptbl_for_each_dimen_reverse(tbl, i)
len += snprintf(buf + len, size - len, "[%d]",
maptbl_get_countof_n_dimen_element(tbl, i));
len += snprintf(buf + len, size - len, "\n");
return len;
}
int maptbl_snprintf_body(struct maptbl *tbl, char *buf, size_t size)
{
int box, layer, row, col, len = 0;
char *space[MAX_NDARR_DIMEN] = {"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t", "\t\t\t\t\t\t", "\t\t\t\t\t\t\t"};
if (!tbl || !buf || !size)
return 0;
len += snprintf(buf + len, size - len, "\n");
maptbl_for_each_n_dimen_element(tbl, NDARR_4D, box) {
if (maptbl_get_countof_dimen(tbl) >= 4)
len += snprintf(buf + len, size - len, "%s[%d] = {\n", space[maptbl_get_countof_dimen(tbl) - 4], box);
maptbl_for_each_n_dimen_element(tbl, NDARR_3D, layer) {
if (maptbl_get_countof_dimen(tbl) >= 3)
len += snprintf(buf + len, size - len, "%s[%d] = {\n", space[maptbl_get_countof_dimen(tbl) - 3], layer);
maptbl_for_each_n_dimen_element(tbl, NDARR_2D, row) {
if (maptbl_get_countof_dimen(tbl) >= 2)
len += snprintf(buf + len, size - len, "%s[%d] = {\n", space[maptbl_get_countof_dimen(tbl) - 2], row);
maptbl_for_each_n_dimen_element(tbl, NDARR_1D, col) {
if (!(col % 8))
len += snprintf(buf + len, size - len, "%s", space[maptbl_get_countof_dimen(tbl) - 1]);
len += snprintf(buf + len, size - len, "%02X",
tbl->arr[maptbl_4d_index(tbl, box, layer, row, col)]);
if (!((col + 1) % 8) ||(col + 1 == maptbl_get_countof_col(tbl)))
len += snprintf(buf + len, size - len, "\n");
else
len += snprintf(buf + len, size - len, " ");
}
if (maptbl_get_countof_dimen(tbl) >= 2)
len += snprintf(buf + len, size - len, "%s},\n", space[maptbl_get_countof_dimen(tbl) - 2]);
}
if (maptbl_get_countof_dimen(tbl) >= 3)
len += snprintf(buf + len, size - len, "%s},\n", space[maptbl_get_countof_dimen(tbl) - 3]);
}
if (maptbl_get_countof_dimen(tbl) >= 4)
len += snprintf(buf + len, size - len, "%s},\n", space[maptbl_get_countof_dimen(tbl) - 4]);
}
return len;
}
int maptbl_snprintf_tail(struct maptbl *tbl, char *buf, size_t size)
{
if (!tbl || !buf || !size)
return 0;
return snprintf(buf, size, "=====================================\n");
}
int maptbl_snprintf(struct maptbl *tbl, char *buf, size_t size)
{
int len;
if (!tbl || !buf || !size)
return 0;
len = maptbl_snprintf_head(tbl, buf, size);
len += maptbl_snprintf_body(tbl, buf + len, size - len);
len += maptbl_snprintf_tail(tbl, buf + len, size - len);
return len;
}
void maptbl_print(struct maptbl *tbl)
{
char buf[256] = { 0, };
if (panel_log_level < 7)
return;
maptbl_snprintf(tbl, buf, sizeof(buf));
pr_info("%s\n", buf);
}
EXPORT_SYMBOL(maptbl_print);