blob: 24fcd37bc06f377b33d80ceef93af8fbbabc08a5 [file] [log] [blame]
// 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
*/
#ifdef MESON_DRM_VERSION_V0
static struct meson_vpu_pipeline_state last_mvps;
#endif
static struct drm_private_state *
meson_vpu_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
{
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;
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);
}
#ifdef MESON_DRM_VERSION_V0
void
meson_vpu_pipeline_atomic_backup_state(struct meson_vpu_pipeline_state *mvps)
{
memcpy(&last_mvps, mvps, sizeof(*mvps));
}
#endif
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 (dps) {
mvbs = priv_to_block_state(dps);
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 (dps) {
dps->state = state;
return priv_to_pipeline_state(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 < pipeline->num_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 < pipeline->num_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;
ret = meson_vpu_hdr_state_init(private, pipeline->hdr);
if (ret)
return ret;
ret = meson_vpu_postblend_state_init(private, pipeline->postblend);
if (ret)
return ret;
return 0;
}