162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
462306a36Sopenharmony_ci * Author:Mark Yao <mark.yao@rock-chips.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <drm/drm.h>
1062306a36Sopenharmony_ci#include <drm/drm_atomic.h>
1162306a36Sopenharmony_ci#include <drm/drm_damage_helper.h>
1262306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
1362306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
1462306a36Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h>
1562306a36Sopenharmony_ci#include <drm/drm_probe_helper.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "rockchip_drm_drv.h"
1862306a36Sopenharmony_ci#include "rockchip_drm_fb.h"
1962306a36Sopenharmony_ci#include "rockchip_drm_gem.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
2262306a36Sopenharmony_ci	.destroy       = drm_gem_fb_destroy,
2362306a36Sopenharmony_ci	.create_handle = drm_gem_fb_create_handle,
2462306a36Sopenharmony_ci	.dirty	       = drm_atomic_helper_dirtyfb,
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
2862306a36Sopenharmony_ci	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic struct drm_framebuffer *
3262306a36Sopenharmony_cirockchip_fb_create(struct drm_device *dev, struct drm_file *file,
3362306a36Sopenharmony_ci		   const struct drm_mode_fb_cmd2 *mode_cmd)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	struct drm_afbc_framebuffer *afbc_fb;
3662306a36Sopenharmony_ci	const struct drm_format_info *info;
3762306a36Sopenharmony_ci	int ret;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	info = drm_get_format_info(dev, mode_cmd);
4062306a36Sopenharmony_ci	if (!info)
4162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL);
4462306a36Sopenharmony_ci	if (!afbc_fb)
4562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd,
4862306a36Sopenharmony_ci					 &rockchip_drm_fb_funcs);
4962306a36Sopenharmony_ci	if (ret) {
5062306a36Sopenharmony_ci		kfree(afbc_fb);
5162306a36Sopenharmony_ci		return ERR_PTR(ret);
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (drm_is_afbc(mode_cmd->modifier[0])) {
5562306a36Sopenharmony_ci		int ret, i;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb);
5862306a36Sopenharmony_ci		if (ret) {
5962306a36Sopenharmony_ci			struct drm_gem_object **obj = afbc_fb->base.obj;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci			for (i = 0; i < info->num_planes; ++i)
6262306a36Sopenharmony_ci				drm_gem_object_put(obj[i]);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci			kfree(afbc_fb);
6562306a36Sopenharmony_ci			return ERR_PTR(ret);
6662306a36Sopenharmony_ci		}
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return &afbc_fb->base;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
7362306a36Sopenharmony_ci	.fb_create = rockchip_fb_create,
7462306a36Sopenharmony_ci	.atomic_check = drm_atomic_helper_check,
7562306a36Sopenharmony_ci	.atomic_commit = drm_atomic_helper_commit,
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_civoid rockchip_drm_mode_config_init(struct drm_device *dev)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	dev->mode_config.min_width = 0;
8162306a36Sopenharmony_ci	dev->mode_config.min_height = 0;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/*
8462306a36Sopenharmony_ci	 * set max width and height as default value(4096x4096).
8562306a36Sopenharmony_ci	 * this value would be used to check framebuffer size limitation
8662306a36Sopenharmony_ci	 * at drm_mode_addfb().
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	dev->mode_config.max_width = 4096;
8962306a36Sopenharmony_ci	dev->mode_config.max_height = 4096;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
9262306a36Sopenharmony_ci	dev->mode_config.helper_private = &rockchip_mode_config_helpers;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	dev->mode_config.normalize_zpos = true;
9562306a36Sopenharmony_ci}
96