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