blob: 7ab4f79fadd2d5914b7e13d4e09936ea111b1569 [file]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include "meson_vpu_pipeline.h"
#include "meson_drv.h"
static inline void
vpu_pipeline_state_set(struct meson_vpu_block *pblk,
struct meson_vpu_block_state *state)
{
u8 i;
for (i = 0; i < pblk->avail_inputs; i++) {
memcpy(&state->inputs[i], &pblk->inputs[i],
sizeof(struct meson_vpu_block_link));
}
for (i = 0; i < pblk->avail_outputs; i++) {
memcpy(&state->outputs[i], &pblk->outputs[i],
sizeof(struct meson_vpu_block_link));
}
state->in_stack = 0;
state->active = 1;
}
static struct drm_private_state *
meson_vpu_osd_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_osd_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void meson_vpu_osd_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_osd_state *mvos = to_osd_state(mvbs);
DRM_DEBUG("%s id=%d,index=%d\n",
mvbs->pblk->name, mvbs->pblk->id, mvbs->pblk->index);
kfree(mvos);
}
static const struct drm_private_state_funcs meson_vpu_osd_obj_funcs = {
.atomic_duplicate_state = meson_vpu_osd_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_osd_atomic_destroy_state,
};
static int meson_vpu_osd_state_init(struct meson_drm *private,
struct meson_vpu_osd *osd)
{
struct meson_vpu_osd_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &osd->base;
drm_atomic_private_obj_init(private->drm, &osd->base.obj,
&state->base.obj,
&meson_vpu_osd_obj_funcs);
return 0;
}
static struct drm_private_state *
meson_vpu_video_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_video_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void
meson_vpu_video_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_video_state *mvvs = to_video_state(mvbs);
DRM_DEBUG("%s id=%d,index=%d\n",
mvbs->pblk->name, mvbs->pblk->id, mvbs->pblk->index);
kfree(mvvs);
}
static const struct drm_private_state_funcs meson_vpu_video_obj_funcs = {
.atomic_duplicate_state = meson_vpu_video_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_video_atomic_destroy_state,
};
static int meson_vpu_video_state_init(struct meson_drm *private,
struct meson_vpu_video *video)
{
struct meson_vpu_video_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &video->base;
drm_atomic_private_obj_init(private->drm, &video->base.obj,
&state->base.obj,
&meson_vpu_video_obj_funcs);
return 0;
}
static struct drm_private_state *
meson_vpu_afbc_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_afbc_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void
meson_vpu_afbc_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_afbc_state *mvas = to_afbc_state(mvbs);
kfree(mvas);
}
static const struct drm_private_state_funcs meson_vpu_afbc_obj_funcs = {
.atomic_duplicate_state = meson_vpu_afbc_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_afbc_atomic_destroy_state,
};
static int meson_vpu_afbc_state_init(struct meson_drm *private,
struct meson_vpu_afbc *afbc)
{
struct meson_vpu_afbc_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &afbc->base;
drm_atomic_private_obj_init(private->drm, &afbc->base.obj,
&state->base.obj,
&meson_vpu_afbc_obj_funcs);
return 0;
}
/*afbc block state ops end
*/
/*scaler block state ops start
*/
static struct drm_private_state *
meson_vpu_scaler_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_scaler_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void
meson_vpu_scaler_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_scaler_state *mvss = to_scaler_state(mvbs);
kfree(mvss);
}
static const struct drm_private_state_funcs meson_vpu_scaler_obj_funcs = {
.atomic_duplicate_state = meson_vpu_scaler_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_scaler_atomic_destroy_state,
};
static int meson_vpu_scaler_state_init(struct meson_drm *private,
struct meson_vpu_scaler *scaler)
{
struct meson_vpu_scaler_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &scaler->base;
drm_atomic_private_obj_init(private->drm, &scaler->base.obj,
&state->base.obj,
&meson_vpu_scaler_obj_funcs);
return 0;
}
static struct drm_private_state *
meson_vpu_osdblend_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_osdblend_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void
meson_vpu_osdblend_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_osdblend_state *mvos = to_osdblend_state(mvbs);
kfree(mvos);
}
static const struct drm_private_state_funcs meson_vpu_osdblend_obj_funcs = {
.atomic_duplicate_state = meson_vpu_osdblend_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_osdblend_atomic_destroy_state,
};
static int meson_vpu_osdblend_state_init(struct meson_drm *private,
struct meson_vpu_osdblend *osdblend)
{
struct meson_vpu_osdblend_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &osdblend->base;
drm_atomic_private_obj_init(private->drm, &osdblend->base.obj,
&state->base.obj,
&meson_vpu_osdblend_obj_funcs);
return 0;
}
static struct drm_private_state *
meson_vpu_hdr_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_hdr_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void meson_vpu_hdr_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_hdr_state *mvhs = to_hdr_state(mvbs);
kfree(mvhs);
}
static const struct drm_private_state_funcs meson_vpu_hdr_obj_funcs = {
.atomic_duplicate_state = meson_vpu_hdr_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_hdr_atomic_destroy_state,
};
static int meson_vpu_hdr_state_init(struct meson_drm *private,
struct meson_vpu_hdr *hdr)
{
struct meson_vpu_hdr_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &hdr->base;
drm_atomic_private_obj_init(private->drm, &hdr->base.obj,
&state->base.obj,
&meson_vpu_hdr_obj_funcs);
return 0;
}
/*hdr block state ops end
*/
/*postblend block state ops start
*/
static struct drm_private_state *
meson_vpu_postblend_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_postblend_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void
meson_vpu_postblend_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_postblend_state *mvas = to_postblend_state(mvbs);
kfree(mvas);
}
static const struct drm_private_state_funcs meson_vpu_postblend_obj_funcs = {
.atomic_duplicate_state = meson_vpu_postblend_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_postblend_atomic_destroy_state,
};
static int
meson_vpu_postblend_state_init(struct meson_drm *private,
struct meson_vpu_postblend *postblend)
{
struct meson_vpu_postblend_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &postblend->base;
drm_atomic_private_obj_init(private->drm, &postblend->base.obj,
&state->base.obj,
&meson_vpu_postblend_obj_funcs);
return 0;
}
/*postblend block state ops end
*/
/* slice2ppc */
static struct drm_private_state *
meson_vpu_slice2ppc_atomic_duplicate_state(struct drm_private_obj *obj)
{
struct meson_vpu_block *mvb;
struct meson_vpu_slice2ppc_state *state;
mvb = priv_to_block(obj);
state = kzalloc(sizeof(*state), GFP_KERNEL);
state->base.pblk = mvb;
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base.obj);
vpu_pipeline_state_set(mvb, &state->base);
return &state->base.obj;
}
static void
meson_vpu_slice2ppc_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_block_state *mvbs = priv_to_block_state(state);
struct meson_vpu_slice2ppc_state *mvss = to_slice2ppc_state(mvbs);
kfree(mvss);
}
static const struct drm_private_state_funcs meson_vpu_slice2ppc_obj_funcs = {
.atomic_duplicate_state = meson_vpu_slice2ppc_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_slice2ppc_atomic_destroy_state,
};
static int
meson_vpu_slice2ppc_state_init(struct meson_drm *private,
struct meson_vpu_slice2ppc *slice2ppc)
{
struct meson_vpu_slice2ppc_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->base.pblk = &slice2ppc->base;
drm_atomic_private_obj_init(private->drm, &slice2ppc->base.obj,
&state->base.obj,
&meson_vpu_slice2ppc_obj_funcs);
return 0;
}
/*slice2ppc block state ops end
*/
static struct drm_private_state *
meson_vpu_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
{
int i;
struct meson_vpu_osd_layer_info *info;
struct meson_vpu_pipeline_state *state;
struct meson_vpu_pipeline *pipeline = priv_to_pipeline(obj);
struct meson_vpu_pipeline_state *cur_state = priv_to_pipeline_state(obj->state);
state = kzalloc(sizeof(*state), GFP_KERNEL);
memcpy(state, cur_state, sizeof(struct meson_vpu_pipeline_state));
state->pipeline = pipeline;
state->global_afbc = 0;
for (i = 0; i < MESON_MAX_OSDS; i++) {
if (state->sub_states[0].more_60 && i == OSD3_SLICE1) {
info = &state->plane_info[i];
info->enable = 0;
}
}
return &state->obj;
}
static void
meson_vpu_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state)
{
struct meson_vpu_pipeline_state *mvps = priv_to_pipeline_state(state);
kfree(mvps);
}
static const struct drm_private_state_funcs meson_vpu_pipeline_obj_funcs = {
.atomic_duplicate_state = meson_vpu_pipeline_atomic_duplicate_state,
.atomic_destroy_state = meson_vpu_pipeline_atomic_destroy_state,
};
static int meson_vpu_pipeline_state_init(struct meson_drm *private,
struct meson_vpu_pipeline *pipeline)
{
struct meson_vpu_pipeline_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->pipeline = pipeline;
drm_atomic_private_obj_init(private->drm, &pipeline->obj, &state->obj,
&meson_vpu_pipeline_obj_funcs);
return 0;
}
struct meson_vpu_block_state *
meson_vpu_block_get_state(struct meson_vpu_block *block,
struct drm_atomic_state *state)
{
struct drm_private_state *dps;
struct meson_vpu_block_state *mvbs;
dps = drm_atomic_get_private_obj_state(state, &block->obj);
if (!IS_ERR(dps)) {
mvbs = priv_to_block_state(dps);
return mvbs;
} else {
DRM_ERROR("vpu block state ERROR (%ld)\n", PTR_ERR(dps));
}
return NULL;
}
struct meson_vpu_block_state *
meson_vpu_block_get_old_state(struct meson_vpu_block *mvb,
struct drm_atomic_state *state)
{
struct drm_private_obj *obj;
struct drm_private_state *old_obj_state;
struct meson_vpu_block_state *mvbs = NULL;
int i;
for_each_old_private_obj_in_state(state, obj, old_obj_state, i) {
mvbs = priv_to_block_state(old_obj_state);
if (mvb == mvbs->pblk)
return mvbs;
}
return NULL;
}
struct meson_vpu_pipeline_state *
meson_vpu_pipeline_get_state(struct meson_vpu_pipeline *pipeline,
struct drm_atomic_state *state)
{
struct drm_private_state *dps;
dps = drm_atomic_get_private_obj_state(state, &pipeline->obj);
if (!IS_ERR(dps)) {
dps->state = state;
return priv_to_pipeline_state(dps);
} else {
DRM_ERROR("vpu pipeline state ERROR (%ld)\n", PTR_ERR(dps));
}
return NULL;
}
int meson_vpu_block_state_init(struct meson_drm *private,
struct meson_vpu_pipeline *pipeline)
{
int i, ret;
ret = meson_vpu_pipeline_state_init(private, pipeline);
if (ret)
return ret;
for (i = 0; i < MESON_MAX_OSDS; i++) {
if (pipeline->osds[i]) {
ret = meson_vpu_osd_state_init(private,
pipeline->osds[i]);
if (ret)
return ret;
}
}
for (i = 0; i < pipeline->num_video; i++) {
ret = meson_vpu_video_state_init(private, pipeline->video[i]);
if (ret)
return ret;
}
for (i = 0; i < pipeline->num_afbc_osds; i++) {
ret = meson_vpu_afbc_state_init(private,
pipeline->afbc_osds[i]);
if (ret)
return ret;
}
for (i = 0; i < MESON_MAX_SCALERS; i++) {
if (pipeline->scalers[i]) {
ret = meson_vpu_scaler_state_init(private,
pipeline->scalers[i]);
if (ret)
return ret;
}
}
ret = meson_vpu_osdblend_state_init(private, pipeline->osdblend);
if (ret)
return ret;
for (i = 0; i < MESON_MAX_HDRS; i++) {
if (pipeline->hdrs[i]) {
ret = meson_vpu_hdr_state_init(private, pipeline->hdrs[i]);
if (ret)
return ret;
}
}
for (i = 0; i < pipeline->num_postblend; i++) {
ret = meson_vpu_postblend_state_init(private,
pipeline->postblends[i]);
if (ret)
return ret;
}
if (pipeline->slice2ppc) {
ret = meson_vpu_slice2ppc_state_init(private, pipeline->slice2ppc);
if (ret)
return ret;
}
return 0;
}