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_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 32 static 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 48 static 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 59 static const uint64_t format_modifiers[] = { 60 DRM_FORMAT_MOD_LINEAR, 61 DRM_FORMAT_MOD_INVALID, 62 }; 63 64 static 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 101 static 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 */ 142 static 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 228 static 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 238 static 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 248 static 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 }; 258 MODULE_DEVICE_TABLE(of, vop2_dt_match); 259 260 static 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 267 static int vop2_remove(struct platform_device *pdev) 268 { 269 component_del(&pdev->dev, &vop2_component_ops); 270 271 return 0; 272 } 273 274 struct platform_driver vop2_platform_driver = { 275 .probe = vop2_probe, 276 .remove = vop2_remove, 277 .driver = { 278 .name = "rockchip-vop2", 279 .of_match_table = of_match_ptr(vop2_dt_match), 280 }, 281 }; 282