mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2025-09-16 03:59:21 +00:00
343 lines
8.6 KiB
C
343 lines
8.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2021 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/component.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include "mtk-mml-core.h"
|
|
#include "mtk-mml-driver.h"
|
|
|
|
#include "tile_driver.h"
|
|
|
|
#define FG_TRIGGER 0x000
|
|
#define FG_STATUS 0x004
|
|
#define FG_CTRL_0 0x020
|
|
#define FG_CK_EN 0x024
|
|
#define FG_BACK_DOOR_0 0x02c
|
|
#define FG_PIC_INFO_0 0x400
|
|
#define FG_PIC_INFO_1 0x404
|
|
#define FG_TILE_INFO_0 0x418
|
|
#define FG_TILE_INFO_1 0x41c
|
|
#define FG_DEBUG_0 0x500
|
|
#define FG_DEBUG_1 0x504
|
|
#define FG_DEBUG_2 0x508
|
|
#define FG_DEBUG_3 0x50c
|
|
#define FG_DEBUG_4 0x510
|
|
#define FG_DEBUG_5 0x514
|
|
#define FG_DEBUG_6 0x518
|
|
|
|
struct fg_data {
|
|
};
|
|
|
|
static const struct fg_data mt6893_fg_data = {
|
|
};
|
|
|
|
struct mml_comp_fg {
|
|
struct mml_comp comp;
|
|
const struct fg_data *data;
|
|
};
|
|
|
|
/* meta data for each different frame config */
|
|
struct fg_frame_data {
|
|
u8 out_idx;
|
|
};
|
|
|
|
#define fg_frm_data(i) ((struct fg_frame_data *)(i->data))
|
|
|
|
static s32 fg_prepare(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct fg_frame_data *fg_frm;
|
|
|
|
fg_frm = kzalloc(sizeof(*fg_frm), GFP_KERNEL);
|
|
ccfg->data = fg_frm;
|
|
/* cache out index for easy use */
|
|
fg_frm->out_idx = ccfg->node->out_idx;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static s32 fg_tile_prepare(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg,
|
|
struct tile_func_block *func,
|
|
union mml_tile_data *data)
|
|
{
|
|
struct fg_frame_data *fg_frm = fg_frm_data(ccfg);
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct mml_frame_data *src = &cfg->info.src;
|
|
struct mml_frame_dest *dest = &cfg->info.dest[fg_frm->out_idx];
|
|
|
|
func->enable_flag = true;
|
|
|
|
if (cfg->info.dest_cnt == 1 &&
|
|
(dest->crop.r.width != src->width ||
|
|
dest->crop.r.height != src->height)) {
|
|
u32 in_crop_w, in_crop_h;
|
|
|
|
in_crop_w = dest->crop.r.width;
|
|
in_crop_h = dest->crop.r.height;
|
|
if (in_crop_w + dest->crop.r.left > src->width)
|
|
in_crop_w = src->width - dest->crop.r.left;
|
|
if (in_crop_h + dest->crop.r.top > src->height)
|
|
in_crop_h = src->height - dest->crop.r.top;
|
|
func->full_size_x_in = in_crop_w + dest->crop.r.left;
|
|
func->full_size_y_in = in_crop_h + dest->crop.r.top;
|
|
} else {
|
|
func->full_size_x_in = src->width;
|
|
func->full_size_y_in = src->height;
|
|
}
|
|
func->full_size_x_out = func->full_size_x_in;
|
|
func->full_size_y_out = func->full_size_y_in;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct mml_comp_tile_ops fg_tile_ops = {
|
|
.prepare = fg_tile_prepare,
|
|
};
|
|
|
|
static s32 fg_init(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
|
|
const phys_addr_t base_pa = comp->base_pa;
|
|
|
|
cmdq_pkt_write(pkt, NULL, base_pa + FG_TRIGGER, 0, U32_MAX);
|
|
return 0;
|
|
}
|
|
|
|
static s32 fg_config_frame(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg)
|
|
{
|
|
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
|
|
const phys_addr_t base_pa = comp->base_pa;
|
|
|
|
/* relay mode */
|
|
cmdq_pkt_write(pkt, NULL, base_pa + FG_CTRL_0, 1, U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + FG_CK_EN, 0x7, U32_MAX);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static s32 fg_config_tile(struct mml_comp *comp, struct mml_task *task,
|
|
struct mml_comp_config *ccfg, u32 idx)
|
|
{
|
|
struct mml_frame_config *cfg = task->config;
|
|
struct cmdq_pkt *pkt = task->pkts[ccfg->pipe];
|
|
const phys_addr_t base_pa = comp->base_pa;
|
|
|
|
struct mml_tile_engine *tile = config_get_tile(cfg, ccfg, idx);
|
|
|
|
u32 width = tile->in.xe - tile->in.xs + 1;
|
|
u32 height = tile->in.ye - tile->in.ys + 1;
|
|
|
|
cmdq_pkt_write(pkt, NULL, base_pa + FG_TILE_INFO_0,
|
|
(tile->in.xs & 0xffff) + ((width & 0xffff) << 16), U32_MAX);
|
|
cmdq_pkt_write(pkt, NULL, base_pa + FG_TILE_INFO_1,
|
|
(tile->in.ys & 0xffff) + ((height & 0xffff) << 16), U32_MAX);
|
|
return 0;
|
|
}
|
|
|
|
static const struct mml_comp_config_ops fg_cfg_ops = {
|
|
.prepare = fg_prepare,
|
|
.init = fg_init,
|
|
.frame = fg_config_frame,
|
|
.tile = fg_config_tile,
|
|
};
|
|
|
|
static void fg_debug_dump(struct mml_comp *comp)
|
|
{
|
|
void __iomem *base = comp->base;
|
|
u32 value[16];
|
|
|
|
mml_err("fg component %u dump:", comp->id);
|
|
|
|
value[0] = readl(base + FG_TRIGGER);
|
|
value[1] = readl(base + FG_STATUS);
|
|
value[2] = readl(base + FG_CTRL_0);
|
|
value[3] = readl(base + FG_CK_EN);
|
|
value[4] = readl(base + FG_BACK_DOOR_0);
|
|
value[5] = readl(base + FG_PIC_INFO_0);
|
|
value[6] = readl(base + FG_PIC_INFO_1);
|
|
value[7] = readl(base + FG_TILE_INFO_0);
|
|
value[8] = readl(base + FG_TILE_INFO_1);
|
|
value[9] = readl(base + FG_DEBUG_0);
|
|
value[10] = readl(base + FG_DEBUG_1);
|
|
value[11] = readl(base + FG_DEBUG_2);
|
|
value[12] = readl(base + FG_DEBUG_3);
|
|
value[13] = readl(base + FG_DEBUG_4);
|
|
value[14] = readl(base + FG_DEBUG_5);
|
|
value[15] = readl(base + FG_DEBUG_6);
|
|
|
|
mml_err("FG_TRIGGER %#010x FG_STATUS %#010x",
|
|
value[0], value[1]);
|
|
mml_err("FG_CTRL_0 %#010x FG_CK_EN %#010x",
|
|
value[2], value[3]);
|
|
mml_err("FG_BACK_DOOR_0 %#010x FG_PIC_INFO_0 %#010x FG_PIC_INFO_1 %#010x",
|
|
value[4], value[5], value[6]);
|
|
mml_err("FG_TILE_INFO_0 %#010x FG_TILE_INFO_1 %#010x",
|
|
value[7], value[8]);
|
|
mml_err("FG_DEBUG_0 %#010x FG_DEBUG_1 %#010x FG_DEBUG_2 %#010x",
|
|
value[9], value[10], value[11]);
|
|
mml_err("FG_DEBUG_3 %#010x FG_DEBUG_4 %#010x FG_DEBUG_5 %#010x",
|
|
value[12], value[13], value[14]);
|
|
mml_err("FG_DEBUG_6 %#010x ", value[15]);
|
|
}
|
|
|
|
static const struct mml_comp_debug_ops fg_debug_ops = {
|
|
.dump = &fg_debug_dump,
|
|
};
|
|
|
|
static int mml_bind(struct device *dev, struct device *master, void *data)
|
|
{
|
|
struct mml_comp_fg *fg = dev_get_drvdata(dev);
|
|
s32 ret;
|
|
|
|
ret = mml_register_comp(master, &fg->comp);
|
|
if (ret)
|
|
dev_err(dev, "Failed to register mml component %s: %d\n",
|
|
dev->of_node->full_name, ret);
|
|
return ret;
|
|
}
|
|
|
|
static void mml_unbind(struct device *dev, struct device *master, void *data)
|
|
{
|
|
struct mml_comp_fg *fg = dev_get_drvdata(dev);
|
|
|
|
mml_unregister_comp(master, &fg->comp);
|
|
}
|
|
|
|
static const struct component_ops mml_comp_ops = {
|
|
.bind = mml_bind,
|
|
.unbind = mml_unbind,
|
|
};
|
|
|
|
static struct mml_comp_fg *dbg_probed_components[2];
|
|
static int dbg_probed_count;
|
|
|
|
static int probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct mml_comp_fg *priv;
|
|
s32 ret;
|
|
|
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
|
|
platform_set_drvdata(pdev, priv);
|
|
priv->data = of_device_get_match_data(dev);
|
|
|
|
ret = mml_comp_init(pdev, &priv->comp);
|
|
if (ret) {
|
|
dev_err(dev, "Failed to init mml component: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* assign ops */
|
|
priv->comp.tile_ops = &fg_tile_ops;
|
|
priv->comp.config_ops = &fg_cfg_ops;
|
|
priv->comp.debug_ops = &fg_debug_ops;
|
|
|
|
dbg_probed_components[dbg_probed_count++] = priv;
|
|
|
|
ret = component_add(dev, &mml_comp_ops);
|
|
if (ret)
|
|
dev_err(dev, "Failed to add component: %d\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int remove(struct platform_device *pdev)
|
|
{
|
|
component_del(&pdev->dev, &mml_comp_ops);
|
|
return 0;
|
|
}
|
|
|
|
const struct of_device_id mml_fg_driver_dt_match[] = {
|
|
{
|
|
.compatible = "mediatek,mt6893-mml_fg",
|
|
.data = &mt6893_fg_data
|
|
},
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, mml_fg_driver_dt_match);
|
|
|
|
struct platform_driver mml_fg_driver = {
|
|
.probe = probe,
|
|
.remove = remove,
|
|
.driver = {
|
|
.name = "mediatek-mml-fg",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = mml_fg_driver_dt_match,
|
|
},
|
|
};
|
|
|
|
//module_platform_driver(mml_fg_driver);
|
|
|
|
static s32 ut_case;
|
|
static s32 ut_set(const char *val, const struct kernel_param *kp)
|
|
{
|
|
s32 result;
|
|
|
|
result = sscanf(val, "%d", &ut_case);
|
|
if (result != 1) {
|
|
mml_err("invalid input: %s, result(%d)", val, result);
|
|
return -EINVAL;
|
|
}
|
|
mml_log("%s: case_id=%d", __func__, ut_case);
|
|
|
|
switch (ut_case) {
|
|
case 0:
|
|
mml_log("use read to dump current pwm setting");
|
|
break;
|
|
default:
|
|
mml_err("invalid case_id: %d", ut_case);
|
|
break;
|
|
}
|
|
|
|
mml_log("%s END", __func__);
|
|
return 0;
|
|
}
|
|
|
|
static s32 ut_get(char *buf, const struct kernel_param *kp)
|
|
{
|
|
s32 length = 0;
|
|
u32 i;
|
|
|
|
switch (ut_case) {
|
|
case 0:
|
|
length += snprintf(buf + length, PAGE_SIZE - length,
|
|
"[%d] probed count: %d\n", ut_case, dbg_probed_count);
|
|
for(i = 0; i < dbg_probed_count; i++) {
|
|
length += snprintf(buf + length, PAGE_SIZE - length,
|
|
" - [%d] mml_comp_id: %d\n", i,
|
|
dbg_probed_components[i]->comp.id);
|
|
length += snprintf(buf + length, PAGE_SIZE - length,
|
|
" - mml_bound: %d\n",
|
|
dbg_probed_components[i]->comp.bound);
|
|
}
|
|
default:
|
|
mml_err("not support read for case_id: %d", ut_case);
|
|
break;
|
|
}
|
|
buf[length] = '\0';
|
|
|
|
return length;
|
|
}
|
|
|
|
static struct kernel_param_ops up_param_ops = {
|
|
.set = ut_set,
|
|
.get = ut_get,
|
|
};
|
|
module_param_cb(fg_ut_case, &up_param_ops, NULL, 0644);
|
|
MODULE_PARM_DESC(fg_ut_case, "mml fg UT test case");
|
|
|
|
MODULE_AUTHOR("Dennis-YC Hsieh <dennis-yc.hsieh@mediatek.com>");
|
|
MODULE_DESCRIPTION("MediaTek SoC display MML FG driver");
|
|
MODULE_LICENSE("GPL v2");
|