1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) Rockchip Electronics Co.Ltd
4 * Author: Andy Yan <andy.yan@rock-chips.com>
5 */
6
7#include <linux/kernel.h>
8#include <linux/component.h>
9#include <linux/mod_devicetable.h>
10#include <linux/platform_device.h>
11#include <linux/of.h>
12#include <drm/drm_fourcc.h>
13#include <drm/drm_plane.h>
14#include <drm/drm_print.h>
15
16#include "rockchip_drm_vop2.h"
17
18static const uint32_t formats_win_full_10bit[] = {
19	DRM_FORMAT_XRGB8888,
20	DRM_FORMAT_ARGB8888,
21	DRM_FORMAT_XBGR8888,
22	DRM_FORMAT_ABGR8888,
23	DRM_FORMAT_RGB888,
24	DRM_FORMAT_BGR888,
25	DRM_FORMAT_RGB565,
26	DRM_FORMAT_BGR565,
27	DRM_FORMAT_NV12,
28	DRM_FORMAT_NV16,
29	DRM_FORMAT_NV24,
30};
31
32static const uint32_t formats_win_full_10bit_yuyv[] = {
33	DRM_FORMAT_XRGB8888,
34	DRM_FORMAT_ARGB8888,
35	DRM_FORMAT_XBGR8888,
36	DRM_FORMAT_ABGR8888,
37	DRM_FORMAT_RGB888,
38	DRM_FORMAT_BGR888,
39	DRM_FORMAT_RGB565,
40	DRM_FORMAT_BGR565,
41	DRM_FORMAT_NV12,
42	DRM_FORMAT_NV16,
43	DRM_FORMAT_NV24,
44	DRM_FORMAT_YVYU,
45	DRM_FORMAT_VYUY,
46};
47
48static const uint32_t formats_win_lite[] = {
49	DRM_FORMAT_XRGB8888,
50	DRM_FORMAT_ARGB8888,
51	DRM_FORMAT_XBGR8888,
52	DRM_FORMAT_ABGR8888,
53	DRM_FORMAT_RGB888,
54	DRM_FORMAT_BGR888,
55	DRM_FORMAT_RGB565,
56	DRM_FORMAT_BGR565,
57};
58
59static const uint64_t format_modifiers[] = {
60	DRM_FORMAT_MOD_LINEAR,
61	DRM_FORMAT_MOD_INVALID,
62};
63
64static const uint64_t format_modifiers_afbc[] = {
65	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
66
67	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
68				AFBC_FORMAT_MOD_SPARSE),
69
70	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
71				AFBC_FORMAT_MOD_YTR),
72
73	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
74				AFBC_FORMAT_MOD_CBR),
75
76	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
77				AFBC_FORMAT_MOD_YTR |
78				AFBC_FORMAT_MOD_SPARSE),
79
80	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
81				AFBC_FORMAT_MOD_CBR |
82				AFBC_FORMAT_MOD_SPARSE),
83
84	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
85				AFBC_FORMAT_MOD_YTR |
86				AFBC_FORMAT_MOD_CBR),
87
88	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
89				AFBC_FORMAT_MOD_YTR |
90				AFBC_FORMAT_MOD_CBR |
91				AFBC_FORMAT_MOD_SPARSE),
92
93	/* SPLIT mandates SPARSE, RGB modes mandates YTR */
94	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
95				AFBC_FORMAT_MOD_YTR |
96				AFBC_FORMAT_MOD_SPARSE |
97				AFBC_FORMAT_MOD_SPLIT),
98	DRM_FORMAT_MOD_INVALID,
99};
100
101static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
102	{
103		.id = 0,
104		.feature = VOP_FEATURE_OUTPUT_10BIT,
105		.gamma_lut_len = 1024,
106		.cubic_lut_len = 9 * 9 * 9,
107		.max_output = { 4096, 2304 },
108		.pre_scan_max_dly = { 69, 53, 53, 42 },
109		.offset = 0xc00,
110	}, {
111		.id = 1,
112		.gamma_lut_len = 1024,
113		.max_output = { 2048, 1536 },
114		.pre_scan_max_dly = { 40, 40, 40, 40 },
115		.offset = 0xd00,
116	}, {
117		.id = 2,
118		.gamma_lut_len = 1024,
119		.max_output = { 1920, 1080 },
120		.pre_scan_max_dly = { 40, 40, 40, 40 },
121		.offset = 0xe00,
122	},
123};
124
125/*
126 * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
127 * Every cluster can work as 4K win or split into two win.
128 * All win in cluster support AFBCD.
129 *
130 * Every esmart win and smart win support 4 Multi-region.
131 *
132 * Scale filter mode:
133 *
134 * * Cluster:  bicubic for horizontal scale up, others use bilinear
135 * * ESmart:
136 *    * nearest-neighbor/bilinear/bicubic for scale up
137 *    * nearest-neighbor/bilinear/average for scale down
138 *
139 *
140 * @TODO describe the wind like cpu-map dt nodes;
141 */
142static const struct vop2_win_data rk3568_vop_win_data[] = {
143	{
144		.name = "Smart0-win0",
145		.phys_id = ROCKCHIP_VOP2_SMART0,
146		.base = 0x1c00,
147		.formats = formats_win_lite,
148		.nformats = ARRAY_SIZE(formats_win_lite),
149		.format_modifiers = format_modifiers,
150		.layer_sel_id = 3,
151		.supported_rotations = DRM_MODE_REFLECT_Y,
152		.type = DRM_PLANE_TYPE_PRIMARY,
153		.max_upscale_factor = 8,
154		.max_downscale_factor = 8,
155		.dly = { 20, 47, 41 },
156	}, {
157		.name = "Smart1-win0",
158		.phys_id = ROCKCHIP_VOP2_SMART1,
159		.formats = formats_win_lite,
160		.nformats = ARRAY_SIZE(formats_win_lite),
161		.format_modifiers = format_modifiers,
162		.base = 0x1e00,
163		.layer_sel_id = 7,
164		.supported_rotations = DRM_MODE_REFLECT_Y,
165		.type = DRM_PLANE_TYPE_PRIMARY,
166		.max_upscale_factor = 8,
167		.max_downscale_factor = 8,
168		.dly = { 20, 47, 41 },
169	}, {
170		.name = "Esmart1-win0",
171		.phys_id = ROCKCHIP_VOP2_ESMART1,
172		.formats = formats_win_full_10bit_yuyv,
173		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
174		.format_modifiers = format_modifiers,
175		.base = 0x1a00,
176		.layer_sel_id = 6,
177		.supported_rotations = DRM_MODE_REFLECT_Y,
178		.type = DRM_PLANE_TYPE_PRIMARY,
179		.max_upscale_factor = 8,
180		.max_downscale_factor = 8,
181		.dly = { 20, 47, 41 },
182	}, {
183		.name = "Esmart0-win0",
184		.phys_id = ROCKCHIP_VOP2_ESMART0,
185		.formats = formats_win_full_10bit_yuyv,
186		.nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
187		.format_modifiers = format_modifiers,
188		.base = 0x1800,
189		.layer_sel_id = 2,
190		.supported_rotations = DRM_MODE_REFLECT_Y,
191		.type = DRM_PLANE_TYPE_PRIMARY,
192		.max_upscale_factor = 8,
193		.max_downscale_factor = 8,
194		.dly = { 20, 47, 41 },
195	}, {
196		.name = "Cluster0-win0",
197		.phys_id = ROCKCHIP_VOP2_CLUSTER0,
198		.base = 0x1000,
199		.formats = formats_win_full_10bit,
200		.nformats = ARRAY_SIZE(formats_win_full_10bit),
201		.format_modifiers = format_modifiers_afbc,
202		.layer_sel_id = 0,
203		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
204					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
205		.max_upscale_factor = 4,
206		.max_downscale_factor = 4,
207		.dly = { 0, 27, 21 },
208		.type = DRM_PLANE_TYPE_OVERLAY,
209		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
210	}, {
211		.name = "Cluster1-win0",
212		.phys_id = ROCKCHIP_VOP2_CLUSTER1,
213		.base = 0x1200,
214		.formats = formats_win_full_10bit,
215		.nformats = ARRAY_SIZE(formats_win_full_10bit),
216		.format_modifiers = format_modifiers_afbc,
217		.layer_sel_id = 1,
218		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
219					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
220		.type = DRM_PLANE_TYPE_OVERLAY,
221		.max_upscale_factor = 4,
222		.max_downscale_factor = 4,
223		.dly = { 0, 27, 21 },
224		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
225	},
226};
227
228static const struct vop2_data rk3566_vop = {
229	.nr_vps = 3,
230	.max_input = { 4096, 2304 },
231	.max_output = { 4096, 2304 },
232	.vp = rk3568_vop_video_ports,
233	.win = rk3568_vop_win_data,
234	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
235	.soc_id = 3566,
236};
237
238static const struct vop2_data rk3568_vop = {
239	.nr_vps = 3,
240	.max_input = { 4096, 2304 },
241	.max_output = { 4096, 2304 },
242	.vp = rk3568_vop_video_ports,
243	.win = rk3568_vop_win_data,
244	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
245	.soc_id = 3568,
246};
247
248static const struct of_device_id vop2_dt_match[] = {
249	{
250		.compatible = "rockchip,rk3566-vop",
251		.data = &rk3566_vop,
252	}, {
253		.compatible = "rockchip,rk3568-vop",
254		.data = &rk3568_vop,
255	}, {
256	},
257};
258MODULE_DEVICE_TABLE(of, vop2_dt_match);
259
260static int vop2_probe(struct platform_device *pdev)
261{
262	struct device *dev = &pdev->dev;
263
264	return component_add(dev, &vop2_component_ops);
265}
266
267static void vop2_remove(struct platform_device *pdev)
268{
269	component_del(&pdev->dev, &vop2_component_ops);
270}
271
272struct platform_driver vop2_platform_driver = {
273	.probe = vop2_probe,
274	.remove_new = vop2_remove,
275	.driver = {
276		.name = "rockchip-vop2",
277		.of_match_table = of_match_ptr(vop2_dt_match),
278	},
279};
280