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