OpenCloudOS-Kernel/drivers/gpu/drm/phytium/phytium_fb.c

132 lines
3.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Phytium display drm driver
*
* Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
*/
#include <drm/drm_gem.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_fourcc.h>
#include "phytium_display_drv.h"
#include "phytium_fb.h"
#include "phytium_gem.h"
static int
phytium_fb_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv,
unsigned int *handle)
{
struct phytium_framebuffer *phytium_fb = to_phytium_framebuffer(fb);
return drm_gem_handle_create(file_priv, &phytium_fb->phytium_gem_obj[0]->base, handle);
}
static void phytium_fb_destroy(struct drm_framebuffer *fb)
{
struct phytium_framebuffer *phytium_fb = to_phytium_framebuffer(fb);
int i, num_planes;
struct drm_gem_object *obj = NULL;
const struct drm_format_info *info;
info = drm_format_info(fb->format->format);
num_planes = info ? info->num_planes : 1;
for (i = 0; i < num_planes; i++) {
obj = &phytium_fb->phytium_gem_obj[i]->base;
if (obj)
drm_gem_object_put(obj);
}
drm_framebuffer_cleanup(fb);
kfree(phytium_fb);
}
static struct drm_framebuffer_funcs viv_fb_funcs = {
.create_handle = phytium_fb_create_handle,
.destroy = phytium_fb_destroy,
};
struct phytium_framebuffer *
phytium_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
struct phytium_gem_object **phytium_gem_obj, unsigned int num_planes)
{
struct phytium_framebuffer *phytium_fb;
int ret = 0, i;
phytium_fb = kzalloc(sizeof(*phytium_fb), GFP_KERNEL);
if (!phytium_fb)
return ERR_PTR(-ENOMEM);
drm_helper_mode_fill_fb_struct(dev, &phytium_fb->base, mode_cmd);
ret = drm_framebuffer_init(dev, &phytium_fb->base, &viv_fb_funcs);
if (ret) {
DRM_ERROR("Failed to initialize framebuffer: %d\n", ret);
kfree(phytium_fb);
return ERR_PTR(ret);
}
for (i = 0; i < num_planes; i++) {
phytium_fb->phytium_gem_obj[i] = phytium_gem_obj[i];
phytium_fb->base.obj[i] = &phytium_gem_obj[i]->base;
}
return phytium_fb;
}
struct drm_framebuffer *
phytium_fb_create(struct drm_device *dev, struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
int ret = 0, i, num_planes;
struct drm_gem_object *obj;
unsigned int hsub, vsub, size;
struct phytium_gem_object *phytium_gem_obj[PHYTIUM_FORMAT_MAX_PLANE] = {0};
struct phytium_framebuffer *phytium_fb;
struct phytium_display_private *priv = dev->dev_private;
const struct drm_format_info *info;
info = drm_format_info(mode_cmd->pixel_format);
hsub = info ? info->hsub : 1;
vsub = info ? info->vsub : 1;
num_planes = info ? info->num_planes : 1;
num_planes = min(num_planes, PHYTIUM_FORMAT_MAX_PLANE);
for (i = 0; i < num_planes; i++) {
unsigned int height = mode_cmd->height / (i ? vsub : 1);
size = height * mode_cmd->pitches[i] + mode_cmd->offsets[i];
obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
if (!obj) {
DRM_ERROR("Failed to lookup GEM object\n");
ret = -ENXIO;
goto error;
}
if (obj->size < size) {
drm_gem_object_put(obj);
ret = -EINVAL;
goto error;
}
phytium_gem_obj[i] = to_phytium_gem_obj(obj);
ret = priv->dc_hw_fb_format_check(mode_cmd, i);
if (ret < 0)
goto error;
}
phytium_fb = phytium_fb_alloc(dev, mode_cmd, phytium_gem_obj, i);
if (IS_ERR(phytium_fb)) {
DRM_DEBUG_KMS("phytium_fb_alloc failed\n");
ret = PTR_ERR(phytium_fb);
goto error;
}
return &phytium_fb->base;
error:
for (i--; i >= 0; i--)
drm_gem_object_put(&phytium_gem_obj[i]->base);
return ERR_PTR(ret);
}