18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd 48c2ecf20Sopenharmony_ci * Author:Mark Yao <mark.yao@rock-chips.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <drm/drm.h> 108c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 118c2ecf20Sopenharmony_ci#include <drm/drm_damage_helper.h> 128c2ecf20Sopenharmony_ci#include <drm/drm_fb_helper.h> 138c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h> 158c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "rockchip_drm_drv.h" 188c2ecf20Sopenharmony_ci#include "rockchip_drm_fb.h" 198c2ecf20Sopenharmony_ci#include "rockchip_drm_gem.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { 228c2ecf20Sopenharmony_ci .destroy = drm_gem_fb_destroy, 238c2ecf20Sopenharmony_ci .create_handle = drm_gem_fb_create_handle, 248c2ecf20Sopenharmony_ci .dirty = drm_atomic_helper_dirtyfb, 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic struct drm_framebuffer * 288c2ecf20Sopenharmony_cirockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, 298c2ecf20Sopenharmony_ci struct drm_gem_object **obj, unsigned int num_planes) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct drm_framebuffer *fb; 328c2ecf20Sopenharmony_ci int ret; 338c2ecf20Sopenharmony_ci int i; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci fb = kzalloc(sizeof(*fb), GFP_KERNEL); 368c2ecf20Sopenharmony_ci if (!fb) 378c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci for (i = 0; i < num_planes; i++) 428c2ecf20Sopenharmony_ci fb->obj[i] = obj[i]; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci ret = drm_framebuffer_init(dev, fb, &rockchip_drm_fb_funcs); 458c2ecf20Sopenharmony_ci if (ret) { 468c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev->dev, 478c2ecf20Sopenharmony_ci "Failed to initialize framebuffer: %d\n", 488c2ecf20Sopenharmony_ci ret); 498c2ecf20Sopenharmony_ci kfree(fb); 508c2ecf20Sopenharmony_ci return ERR_PTR(ret); 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return fb; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = { 578c2ecf20Sopenharmony_ci .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic struct drm_framebuffer * 618c2ecf20Sopenharmony_cirockchip_fb_create(struct drm_device *dev, struct drm_file *file, 628c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct drm_afbc_framebuffer *afbc_fb; 658c2ecf20Sopenharmony_ci const struct drm_format_info *info; 668c2ecf20Sopenharmony_ci int ret; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci info = drm_get_format_info(dev, mode_cmd); 698c2ecf20Sopenharmony_ci if (!info) 708c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL); 738c2ecf20Sopenharmony_ci if (!afbc_fb) 748c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd, 778c2ecf20Sopenharmony_ci &rockchip_drm_fb_funcs); 788c2ecf20Sopenharmony_ci if (ret) { 798c2ecf20Sopenharmony_ci kfree(afbc_fb); 808c2ecf20Sopenharmony_ci return ERR_PTR(ret); 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (drm_is_afbc(mode_cmd->modifier[0])) { 848c2ecf20Sopenharmony_ci int ret, i; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb); 878c2ecf20Sopenharmony_ci if (ret) { 888c2ecf20Sopenharmony_ci struct drm_gem_object **obj = afbc_fb->base.obj; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci for (i = 0; i < info->num_planes; ++i) 918c2ecf20Sopenharmony_ci drm_gem_object_put(obj[i]); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci kfree(afbc_fb); 948c2ecf20Sopenharmony_ci return ERR_PTR(ret); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return &afbc_fb->base; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { 1028c2ecf20Sopenharmony_ci .fb_create = rockchip_fb_create, 1038c2ecf20Sopenharmony_ci .output_poll_changed = drm_fb_helper_output_poll_changed, 1048c2ecf20Sopenharmony_ci .atomic_check = drm_atomic_helper_check, 1058c2ecf20Sopenharmony_ci .atomic_commit = drm_atomic_helper_commit, 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistruct drm_framebuffer * 1098c2ecf20Sopenharmony_cirockchip_drm_framebuffer_init(struct drm_device *dev, 1108c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd, 1118c2ecf20Sopenharmony_ci struct drm_gem_object *obj) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct drm_framebuffer *fb; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); 1168c2ecf20Sopenharmony_ci if (IS_ERR(fb)) 1178c2ecf20Sopenharmony_ci return ERR_CAST(fb); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return fb; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_civoid rockchip_drm_mode_config_init(struct drm_device *dev) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci dev->mode_config.min_width = 0; 1258c2ecf20Sopenharmony_ci dev->mode_config.min_height = 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * set max width and height as default value(4096x4096). 1298c2ecf20Sopenharmony_ci * this value would be used to check framebuffer size limitation 1308c2ecf20Sopenharmony_ci * at drm_mode_addfb(). 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci dev->mode_config.max_width = 4096; 1338c2ecf20Sopenharmony_ci dev->mode_config.max_height = 4096; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci dev->mode_config.funcs = &rockchip_drm_mode_config_funcs; 1368c2ecf20Sopenharmony_ci dev->mode_config.helper_private = &rockchip_mode_config_helpers; 1378c2ecf20Sopenharmony_ci} 138