162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) Rockchip Electronics Co.Ltd
462306a36Sopenharmony_ci * Author: Andy Yan <andy.yan@rock-chips.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/component.h>
962306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
1362306a36Sopenharmony_ci#include <drm/drm_plane.h>
1462306a36Sopenharmony_ci#include <drm/drm_print.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "rockchip_drm_vop2.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic const uint32_t formats_win_full_10bit[] = {
1962306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888,
2062306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888,
2162306a36Sopenharmony_ci	DRM_FORMAT_XBGR8888,
2262306a36Sopenharmony_ci	DRM_FORMAT_ABGR8888,
2362306a36Sopenharmony_ci	DRM_FORMAT_RGB888,
2462306a36Sopenharmony_ci	DRM_FORMAT_BGR888,
2562306a36Sopenharmony_ci	DRM_FORMAT_RGB565,
2662306a36Sopenharmony_ci	DRM_FORMAT_BGR565,
2762306a36Sopenharmony_ci	DRM_FORMAT_NV12,
2862306a36Sopenharmony_ci	DRM_FORMAT_NV16,
2962306a36Sopenharmony_ci	DRM_FORMAT_NV24,
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const uint32_t formats_win_full_10bit_yuyv[] = {
3362306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888,
3462306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888,
3562306a36Sopenharmony_ci	DRM_FORMAT_XBGR8888,
3662306a36Sopenharmony_ci	DRM_FORMAT_ABGR8888,
3762306a36Sopenharmony_ci	DRM_FORMAT_RGB888,
3862306a36Sopenharmony_ci	DRM_FORMAT_BGR888,
3962306a36Sopenharmony_ci	DRM_FORMAT_RGB565,
4062306a36Sopenharmony_ci	DRM_FORMAT_BGR565,
4162306a36Sopenharmony_ci	DRM_FORMAT_NV12,
4262306a36Sopenharmony_ci	DRM_FORMAT_NV16,
4362306a36Sopenharmony_ci	DRM_FORMAT_NV24,
4462306a36Sopenharmony_ci	DRM_FORMAT_YVYU,
4562306a36Sopenharmony_ci	DRM_FORMAT_VYUY,
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic const uint32_t formats_win_lite[] = {
4962306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888,
5062306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888,
5162306a36Sopenharmony_ci	DRM_FORMAT_XBGR8888,
5262306a36Sopenharmony_ci	DRM_FORMAT_ABGR8888,
5362306a36Sopenharmony_ci	DRM_FORMAT_RGB888,
5462306a36Sopenharmony_ci	DRM_FORMAT_BGR888,
5562306a36Sopenharmony_ci	DRM_FORMAT_RGB565,
5662306a36Sopenharmony_ci	DRM_FORMAT_BGR565,
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const uint64_t format_modifiers[] = {
6062306a36Sopenharmony_ci	DRM_FORMAT_MOD_LINEAR,
6162306a36Sopenharmony_ci	DRM_FORMAT_MOD_INVALID,
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const uint64_t format_modifiers_afbc[] = {
6562306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
6862306a36Sopenharmony_ci				AFBC_FORMAT_MOD_SPARSE),
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
7162306a36Sopenharmony_ci				AFBC_FORMAT_MOD_YTR),
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
7462306a36Sopenharmony_ci				AFBC_FORMAT_MOD_CBR),
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
7762306a36Sopenharmony_ci				AFBC_FORMAT_MOD_YTR |
7862306a36Sopenharmony_ci				AFBC_FORMAT_MOD_SPARSE),
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
8162306a36Sopenharmony_ci				AFBC_FORMAT_MOD_CBR |
8262306a36Sopenharmony_ci				AFBC_FORMAT_MOD_SPARSE),
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
8562306a36Sopenharmony_ci				AFBC_FORMAT_MOD_YTR |
8662306a36Sopenharmony_ci				AFBC_FORMAT_MOD_CBR),
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
8962306a36Sopenharmony_ci				AFBC_FORMAT_MOD_YTR |
9062306a36Sopenharmony_ci				AFBC_FORMAT_MOD_CBR |
9162306a36Sopenharmony_ci				AFBC_FORMAT_MOD_SPARSE),
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* SPLIT mandates SPARSE, RGB modes mandates YTR */
9462306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
9562306a36Sopenharmony_ci				AFBC_FORMAT_MOD_YTR |
9662306a36Sopenharmony_ci				AFBC_FORMAT_MOD_SPARSE |
9762306a36Sopenharmony_ci				AFBC_FORMAT_MOD_SPLIT),
9862306a36Sopenharmony_ci	DRM_FORMAT_MOD_INVALID,
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic const struct vop2_video_port_data rk3568_vop_video_ports[] = {
10262306a36Sopenharmony_ci	{
10362306a36Sopenharmony_ci		.id = 0,
10462306a36Sopenharmony_ci		.feature = VOP_FEATURE_OUTPUT_10BIT,
10562306a36Sopenharmony_ci		.gamma_lut_len = 1024,
10662306a36Sopenharmony_ci		.cubic_lut_len = 9 * 9 * 9,
10762306a36Sopenharmony_ci		.max_output = { 4096, 2304 },
10862306a36Sopenharmony_ci		.pre_scan_max_dly = { 69, 53, 53, 42 },
10962306a36Sopenharmony_ci		.offset = 0xc00,
11062306a36Sopenharmony_ci	}, {
11162306a36Sopenharmony_ci		.id = 1,
11262306a36Sopenharmony_ci		.gamma_lut_len = 1024,
11362306a36Sopenharmony_ci		.max_output = { 2048, 1536 },
11462306a36Sopenharmony_ci		.pre_scan_max_dly = { 40, 40, 40, 40 },
11562306a36Sopenharmony_ci		.offset = 0xd00,
11662306a36Sopenharmony_ci	}, {
11762306a36Sopenharmony_ci		.id = 2,
11862306a36Sopenharmony_ci		.gamma_lut_len = 1024,
11962306a36Sopenharmony_ci		.max_output = { 1920, 1080 },
12062306a36Sopenharmony_ci		.pre_scan_max_dly = { 40, 40, 40, 40 },
12162306a36Sopenharmony_ci		.offset = 0xe00,
12262306a36Sopenharmony_ci	},
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
12762306a36Sopenharmony_ci * Every cluster can work as 4K win or split into two win.
12862306a36Sopenharmony_ci * All win in cluster support AFBCD.
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Every esmart win and smart win support 4 Multi-region.
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci * Scale filter mode:
13362306a36Sopenharmony_ci *
13462306a36Sopenharmony_ci * * Cluster:  bicubic for horizontal scale up, others use bilinear
13562306a36Sopenharmony_ci * * ESmart:
13662306a36Sopenharmony_ci *    * nearest-neighbor/bilinear/bicubic for scale up
13762306a36Sopenharmony_ci *    * nearest-neighbor/bilinear/average for scale down
13862306a36Sopenharmony_ci *
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci * @TODO describe the wind like cpu-map dt nodes;
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cistatic const struct vop2_win_data rk3568_vop_win_data[] = {
14362306a36Sopenharmony_ci	{
14462306a36Sopenharmony_ci		.name = "Smart0-win0",
14562306a36Sopenharmony_ci		.phys_id = ROCKCHIP_VOP2_SMART0,
14662306a36Sopenharmony_ci		.base = 0x1c00,
14762306a36Sopenharmony_ci		.formats = formats_win_lite,
14862306a36Sopenharmony_ci		.nformats = ARRAY_SIZE(formats_win_lite),
14962306a36Sopenharmony_ci		.format_modifiers = format_modifiers,
15062306a36Sopenharmony_ci		.layer_sel_id = 3,
15162306a36Sopenharmony_ci		.supported_rotations = DRM_MODE_REFLECT_Y,
15262306a36Sopenharmony_ci		.type = DRM_PLANE_TYPE_PRIMARY,
15362306a36Sopenharmony_ci		.max_upscale_factor = 8,
15462306a36Sopenharmony_ci		.max_downscale_factor = 8,
15562306a36Sopenharmony_ci		.dly = { 20, 47, 41 },
15662306a36Sopenharmony_ci	}, {
15762306a36Sopenharmony_ci		.name = "Smart1-win0",
15862306a36Sopenharmony_ci		.phys_id = ROCKCHIP_VOP2_SMART1,
15962306a36Sopenharmony_ci		.formats = formats_win_lite,
16062306a36Sopenharmony_ci		.nformats = ARRAY_SIZE(formats_win_lite),
16162306a36Sopenharmony_ci		.format_modifiers = format_modifiers,
16262306a36Sopenharmony_ci		.base = 0x1e00,
16362306a36Sopenharmony_ci		.layer_sel_id = 7,
16462306a36Sopenharmony_ci		.supported_rotations = DRM_MODE_REFLECT_Y,
16562306a36Sopenharmony_ci		.type = DRM_PLANE_TYPE_PRIMARY,
16662306a36Sopenharmony_ci		.max_upscale_factor = 8,
16762306a36Sopenharmony_ci		.max_downscale_factor = 8,
16862306a36Sopenharmony_ci		.dly = { 20, 47, 41 },
16962306a36Sopenharmony_ci	}, {
17062306a36Sopenharmony_ci		.name = "Esmart1-win0",
17162306a36Sopenharmony_ci		.phys_id = ROCKCHIP_VOP2_ESMART1,
17262306a36Sopenharmony_ci		.formats = formats_win_full_10bit_yuyv,
17362306a36Sopenharmony_ci		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
17462306a36Sopenharmony_ci		.format_modifiers = format_modifiers,
17562306a36Sopenharmony_ci		.base = 0x1a00,
17662306a36Sopenharmony_ci		.layer_sel_id = 6,
17762306a36Sopenharmony_ci		.supported_rotations = DRM_MODE_REFLECT_Y,
17862306a36Sopenharmony_ci		.type = DRM_PLANE_TYPE_PRIMARY,
17962306a36Sopenharmony_ci		.max_upscale_factor = 8,
18062306a36Sopenharmony_ci		.max_downscale_factor = 8,
18162306a36Sopenharmony_ci		.dly = { 20, 47, 41 },
18262306a36Sopenharmony_ci	}, {
18362306a36Sopenharmony_ci		.name = "Esmart0-win0",
18462306a36Sopenharmony_ci		.phys_id = ROCKCHIP_VOP2_ESMART0,
18562306a36Sopenharmony_ci		.formats = formats_win_full_10bit_yuyv,
18662306a36Sopenharmony_ci		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
18762306a36Sopenharmony_ci		.format_modifiers = format_modifiers,
18862306a36Sopenharmony_ci		.base = 0x1800,
18962306a36Sopenharmony_ci		.layer_sel_id = 2,
19062306a36Sopenharmony_ci		.supported_rotations = DRM_MODE_REFLECT_Y,
19162306a36Sopenharmony_ci		.type = DRM_PLANE_TYPE_PRIMARY,
19262306a36Sopenharmony_ci		.max_upscale_factor = 8,
19362306a36Sopenharmony_ci		.max_downscale_factor = 8,
19462306a36Sopenharmony_ci		.dly = { 20, 47, 41 },
19562306a36Sopenharmony_ci	}, {
19662306a36Sopenharmony_ci		.name = "Cluster0-win0",
19762306a36Sopenharmony_ci		.phys_id = ROCKCHIP_VOP2_CLUSTER0,
19862306a36Sopenharmony_ci		.base = 0x1000,
19962306a36Sopenharmony_ci		.formats = formats_win_full_10bit,
20062306a36Sopenharmony_ci		.nformats = ARRAY_SIZE(formats_win_full_10bit),
20162306a36Sopenharmony_ci		.format_modifiers = format_modifiers_afbc,
20262306a36Sopenharmony_ci		.layer_sel_id = 0,
20362306a36Sopenharmony_ci		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
20462306a36Sopenharmony_ci					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
20562306a36Sopenharmony_ci		.max_upscale_factor = 4,
20662306a36Sopenharmony_ci		.max_downscale_factor = 4,
20762306a36Sopenharmony_ci		.dly = { 0, 27, 21 },
20862306a36Sopenharmony_ci		.type = DRM_PLANE_TYPE_OVERLAY,
20962306a36Sopenharmony_ci		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
21062306a36Sopenharmony_ci	}, {
21162306a36Sopenharmony_ci		.name = "Cluster1-win0",
21262306a36Sopenharmony_ci		.phys_id = ROCKCHIP_VOP2_CLUSTER1,
21362306a36Sopenharmony_ci		.base = 0x1200,
21462306a36Sopenharmony_ci		.formats = formats_win_full_10bit,
21562306a36Sopenharmony_ci		.nformats = ARRAY_SIZE(formats_win_full_10bit),
21662306a36Sopenharmony_ci		.format_modifiers = format_modifiers_afbc,
21762306a36Sopenharmony_ci		.layer_sel_id = 1,
21862306a36Sopenharmony_ci		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
21962306a36Sopenharmony_ci					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
22062306a36Sopenharmony_ci		.type = DRM_PLANE_TYPE_OVERLAY,
22162306a36Sopenharmony_ci		.max_upscale_factor = 4,
22262306a36Sopenharmony_ci		.max_downscale_factor = 4,
22362306a36Sopenharmony_ci		.dly = { 0, 27, 21 },
22462306a36Sopenharmony_ci		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
22562306a36Sopenharmony_ci	},
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const struct vop2_data rk3566_vop = {
22962306a36Sopenharmony_ci	.nr_vps = 3,
23062306a36Sopenharmony_ci	.max_input = { 4096, 2304 },
23162306a36Sopenharmony_ci	.max_output = { 4096, 2304 },
23262306a36Sopenharmony_ci	.vp = rk3568_vop_video_ports,
23362306a36Sopenharmony_ci	.win = rk3568_vop_win_data,
23462306a36Sopenharmony_ci	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
23562306a36Sopenharmony_ci	.soc_id = 3566,
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic const struct vop2_data rk3568_vop = {
23962306a36Sopenharmony_ci	.nr_vps = 3,
24062306a36Sopenharmony_ci	.max_input = { 4096, 2304 },
24162306a36Sopenharmony_ci	.max_output = { 4096, 2304 },
24262306a36Sopenharmony_ci	.vp = rk3568_vop_video_ports,
24362306a36Sopenharmony_ci	.win = rk3568_vop_win_data,
24462306a36Sopenharmony_ci	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
24562306a36Sopenharmony_ci	.soc_id = 3568,
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic const struct of_device_id vop2_dt_match[] = {
24962306a36Sopenharmony_ci	{
25062306a36Sopenharmony_ci		.compatible = "rockchip,rk3566-vop",
25162306a36Sopenharmony_ci		.data = &rk3566_vop,
25262306a36Sopenharmony_ci	}, {
25362306a36Sopenharmony_ci		.compatible = "rockchip,rk3568-vop",
25462306a36Sopenharmony_ci		.data = &rk3568_vop,
25562306a36Sopenharmony_ci	}, {
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci};
25862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, vop2_dt_match);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int vop2_probe(struct platform_device *pdev)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return component_add(dev, &vop2_component_ops);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic void vop2_remove(struct platform_device *pdev)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	component_del(&pdev->dev, &vop2_component_ops);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistruct platform_driver vop2_platform_driver = {
27362306a36Sopenharmony_ci	.probe = vop2_probe,
27462306a36Sopenharmony_ci	.remove_new = vop2_remove,
27562306a36Sopenharmony_ci	.driver = {
27662306a36Sopenharmony_ci		.name = "rockchip-vop2",
27762306a36Sopenharmony_ci		.of_match_table = of_match_ptr(vop2_dt_match),
27862306a36Sopenharmony_ci	},
27962306a36Sopenharmony_ci};
280