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

644 lines
20 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Phytium display drm driver
*
* Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_fourcc.h>
#include <linux/dma-buf.h>
#include "phytium_display_drv.h"
#include "phytium_plane.h"
#include "phytium_fb.h"
#include "phytium_gem.h"
#include "phytium_crtc.h"
#include "px210_dc.h"
#include "pe220x_dc.h"
#include "phytium_reg.h"
#define PHYTIUM_CURS_W_SIZE 32
#define PHYTIUM_CURS_H_SIZE 32
void phytium_plane_destroy(struct drm_plane *plane)
{
struct phytium_plane *phytium_plane = to_phytium_plane(plane);
drm_plane_cleanup(plane);
kfree(phytium_plane);
}
/**
* phytium_plane_atomic_get_property - fetch plane property value
* @plane: plane to fetch property for
* @state: state containing the property value
* @property: property to look up
* @val: pointer to write property value into
*
* The DRM core does not store shadow copies of properties for
* atomic-capable drivers. This entrypoint is used to fetch
* the current value of a driver-specific plane property.
*/
static int
phytium_plane_atomic_get_property(struct drm_plane *plane,
const struct drm_plane_state *state,
struct drm_property *property,
uint64_t *val)
{
DRM_DEBUG_KMS("Unknown plane property [PROP:%d:%s]\n", property->base.id, property->name);
return -EINVAL;
}
/**
* phytium_plane_atomic_set_property - set plane property value
* @plane: plane to set property for
* @state: state to update property value in
* @property: property to set
* @val: value to set property to
*
* Writes the specified property value for a plane into the provided atomic
* state object.
*
* Returns 0 on success, -EINVAL on unrecognized properties
*/
int
phytium_plane_atomic_set_property(struct drm_plane *plane,
struct drm_plane_state *state,
struct drm_property *property,
uint64_t val)
{
DRM_DEBUG_KMS("Unknown plane property [PROP:%d:%s]\n", property->base.id, property->name);
return -EINVAL;
}
struct drm_plane_state *
phytium_plane_atomic_duplicate_state(struct drm_plane *plane)
{
struct drm_plane_state *state = NULL;
struct phytium_plane_state *phytium_state = NULL;
phytium_state = kmemdup(plane->state, sizeof(*phytium_state), GFP_KERNEL);
if (!phytium_state)
return NULL;
state = &phytium_state->base;
if (state->fb)
drm_framebuffer_get(state->fb);
state->fence = NULL;
state->commit = NULL;
return state;
}
void
phytium_plane_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state)
{
struct phytium_plane_state *phytium_state = to_phytium_plane_state(state);
__drm_atomic_helper_plane_destroy_state(state);
kfree(phytium_state);
}
const struct drm_plane_funcs phytium_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = phytium_plane_destroy,
.reset = drm_atomic_helper_plane_reset,
.atomic_get_property = phytium_plane_atomic_get_property,
.atomic_set_property = phytium_plane_atomic_set_property,
.atomic_duplicate_state = phytium_plane_atomic_duplicate_state,
.atomic_destroy_state = phytium_plane_atomic_destroy_state,
};
static int phytium_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct dma_buf *dma_buf;
struct dma_fence *fence;
if (!state->fb)
return 0;
dma_buf = to_phytium_framebuffer(state->fb)->phytium_gem_obj[0]->base.dma_buf;
if (dma_buf) {
fence = dma_resv_get_excl_rcu(dma_buf->resv);
drm_atomic_set_fence_for_plane(state, fence);
}
return 0;
}
static int
phytium_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
{
struct drm_device *dev = plane->dev;
struct phytium_display_private *priv = dev->dev_private;
struct drm_framebuffer *fb = state->fb;
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state;
int src_x, src_y, src_w, src_h;
unsigned long base_offset;
struct phytium_crtc *phytium_crtc = to_phytium_crtc(crtc);
if ((!fb) || (!crtc))
return 0;
crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
if (plane->type == DRM_PLANE_TYPE_CURSOR) {
src_w = state->src_w >> 16;
src_h = state->src_h >> 16;
if (phytium_crtc->scale_enable)
return -EINVAL;
if ((src_w != PHYTIUM_CURS_W_SIZE) || (src_h != PHYTIUM_CURS_W_SIZE)) {
DRM_INFO("Invalid cursor size(%d, %d)\n", src_w, src_h);
return -EINVAL;
}
} else if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
src_x = state->src_x >> 16;
src_y = state->src_y >> 16;
src_w = state->src_w >> 16;
src_h = state->src_h >> 16;
base_offset = src_x * fb->format->cpp[0] + src_y*fb->pitches[0];
if (base_offset & (priv->info.address_mask)) {
DRM_ERROR("fb base address is not aligned by 0x%lx byte\n",
priv->info.address_mask);
return -EINVAL;
}
if (src_w != state->crtc_w || src_h != state->crtc_h) {
DRM_ERROR("scale not support: crtc_w(0x%x)/h(0x%x) src_w(0x%x)/h(0x%x)\n",
state->crtc_w, state->crtc_h, src_w, src_h);
return -EINVAL;
}
if ((state->crtc_x < 0) || (state->crtc_y < 0)) {
DRM_ERROR("crtc_x(0x%x)/y(0x%x) of drm plane state is invalid\n",
state->crtc_x, state->crtc_y);
return -EINVAL;
}
if ((state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
|| (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)) {
DRM_ERROR("plane out of crtc region\n");
return -EINVAL;
}
}
return 0;
}
static void phytium_dc_get_plane_parameter(struct drm_plane *plane)
{
struct phytium_plane *phytium_plane = to_phytium_plane(plane);
struct drm_framebuffer *fb = plane->state->fb;
struct phytium_framebuffer *phytium_fb = to_phytium_framebuffer(fb);
struct phytium_gem_object *phytium_gem_obj = NULL;
int i, num_planes = 0;
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++) {
phytium_gem_obj = phytium_fb->phytium_gem_obj[i];
phytium_plane->iova[i] = phytium_gem_obj->iova + fb->offsets[i];
phytium_plane->size[i] = phytium_gem_obj->size - fb->offsets[i];
if (fb->modifier == DRM_FORMAT_MOD_PHYTIUM_TILE_MODE0_FBCDC)
phytium_plane->tiling[i] = FRAMEBUFFER_TILE_MODE0;
else if (fb->modifier == DRM_FORMAT_MOD_PHYTIUM_TILE_MODE3_FBCDC)
phytium_plane->tiling[i] = FRAMEBUFFER_TILE_MODE3;
else if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
phytium_plane->tiling[i] = FRAMEBUFFER_LINEAR;
else
phytium_plane->tiling[i] = FRAMEBUFFER_LINEAR;
if (i == 0) {
switch (fb->format->format) {
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_RGBA1010102:
case DRM_FORMAT_BGRA1010102:
phytium_plane->format = FRAMEBUFFER_FORMAT_ARGB2101010;
break;
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_BGRA8888:
phytium_plane->format = FRAMEBUFFER_FORMAT_ARGB8888;
break;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_BGRX8888:
phytium_plane->format = FRAMEBUFFER_FORMAT_XRGB8888;
break;
case DRM_FORMAT_ARGB4444:
case DRM_FORMAT_ABGR4444:
case DRM_FORMAT_RGBA4444:
case DRM_FORMAT_BGRA4444:
phytium_plane->format = FRAMEBUFFER_FORMAT_ARGB4444;
break;
case DRM_FORMAT_XRGB4444:
case DRM_FORMAT_XBGR4444:
case DRM_FORMAT_RGBX4444:
case DRM_FORMAT_BGRX4444:
phytium_plane->format = FRAMEBUFFER_FORMAT_XRGB4444;
break;
case DRM_FORMAT_ARGB1555:
case DRM_FORMAT_ABGR1555:
case DRM_FORMAT_RGBA5551:
case DRM_FORMAT_BGRA5551:
phytium_plane->format = FRAMEBUFFER_FORMAT_ARGB1555;
break;
case DRM_FORMAT_XRGB1555:
case DRM_FORMAT_XBGR1555:
case DRM_FORMAT_RGBX5551:
case DRM_FORMAT_BGRX5551:
phytium_plane->format = FRAMEBUFFER_FORMAT_XRGB1555;
break;
case DRM_FORMAT_RGB565:
case DRM_FORMAT_BGR565:
phytium_plane->format = FRAMEBUFFER_FORMAT_RGB565;
break;
case DRM_FORMAT_YUYV:
phytium_plane->format = FRAMEBUFFER_FORMAT_YUYV;
break;
case DRM_FORMAT_UYVY:
phytium_plane->format = FRAMEBUFFER_FORMAT_UYVY;
break;
case DRM_FORMAT_NV16:
phytium_plane->format = FRAMEBUFFER_FORMAT_NV16;
break;
case DRM_FORMAT_NV12:
phytium_plane->format = FRAMEBUFFER_FORMAT_NV12;
break;
case DRM_FORMAT_NV21:
phytium_plane->format = FRAMEBUFFER_FORMAT_NV12;
break;
default:
DRM_ERROR("unsupported pixel format (format = %d)\n",
fb->format->format);
return;
}
switch (fb->format->format) {
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB4444:
case DRM_FORMAT_XRGB4444:
case DRM_FORMAT_ARGB1555:
case DRM_FORMAT_XRGB1555:
case DRM_FORMAT_RGB565:
phytium_plane->swizzle = FRAMEBUFFER_SWIZZLE_ARGB;
phytium_plane->uv_swizzle = FRAMEBUFFER_UVSWIZZLE_DISABLE;
break;
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR4444:
case DRM_FORMAT_XBGR4444:
case DRM_FORMAT_ABGR1555:
case DRM_FORMAT_XBGR1555:
case DRM_FORMAT_BGR565:
phytium_plane->swizzle = FRAMEBUFFER_SWIZZLE_ABGR;
phytium_plane->uv_swizzle = FRAMEBUFFER_UVSWIZZLE_DISABLE;
break;
case DRM_FORMAT_RGBA1010102:
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA4444:
case DRM_FORMAT_RGBX4444:
case DRM_FORMAT_RGBA5551:
case DRM_FORMAT_RGBX5551:
phytium_plane->swizzle = FRAMEBUFFER_SWIZZLE_RGBA;
phytium_plane->uv_swizzle = FRAMEBUFFER_UVSWIZZLE_DISABLE;
break;
case DRM_FORMAT_BGRA1010102:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA4444:
case DRM_FORMAT_BGRX4444:
case DRM_FORMAT_BGRA5551:
case DRM_FORMAT_BGRX5551:
phytium_plane->swizzle = FRAMEBUFFER_SWIZZLE_BGRA;
phytium_plane->uv_swizzle = FRAMEBUFFER_UVSWIZZLE_DISABLE;
break;
case DRM_FORMAT_YUYV:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV12:
phytium_plane->swizzle = FRAMEBUFFER_SWIZZLE_ARGB;
phytium_plane->uv_swizzle = FRAMEBUFFER_UVSWIZZLE_DISABLE;
break;
default:
DRM_ERROR("unsupported pixel format (format = %d)\n",
fb->format->format);
return;
}
}
}
}
static void phytium_dc_primary_plane_update(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
struct phytium_display_private *priv = dev->dev_private;
struct phytium_plane *phytium_plane = to_phytium_plane(plane);
struct drm_framebuffer *fb = plane->state->fb;
int phys_pipe = phytium_plane->phys_pipe;
int src_x, src_y, crtc_x, crtc_y, crtc_w, crtc_h;
unsigned long base_offset;
int config;
src_x = plane->state->src_x >> 16;
src_y = plane->state->src_y >> 16;
crtc_x = plane->state->crtc_x;
crtc_y = plane->state->crtc_y;
crtc_w = plane->state->crtc_w;
crtc_h = plane->state->crtc_h;
if (phytium_plane->dc_hw_update_dcreq)
phytium_plane->dc_hw_update_dcreq(plane);
phytium_plane->dc_hw_update_primary_hi_addr(plane);
/* config dc */
/* Y */
base_offset = src_x * fb->format->cpp[0] + src_y*fb->pitches[0];
phytium_writel_reg(priv, (phytium_plane->iova[0] + base_offset) & ADDRESS_MASK,
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_FRAMEBUFFER_Y_ADDRESS);
phytium_writel_reg(priv, ALIGN(fb->pitches[0], 128),
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_FRAMEBUFFER_Y_STRIDE);
/* U */
phytium_writel_reg(priv, phytium_plane->iova[1] & 0xffffffff,
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_FRAMEBUFFER_U_ADDRESS);
phytium_writel_reg(priv, ALIGN(fb->pitches[1], 128),
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_FRAMEBUFFER_U_STRIDE);
/* V */
phytium_writel_reg(priv, phytium_plane->iova[2] & 0xffffffff,
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_FRAMEBUFFER_V_ADDRESS);
phytium_writel_reg(priv, ALIGN(fb->pitches[2], 128),
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_FRAMEBUFFER_V_STRIDE);
/* size */
phytium_writel_reg(priv, (crtc_w & WIDTH_MASK) | ((crtc_h&HEIGHT_MASK) << HEIGHT_SHIFT),
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_FRAMEBUFFER_SIZE);
/* config */
config = phytium_readl_reg(priv, priv->dc_reg_base[phys_pipe],
PHYTIUM_DC_FRAMEBUFFER_CONFIG);
config &= ~(FRAMEBUFFER_FORMAT_MASK << FRAMEBUFFER_FORMAT_SHIFT);
config |= (phytium_plane->format << FRAMEBUFFER_FORMAT_SHIFT);
config &= ~(1 << FRAMEBUFFER_UVSWIZZLE_SHIFT);
config |= (phytium_plane->uv_swizzle << FRAMEBUFFER_UVSWIZZLE_SHIFT);
config &= ~(FRAMEBUFFER_SWIZZLE_MASK << FRAMEBUFFER_SWIZZLE_SHIFT);
config |= (phytium_plane->swizzle << FRAMEBUFFER_SWIZZLE_SHIFT);
config &= ~(FRAMEBUFFER_TILE_MODE_MASK << FRAMEBUFFER_TILE_MODE_SHIFT);
config |= (phytium_plane->tiling[0] << FRAMEBUFFER_TILE_MODE_SHIFT);
config &= (~FRAMEBUFFER_CLEAR);
phytium_writel_reg(priv, config, priv->dc_reg_base[phys_pipe],
PHYTIUM_DC_FRAMEBUFFER_CONFIG);
}
static void phytium_dc_cursor_plane_update(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
struct phytium_display_private *priv = dev->dev_private;
struct phytium_plane *phytium_plane = to_phytium_plane(plane);
struct drm_framebuffer *fb = plane->state->fb;
int phys_pipe = phytium_plane->phys_pipe;
int config;
unsigned long iova;
phytium_plane->enable = 1;
phytium_plane->cursor_hot_x = fb->hot_x;
phytium_plane->cursor_hot_y = fb->hot_y;
phytium_plane->cursor_x = plane->state->crtc_x + fb->hot_x;
phytium_plane->cursor_y = plane->state->crtc_y + fb->hot_y;
config = CURSOR_FORMAT_ARGB8888 |
((phytium_plane->cursor_hot_y & CURSOR_HOT_Y_MASK) << CURSOR_HOT_Y_SHIFT) |
((phytium_plane->cursor_hot_x & CURSOR_HOT_X_MASK) << CURSOR_HOT_X_SHIFT);
phytium_writel_reg(priv, config, priv->dc_reg_base[phys_pipe], PHYTIUM_DC_CURSOR_CONFIG);
config = ((phytium_plane->cursor_x & CURSOR_X_MASK) << CURSOR_X_SHIFT) |
((phytium_plane->cursor_y & CURSOR_Y_MASK) << CURSOR_Y_SHIFT);
phytium_writel_reg(priv, config, priv->dc_reg_base[phys_pipe],
PHYTIUM_DC_CURSOR_LOCATION);
iova = phytium_plane->iova[0];
phytium_writel_reg(priv, iova & 0xffffffff, priv->dc_reg_base[phys_pipe],
PHYTIUM_DC_CURSOR_ADDRESS);
if (phytium_plane->dc_hw_update_cursor_hi_addr)
phytium_plane->dc_hw_update_cursor_hi_addr(plane, iova);
}
static void phytium_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct drm_framebuffer *fb, *old_fb;
DRM_DEBUG_KMS("update plane: type=%d\n", plane->type);
if (!plane->state->crtc || !plane->state->fb)
return;
fb = plane->state->fb;
old_fb = old_state->fb;
if (fb)
drm_framebuffer_get(fb);
if (old_fb)
drm_framebuffer_put(old_fb);
phytium_dc_get_plane_parameter(plane);
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
phytium_dc_primary_plane_update(plane);
else if (plane->type == DRM_PLANE_TYPE_CURSOR)
phytium_dc_cursor_plane_update(plane);
}
static void phytium_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct drm_device *dev = plane->dev;
struct phytium_display_private *priv = dev->dev_private;
struct phytium_plane *phytium_plane = to_phytium_plane(plane);
int phys_pipe = phytium_plane->phys_pipe;
int config;
struct drm_framebuffer *old_fb;
old_fb = old_state->fb;
if (old_fb)
drm_framebuffer_put(old_fb);
if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
phytium_writel_reg(priv, CLEAR_VALUE_RED, priv->dc_reg_base[phys_pipe],
PHYTIUM_DC_FRAMEBUFFER_CLEARVALUE);
config = phytium_readl_reg(priv, priv->dc_reg_base[phys_pipe],
PHYTIUM_DC_FRAMEBUFFER_CONFIG);
config |= FRAMEBUFFER_CLEAR;
phytium_writel_reg(priv, config, priv->dc_reg_base[phys_pipe],
PHYTIUM_DC_FRAMEBUFFER_CONFIG);
} else if (plane->type == DRM_PLANE_TYPE_CURSOR) {
phytium_writel_reg(priv, CURSOR_FORMAT_DISABLED,
priv->dc_reg_base[phys_pipe], PHYTIUM_DC_CURSOR_CONFIG);
}
}
const struct drm_plane_helper_funcs phytium_plane_helper_funcs = {
.prepare_fb = phytium_plane_prepare_fb,
.atomic_check = phytium_plane_atomic_check,
.atomic_update = phytium_plane_atomic_update,
.atomic_disable = phytium_plane_atomic_disable,
};
struct phytium_plane *phytium_primary_plane_create(struct drm_device *dev, int phys_pipe)
{
struct phytium_display_private *priv = dev->dev_private;
struct phytium_plane *phytium_plane = NULL;
struct phytium_plane_state *phytium_plane_state = NULL;
int ret = 0;
unsigned int flags = 0;
const uint32_t *formats = NULL;
uint32_t format_count;
const uint64_t *format_modifiers;
phytium_plane = kzalloc(sizeof(*phytium_plane), GFP_KERNEL);
if (!phytium_plane) {
ret = -ENOMEM;
goto failed_malloc_plane;
}
phytium_plane_state = kzalloc(sizeof(*phytium_plane_state), GFP_KERNEL);
if (!phytium_plane_state) {
ret = -ENOMEM;
goto failed_malloc_plane_state;
}
phytium_plane_state->base.plane = &phytium_plane->base;
phytium_plane_state->base.rotation = DRM_MODE_ROTATE_0;
phytium_plane->base.state = &phytium_plane_state->base;
phytium_plane->phys_pipe = phys_pipe;
if (IS_PX210(priv)) {
phytium_plane->dc_hw_plane_get_format = px210_dc_hw_plane_get_primary_format;
phytium_plane->dc_hw_update_dcreq = px210_dc_hw_update_dcreq;
phytium_plane->dc_hw_update_primary_hi_addr = px210_dc_hw_update_primary_hi_addr;
phytium_plane->dc_hw_update_cursor_hi_addr = NULL;
} else if (IS_PE220X(priv)) {
phytium_plane->dc_hw_plane_get_format = pe220x_dc_hw_plane_get_primary_format;
phytium_plane->dc_hw_update_dcreq = NULL;
phytium_plane->dc_hw_update_primary_hi_addr = pe220x_dc_hw_update_primary_hi_addr;
phytium_plane->dc_hw_update_cursor_hi_addr = NULL;
}
phytium_plane->dc_hw_plane_get_format(&format_modifiers, &formats, &format_count);
ret = drm_universal_plane_init(dev, &phytium_plane->base, 0x0,
&phytium_plane_funcs, formats,
format_count,
format_modifiers,
DRM_PLANE_TYPE_PRIMARY, "primary %d", phys_pipe);
if (ret)
goto failed_plane_init;
flags = DRM_MODE_ROTATE_0;
drm_plane_create_rotation_property(&phytium_plane->base, DRM_MODE_ROTATE_0, flags);
drm_plane_helper_add(&phytium_plane->base, &phytium_plane_helper_funcs);
return phytium_plane;
failed_plane_init:
kfree(phytium_plane_state);
failed_malloc_plane_state:
kfree(phytium_plane);
failed_malloc_plane:
return ERR_PTR(ret);
}
struct phytium_plane *phytium_cursor_plane_create(struct drm_device *dev, int phys_pipe)
{
struct phytium_display_private *priv = dev->dev_private;
struct phytium_plane *phytium_plane = NULL;
struct phytium_plane_state *phytium_plane_state = NULL;
int ret = 0;
unsigned int flags = 0;
const uint32_t *formats = NULL;
uint32_t format_count;
const uint64_t *format_modifiers;
phytium_plane = kzalloc(sizeof(*phytium_plane), GFP_KERNEL);
if (!phytium_plane) {
ret = -ENOMEM;
goto failed_malloc_plane;
}
phytium_plane_state = kzalloc(sizeof(*phytium_plane_state), GFP_KERNEL);
if (!phytium_plane_state) {
ret = -ENOMEM;
goto failed_malloc_plane_state;
}
phytium_plane_state->base.plane = &phytium_plane->base;
phytium_plane_state->base.rotation = DRM_MODE_ROTATE_0;
phytium_plane->base.state = &phytium_plane_state->base;
phytium_plane->phys_pipe = phys_pipe;
if (IS_PX210(priv)) {
phytium_plane->dc_hw_plane_get_format = px210_dc_hw_plane_get_cursor_format;
phytium_plane->dc_hw_update_dcreq = NULL;
phytium_plane->dc_hw_update_primary_hi_addr = NULL;
phytium_plane->dc_hw_update_cursor_hi_addr = NULL;
} else if (IS_PE220X(priv)) {
phytium_plane->dc_hw_plane_get_format = pe220x_dc_hw_plane_get_cursor_format;
phytium_plane->dc_hw_update_dcreq = NULL;
phytium_plane->dc_hw_update_primary_hi_addr = NULL;
phytium_plane->dc_hw_update_cursor_hi_addr = pe220x_dc_hw_update_cursor_hi_addr;
}
phytium_plane->dc_hw_plane_get_format(&format_modifiers, &formats, &format_count);
ret = drm_universal_plane_init(dev, &phytium_plane->base, 0x0,
&phytium_plane_funcs,
formats, format_count,
format_modifiers,
DRM_PLANE_TYPE_CURSOR, "cursor %d", phys_pipe);
if (ret)
goto failed_plane_init;
flags = DRM_MODE_ROTATE_0;
drm_plane_create_rotation_property(&phytium_plane->base, DRM_MODE_ROTATE_0, flags);
drm_plane_helper_add(&phytium_plane->base, &phytium_plane_helper_funcs);
return phytium_plane;
failed_plane_init:
kfree(phytium_plane_state);
failed_malloc_plane_state:
kfree(phytium_plane);
failed_malloc_plane:
return ERR_PTR(ret);
}