diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 8c3348dd7b78..2ef222a882a7 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -37,6 +37,11 @@ config ROCKCHIP_DRM_DEBUG cat /d/dri/0/ff900000.vop/vop_dump/dump get more help the upper ff900000.vop is different at different SOC platform. +config ROCKCHIP_DRM_DIRECT_SHOW + bool "Rockchip DRM direct show" + help + This is a quick display scheme api in kernel space. + config ROCKCHIP_VOP bool "Rockchip VOP driver" default y if (CPU_RK3036 || CPU_RK30XX || CPU_RK312X || \ diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 4dba77351291..8a9f5b6f7d57 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -11,6 +11,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_VOP2) += rockchip_drm_vop2.o rockchip_vop2_reg.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_DRM_DEBUG) += rockchip_drm_debugfs.o +rockchipdrm-$(CONFIG_ROCKCHIP_DRM_DIRECT_SHOW) += rockchip_drm_direct_show.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c new file mode 100644 index 000000000000..a4799985add0 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + * Author: Sandy Huang + */ +#include +#include +#include + +#include "../drm_internal.h" +#include "rockchip_drm_direct_show.h" + +static int drm_ds_debug; +#define DRM_DS_DBG(format, ...) do { \ + if (drm_ds_debug) \ + pr_info("DRM_DS: %s(%d): " format, __func__, __LINE__, ## __VA_ARGS__); \ + } while (0) + +#define DRM_DS_ERR(format, ...) \ + pr_info("ERR: DRM_DS: %s(%d): " format, __func__, __LINE__, ## __VA_ARGS__) + +struct drm_device *rockchip_drm_get_dev(void) +{ + int i; + char *name = "rockchip"; + + for (i = 0; i < 64; i++) { + struct drm_minor *minor; + + minor = drm_minor_acquire(i + DRM_MINOR_PRIMARY); + if (IS_ERR(minor)) + continue; + if (!minor->dev || !minor->dev->driver || + !minor->dev->driver->name) + continue; + if (!name) + return minor->dev; + if (!strcmp(name, minor->dev->driver->name)) + return minor->dev; + } + + return NULL; +} + +static int rockchip_drm_direct_show_alloc_fb(struct drm_device *drm, + struct rockchip_drm_direct_show_buffer *buffer) +{ + struct drm_gem_object *obj; + struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER]; + struct drm_mode_fb_cmd2 mode_cmd = { 0 }; + struct drm_framebuffer *fb; + const struct drm_format_info *format_info = drm_format_info(buffer->pixel_format); + + mode_cmd.offsets[0] = 0; + mode_cmd.width = buffer->width; + mode_cmd.height = buffer->height; + mode_cmd.pitches[0] = buffer->pitch[0]; + mode_cmd.pixel_format = buffer->pixel_format; + obj = &buffer->rk_gem_obj->base; + objs[0] = obj; + + if (format_info->is_yuv) { + mode_cmd.offsets[1] = buffer->width * buffer->height; + mode_cmd.pitches[1] = mode_cmd.pitches[0]; + objs[1] = obj; + } + + fb = rockchip_fb_alloc(drm, &mode_cmd, objs, format_info->num_planes); + if (IS_ERR_OR_NULL(fb)) + return -ENOMEM; + + buffer->fb = fb; + + return 0; +} + +int rockchip_drm_direct_show_alloc_buffer(struct drm_device *drm, + struct rockchip_drm_direct_show_buffer *buffer) +{ + u32 min_pitch; + const struct drm_format_info *format_info; + struct drm_mode_create_dumb args; + struct rockchip_gem_object *rk_obj; + struct drm_gem_object *obj; + struct dma_buf *dmabuf; + int dmabuf_fd; + + args.width = buffer->width; + args.height = buffer->height; + format_info = drm_format_info(buffer->pixel_format); + args.bpp = rockchip_drm_get_bpp(format_info); + min_pitch = args.width * DIV_ROUND_UP(args.bpp, 8); + args.pitch = ALIGN(min_pitch, 64); + args.size = args.pitch * args.height; + args.flags = buffer->flag; + + if (format_info->is_yuv) { + int bpp = 0; + + bpp = format_info->cpp[1] * 8; + min_pitch = args.width * DIV_ROUND_UP(bpp, 8); + min_pitch = ALIGN(min_pitch, 64); + args.size += min_pitch * args.height / format_info->hsub / format_info->vsub; + } + /* create a gem obj with kmap flag */ + rk_obj = rockchip_gem_create_object(drm, args.size, true, args.flags); + if (IS_ERR(rk_obj)) { + DRM_DS_ERR("create rk_obj failed\n"); + return -ENOMEM; + } + obj = &rk_obj->base; + + buffer->bpp = args.bpp; + buffer->pitch[0] = args.pitch; + buffer->vir_addr[0] = rk_obj->kvaddr; + buffer->phy_addr[0] = rk_obj->dma_handle; + buffer->rk_gem_obj = rk_obj; + if (format_info->is_yuv) { + buffer->vir_addr[1] = buffer->vir_addr[0] + buffer->width * buffer->height; + buffer->pitch[1] = buffer->pitch[0]; + buffer->phy_addr[1] = buffer->phy_addr[0] + buffer->width * buffer->height; + } + + /* to get drm fb */ + rockchip_drm_direct_show_alloc_fb(drm, buffer); + + /* to get dma buffer fd */ + mutex_lock(&drm->object_name_lock); + dmabuf = drm->driver->gem_prime_export(obj, 0); + if (IS_ERR(dmabuf)) { + mutex_unlock(&drm->object_name_lock); + goto err_gem_free; + } + get_dma_buf(dmabuf); + drm_gem_object_get(obj); + mutex_unlock(&drm->object_name_lock); + + dmabuf_fd = dma_buf_fd(dmabuf, 0); + if (dmabuf_fd < 0) { + DRM_DS_ERR("failed dma_buf_fd, ret %d\n", dmabuf_fd); + goto err_free_dmabuf; + } + buffer->dmabuf_fd = dmabuf_fd; + + DRM_DS_DBG("alloc buffer: 0x%p, dma buf fd:%d, args.pitch:%d\n", buffer->rk_gem_obj, dmabuf_fd, args.pitch); + + return 0; + +err_free_dmabuf: + dma_buf_put(dmabuf); +err_gem_free: + rockchip_gem_free_object(&rk_obj->base); + + return -ENOMEM; +} + +void rockchip_drm_direct_show_free_buffer(struct drm_device *drm, + struct rockchip_drm_direct_show_buffer *buffer) +{ + struct dma_buf *dmabuf; + + DRM_DS_DBG("free buffer: 0x%p, dma buf fd:%d\n", buffer->rk_gem_obj, buffer->dmabuf_fd); + dmabuf = dma_buf_get(buffer->dmabuf_fd); + dma_buf_put(dmabuf); + __close_fd(current->files, buffer->dmabuf_fd); + rockchip_gem_free_object(&buffer->rk_gem_obj->base); +} + +struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, char *name) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, drm) { + if (!strncmp(plane->name, name, DRM_PROP_NAME_LEN)) + break; + } + if (!plane) { + DRM_DS_ERR("failed to find plane:%s!\n", name); + return NULL; + } + + DRM_DS_DBG("get plane[%s] success\n", plane->name); + + return plane; +} + +struct drm_crtc *rockchip_drm_direct_show_get_crtc(struct drm_device *drm) +{ + struct drm_crtc *crtc = NULL; + bool crtc_active = false; + + drm_for_each_crtc(crtc, drm) { + if (crtc->state && crtc->state->active) { + crtc_active = true; + break; + } + } + + if (crtc_active == false) { + DRM_DS_ERR("failed to find active crtc\n"); + return NULL; + } + DRM_DS_DBG("get crtc[%s] success\n", crtc->name); + + return crtc; +} + +static int +rockchip_drm_direct_show_set_property_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t val) +{ + int i; + + for (i = 0; i < obj->properties->count; i++) { + if (obj->properties->properties[i] == property) { + obj->properties->values[i] = val; + return 0; + } + } + + return -EINVAL; +} + +static struct drm_property * +rockchip_drm_direct_show_find_prop(struct drm_device *dev, + struct drm_mode_object *obj, + char *prop_name) +{ + int i = 0; + + if (!obj->properties) + return NULL; + + for (i = 0; i < obj->properties->count; i++) { + struct drm_property *prop = obj->properties->properties[i]; + + if (!strncmp(prop->name, prop_name, DRM_PROP_NAME_LEN)) + return prop; + } + + return NULL; +} + +int rockchip_drm_direct_show_commit(struct drm_device *drm, + struct rockchip_drm_direct_show_commit_info *commit_info) +{ + int ret = 0; + struct drm_plane *plane = commit_info->plane; + struct drm_crtc *crtc = commit_info->crtc; + struct drm_framebuffer *fb = commit_info->buffer->fb; + struct drm_mode_config *conf = &drm->mode_config; + struct drm_property *zpos_prop; + + /*setplane overlay zpos top*/ + zpos_prop = rockchip_drm_direct_show_find_prop(drm, &plane->base, "zpos"); + if (!zpos_prop) + DRM_DS_ERR("failed to find plane zpos prop, ret:%d\n", ret); + + drm_modeset_lock_all(drm); + /* set the max zpos value */ + if (commit_info->top_zpos && zpos_prop) { + ret = rockchip_drm_direct_show_set_property_value(&plane->base, + zpos_prop, + zpos_prop->values[1]); + if (ret) + DRM_DS_ERR("failed to set plane zpos prop, ret:%d\n", ret); + plane->state->zpos = zpos_prop->values[1]; + } + ret = plane->funcs->update_plane(plane, crtc, fb, + commit_info->dst_x, commit_info->dst_y, + commit_info->dst_w, commit_info->dst_h, + commit_info->src_x << 16, + commit_info->src_y << 16, + commit_info->src_w << 16, + commit_info->src_h << 16, + conf->acquire_ctx); + drm_modeset_unlock_all(drm); + + if (ret) + return ret; + + DRM_DS_DBG("commit success: plane[%s], crtc[%s], src[%dx%d@%dx%d], dst[%dx%d@%dx%d]\n", + plane->name, crtc->name, + commit_info->src_w, commit_info->src_h, + commit_info->src_x, commit_info->src_y, + commit_info->dst_w, commit_info->dst_h, + commit_info->dst_x, commit_info->dst_y); + + return ret; +} + +int rockchip_drm_direct_show_disable_plane(struct drm_device *drm, struct drm_plane *plane) +{ + int ret = 0; + struct drm_mode_config *conf = &drm->mode_config; + + DRM_DS_DBG("disable plane: %s\n", plane->name); + drm_modeset_lock_all(drm); + ret = plane->funcs->disable_plane(plane, conf->acquire_ctx); + drm_modeset_unlock_all(drm); + + return ret; +} diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h new file mode 100644 index 000000000000..14a542fd63e2 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + * Author: Sandy Huang + */ + +#ifndef ROCKCHIP_DRM_DIRECT_SHOW_H +#define ROCKCHIP_DRM_DIRECT_SHOW_H + +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_fb.h" +#include "rockchip_drm_gem.h" + +struct rockchip_drm_direct_show_buffer { + /* input */ + u32 width; + u32 height; + u32 pixel_format; + u32 flag; /* default 0 is scattered buffer, set ROCKCHIP_BO_CONTIG is continue CMA buffer */ + + /* output */ + u32 bpp; /* bits num per pixel */ + u32 pitch[3]; /* byte num for each line */ + void *vir_addr[3]; /* kernel virtual address, default use vir_addr[0] for RGB format */ + dma_addr_t phy_addr[3]; /* physical address when alloc continue cma buffer or secure buffer */ + struct rockchip_gem_object *rk_gem_obj; + struct drm_framebuffer *fb; + int dmabuf_fd; /* export dmabuf_fd used by other module */ +}; + +struct rockchip_drm_direct_show_commit_info { + struct drm_crtc *crtc; + struct drm_plane *plane; + struct rockchip_drm_direct_show_buffer *buffer; + u32 src_x; + u32 src_y; + u32 src_w; + u32 src_h; + u32 dst_x; + u32 dst_y; + u32 dst_w; + u32 dst_h; + bool top_zpos; +}; + +struct drm_device *rockchip_drm_get_dev(void); +int rockchip_drm_direct_show_alloc_buffer(struct drm_device *drm, + struct rockchip_drm_direct_show_buffer *buffer); +void rockchip_drm_direct_show_free_buffer(struct drm_device *drm, + struct rockchip_drm_direct_show_buffer *buffer); +struct drm_crtc *rockchip_drm_direct_show_get_crtc(struct drm_device *drm); +struct drm_plane *rockchip_drm_direct_show_get_plane(struct drm_device *drm, char *name); +int rockchip_drm_direct_show_commit(struct drm_device *drm, + struct rockchip_drm_direct_show_commit_info *commit_info); +int rockchip_drm_direct_show_disable_plane(struct drm_device *drm, struct drm_plane *plane); + +#endif