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