mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
drm/rockchip: drv: add support rockchip drm direct show
Signed-off-by: Sandy Huang <hjc@rock-chips.com> Change-Id: Ibb7628ba06e41a96c7f63ed24dc5ff911b466b43
This commit is contained in:
@@ -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 || \
|
||||
|
||||
@@ -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
|
||||
|
||||
304
drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c
Normal file
304
drivers/gpu/drm/rockchip/rockchip_drm_direct_show.c
Normal file
@@ -0,0 +1,304 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
|
||||
* Author: Sandy Huang <hjc@rock-chips.com>
|
||||
*/
|
||||
#include <linux/dma-buf-cache.h>
|
||||
#include <linux/fdtable.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
65
drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h
Normal file
65
drivers/gpu/drm/rockchip/rockchip_drm_direct_show.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
|
||||
* Author: Sandy Huang <hjc@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef ROCKCHIP_DRM_DIRECT_SHOW_H
|
||||
#define ROCKCHIP_DRM_DIRECT_SHOW_H
|
||||
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#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
|
||||
Reference in New Issue
Block a user