// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd * Author:Mark Yao */ #include #include #include #include #include #include #include #include #include #include "rockchip_drm_drv.h" #include "rockchip_drm_fb.h" #include "rockchip_drm_gem.h" static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { .destroy = drm_gem_fb_destroy, .create_handle = drm_gem_fb_create_handle, .dirty = drm_atomic_helper_dirtyfb, }; static struct drm_framebuffer * rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **obj, unsigned int num_planes) { struct drm_framebuffer *fb; int ret; int i; fb = kzalloc(sizeof(*fb), GFP_KERNEL); if (!fb) return ERR_PTR(-ENOMEM); drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); for (i = 0; i < num_planes; i++) fb->obj[i] = obj[i]; ret = drm_framebuffer_init(dev, fb, &rockchip_drm_fb_funcs); if (ret) { DRM_DEV_ERROR(dev->dev, "Failed to initialize framebuffer: %d\n", ret); kfree(fb); return ERR_PTR(ret); } return fb; } static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; static struct drm_framebuffer * rockchip_fb_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_afbc_framebuffer *afbc_fb; const struct drm_format_info *info; int ret; info = drm_get_format_info(dev, mode_cmd); if (!info) return ERR_PTR(-ENOMEM); afbc_fb = kzalloc(sizeof(*afbc_fb), GFP_KERNEL); if (!afbc_fb) return ERR_PTR(-ENOMEM); ret = drm_gem_fb_init_with_funcs(dev, &afbc_fb->base, file, mode_cmd, &rockchip_drm_fb_funcs); if (ret) { kfree(afbc_fb); return ERR_PTR(ret); } if (drm_is_afbc(mode_cmd->modifier[0])) { int ret, i; ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb); if (ret) { struct drm_gem_object **obj = afbc_fb->base.obj; for (i = 0; i < info->num_planes; ++i) drm_gem_object_put(obj[i]); kfree(afbc_fb); return ERR_PTR(ret); } } return &afbc_fb->base; } static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { .fb_create = rockchip_fb_create, .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; struct drm_framebuffer * rockchip_drm_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { struct drm_framebuffer *fb; fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); if (IS_ERR(fb)) return ERR_CAST(fb); return fb; } void rockchip_drm_mode_config_init(struct drm_device *dev) { dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; /* * set max width and height as default value(4096x4096). * this value would be used to check framebuffer size limitation * at drm_mode_addfb(). */ dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; dev->mode_config.funcs = &rockchip_drm_mode_config_funcs; dev->mode_config.helper_private = &rockchip_mode_config_helpers; dev->mode_config.normalize_zpos = true; }