Esmart0-win0 could serve as primary plane, so mark it as such. On RK3568 this window will never be used as primary plane, because the three windows at the beginning of the rk3568_vop_win_data[] array will be used. On RK3566 however, two of the windows at the beginning of the rk3568_vop_win_data[] array cannot not be used due to hardware limitations, so without this patch we end up with CRTCs without primary planes when multiple VPs are active. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Tested-by: Chris Morgan <macromorgan@hotmail.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Link: https://patchwork.freedesktop.org/patch/msgid/20220926081643.304759-1-s.hauer@pengutronix.de
282 lines
7.1 KiB
C
282 lines
7.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) Rockchip Electronics Co.Ltd
|
|
* Author: Andy Yan <andy.yan@rock-chips.com>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/component.h>
|
|
#include <linux/mod_devicetable.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of.h>
|
|
#include <drm/drm_fourcc.h>
|
|
#include <drm/drm_plane.h>
|
|
#include <drm/drm_print.h>
|
|
|
|
#include "rockchip_drm_vop2.h"
|
|
|
|
static const uint32_t formats_win_full_10bit[] = {
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGB565,
|
|
DRM_FORMAT_BGR565,
|
|
DRM_FORMAT_NV12,
|
|
DRM_FORMAT_NV16,
|
|
DRM_FORMAT_NV24,
|
|
};
|
|
|
|
static const uint32_t formats_win_full_10bit_yuyv[] = {
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGB565,
|
|
DRM_FORMAT_BGR565,
|
|
DRM_FORMAT_NV12,
|
|
DRM_FORMAT_NV16,
|
|
DRM_FORMAT_NV24,
|
|
DRM_FORMAT_YVYU,
|
|
DRM_FORMAT_VYUY,
|
|
};
|
|
|
|
static const uint32_t formats_win_lite[] = {
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGB565,
|
|
DRM_FORMAT_BGR565,
|
|
};
|
|
|
|
static const uint64_t format_modifiers[] = {
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
DRM_FORMAT_MOD_INVALID,
|
|
};
|
|
|
|
static const uint64_t format_modifiers_afbc[] = {
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
|
|
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_SPARSE),
|
|
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_YTR),
|
|
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_CBR),
|
|
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_SPARSE),
|
|
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_CBR |
|
|
AFBC_FORMAT_MOD_SPARSE),
|
|
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_CBR),
|
|
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_CBR |
|
|
AFBC_FORMAT_MOD_SPARSE),
|
|
|
|
/* SPLIT mandates SPARSE, RGB modes mandates YTR */
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_SPARSE |
|
|
AFBC_FORMAT_MOD_SPLIT),
|
|
DRM_FORMAT_MOD_INVALID,
|
|
};
|
|
|
|
static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
|
|
{
|
|
.id = 0,
|
|
.feature = VOP_FEATURE_OUTPUT_10BIT,
|
|
.gamma_lut_len = 1024,
|
|
.cubic_lut_len = 9 * 9 * 9,
|
|
.max_output = { 4096, 2304 },
|
|
.pre_scan_max_dly = { 69, 53, 53, 42 },
|
|
.offset = 0xc00,
|
|
}, {
|
|
.id = 1,
|
|
.gamma_lut_len = 1024,
|
|
.max_output = { 2048, 1536 },
|
|
.pre_scan_max_dly = { 40, 40, 40, 40 },
|
|
.offset = 0xd00,
|
|
}, {
|
|
.id = 2,
|
|
.gamma_lut_len = 1024,
|
|
.max_output = { 1920, 1080 },
|
|
.pre_scan_max_dly = { 40, 40, 40, 40 },
|
|
.offset = 0xe00,
|
|
},
|
|
};
|
|
|
|
/*
|
|
* rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
|
|
* Every cluster can work as 4K win or split into two win.
|
|
* All win in cluster support AFBCD.
|
|
*
|
|
* Every esmart win and smart win support 4 Multi-region.
|
|
*
|
|
* Scale filter mode:
|
|
*
|
|
* * Cluster: bicubic for horizontal scale up, others use bilinear
|
|
* * ESmart:
|
|
* * nearest-neighbor/bilinear/bicubic for scale up
|
|
* * nearest-neighbor/bilinear/average for scale down
|
|
*
|
|
*
|
|
* @TODO describe the wind like cpu-map dt nodes;
|
|
*/
|
|
static const struct vop2_win_data rk3568_vop_win_data[] = {
|
|
{
|
|
.name = "Smart0-win0",
|
|
.phys_id = ROCKCHIP_VOP2_SMART0,
|
|
.base = 0x1c00,
|
|
.formats = formats_win_lite,
|
|
.nformats = ARRAY_SIZE(formats_win_lite),
|
|
.format_modifiers = format_modifiers,
|
|
.layer_sel_id = 3,
|
|
.supported_rotations = DRM_MODE_REFLECT_Y,
|
|
.type = DRM_PLANE_TYPE_PRIMARY,
|
|
.max_upscale_factor = 8,
|
|
.max_downscale_factor = 8,
|
|
.dly = { 20, 47, 41 },
|
|
}, {
|
|
.name = "Smart1-win0",
|
|
.phys_id = ROCKCHIP_VOP2_SMART1,
|
|
.formats = formats_win_lite,
|
|
.nformats = ARRAY_SIZE(formats_win_lite),
|
|
.format_modifiers = format_modifiers,
|
|
.base = 0x1e00,
|
|
.layer_sel_id = 7,
|
|
.supported_rotations = DRM_MODE_REFLECT_Y,
|
|
.type = DRM_PLANE_TYPE_PRIMARY,
|
|
.max_upscale_factor = 8,
|
|
.max_downscale_factor = 8,
|
|
.dly = { 20, 47, 41 },
|
|
}, {
|
|
.name = "Esmart1-win0",
|
|
.phys_id = ROCKCHIP_VOP2_ESMART1,
|
|
.formats = formats_win_full_10bit_yuyv,
|
|
.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
|
|
.format_modifiers = format_modifiers,
|
|
.base = 0x1a00,
|
|
.layer_sel_id = 6,
|
|
.supported_rotations = DRM_MODE_REFLECT_Y,
|
|
.type = DRM_PLANE_TYPE_PRIMARY,
|
|
.max_upscale_factor = 8,
|
|
.max_downscale_factor = 8,
|
|
.dly = { 20, 47, 41 },
|
|
}, {
|
|
.name = "Esmart0-win0",
|
|
.phys_id = ROCKCHIP_VOP2_ESMART0,
|
|
.formats = formats_win_full_10bit_yuyv,
|
|
.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
|
|
.format_modifiers = format_modifiers,
|
|
.base = 0x1800,
|
|
.layer_sel_id = 2,
|
|
.supported_rotations = DRM_MODE_REFLECT_Y,
|
|
.type = DRM_PLANE_TYPE_PRIMARY,
|
|
.max_upscale_factor = 8,
|
|
.max_downscale_factor = 8,
|
|
.dly = { 20, 47, 41 },
|
|
}, {
|
|
.name = "Cluster0-win0",
|
|
.phys_id = ROCKCHIP_VOP2_CLUSTER0,
|
|
.base = 0x1000,
|
|
.formats = formats_win_full_10bit,
|
|
.nformats = ARRAY_SIZE(formats_win_full_10bit),
|
|
.format_modifiers = format_modifiers_afbc,
|
|
.layer_sel_id = 0,
|
|
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
|
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
|
.max_upscale_factor = 4,
|
|
.max_downscale_factor = 4,
|
|
.dly = { 0, 27, 21 },
|
|
.type = DRM_PLANE_TYPE_OVERLAY,
|
|
.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
|
|
}, {
|
|
.name = "Cluster1-win0",
|
|
.phys_id = ROCKCHIP_VOP2_CLUSTER1,
|
|
.base = 0x1200,
|
|
.formats = formats_win_full_10bit,
|
|
.nformats = ARRAY_SIZE(formats_win_full_10bit),
|
|
.format_modifiers = format_modifiers_afbc,
|
|
.layer_sel_id = 1,
|
|
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
|
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
|
.type = DRM_PLANE_TYPE_OVERLAY,
|
|
.max_upscale_factor = 4,
|
|
.max_downscale_factor = 4,
|
|
.dly = { 0, 27, 21 },
|
|
.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
|
|
},
|
|
};
|
|
|
|
static const struct vop2_data rk3566_vop = {
|
|
.nr_vps = 3,
|
|
.max_input = { 4096, 2304 },
|
|
.max_output = { 4096, 2304 },
|
|
.vp = rk3568_vop_video_ports,
|
|
.win = rk3568_vop_win_data,
|
|
.win_size = ARRAY_SIZE(rk3568_vop_win_data),
|
|
.soc_id = 3566,
|
|
};
|
|
|
|
static const struct vop2_data rk3568_vop = {
|
|
.nr_vps = 3,
|
|
.max_input = { 4096, 2304 },
|
|
.max_output = { 4096, 2304 },
|
|
.vp = rk3568_vop_video_ports,
|
|
.win = rk3568_vop_win_data,
|
|
.win_size = ARRAY_SIZE(rk3568_vop_win_data),
|
|
.soc_id = 3568,
|
|
};
|
|
|
|
static const struct of_device_id vop2_dt_match[] = {
|
|
{
|
|
.compatible = "rockchip,rk3566-vop",
|
|
.data = &rk3566_vop,
|
|
}, {
|
|
.compatible = "rockchip,rk3568-vop",
|
|
.data = &rk3568_vop,
|
|
}, {
|
|
},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, vop2_dt_match);
|
|
|
|
static int vop2_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
|
|
return component_add(dev, &vop2_component_ops);
|
|
}
|
|
|
|
static int vop2_remove(struct platform_device *pdev)
|
|
{
|
|
component_del(&pdev->dev, &vop2_component_ops);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct platform_driver vop2_platform_driver = {
|
|
.probe = vop2_probe,
|
|
.remove = vop2_remove,
|
|
.driver = {
|
|
.name = "rockchip-vop2",
|
|
.of_match_table = of_match_ptr(vop2_dt_match),
|
|
},
|
|
};
|