1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2016 BayLibre, SAS 4 * Author: Neil Armstrong <narmstrong@baylibre.com> 5 * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 6 * Copyright (C) 2014 Endless Mobile 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <drm/drmP.h> 12 #include "meson_drv.h" 13 #include "meson_viu.h" 14 #include "meson_vpp.h" 15 #include "meson_venc.h" 16 #include "meson_registers.h" 17 18 /** 19 * DOC: Video Input Unit 20 * 21 * VIU Handles the Pixel scanout and the basic Colorspace conversions 22 * We handle the following features : 23 * 24 * - OSD1 RGB565/RGB888/xRGB8888 scanout 25 * - RGB conversion to x/cb/cr 26 * - Progressive or Interlace buffer scanout 27 * - OSD1 Commit on Vsync 28 * - HDR OSD matrix for GXL/GXM 29 * 30 * What is missing : 31 * 32 * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes 33 * - YUV4:2:2 Y0CbY1Cr scanout 34 * - Conversion to YUV 4:4:4 from 4:2:2 input 35 * - Colorkey Alpha matching 36 * - Big endian scanout 37 * - X/Y reverse scanout 38 * - Global alpha setup 39 * - OSD2 support, would need interlace switching on vsync 40 * - OSD1 full scaling to support TV overscan 41 */ 42 43 /* OSD csc defines */ 44 45 enum viu_matrix_sel_e { 46 VIU_MATRIX_OSD_EOTF = 0, 47 VIU_MATRIX_OSD, 48 }; 49 50 enum viu_lut_sel_e { 51 VIU_LUT_OSD_EOTF = 0, 52 VIU_LUT_OSD_OETF, 53 }; 54 55 #define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2)) 56 #define MATRIX_5X3_COEF_SIZE 24 57 58 #define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2)) 59 #define EOTF_COEFF_SIZE 10 60 #define EOTF_COEFF_RIGHTSHIFT 1 61 62 static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = { 63 0, 0, 0, /* pre offset */ 64 COEFF_NORM(0.181873), COEFF_NORM(0.611831), COEFF_NORM(0.061765), 65 COEFF_NORM(-0.100251), COEFF_NORM(-0.337249), COEFF_NORM(0.437500), 66 COEFF_NORM(0.437500), COEFF_NORM(-0.397384), COEFF_NORM(-0.040116), 67 0, 0, 0, /* 10'/11'/12' */ 68 0, 0, 0, /* 20'/21'/22' */ 69 64, 512, 512, /* offset */ 70 0, 0, 0 /* mode, right_shift, clip_en */ 71 }; 72 73 /* eotf matrix: bypass */ 74 static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { 75 EOTF_COEFF_NORM(1.0), EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(0.0), 76 EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(1.0), EOTF_COEFF_NORM(0.0), 77 EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(1.0), 78 EOTF_COEFF_RIGHTSHIFT /* right shift */ 79 }; 80 81 static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, 82 int *m, bool csc_on) 83 { 84 /* VPP WRAP OSD1 matrix */ 85 writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), 86 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1)); 87 writel(m[2] & 0xfff, 88 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2)); 89 writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), 90 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01)); 91 writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), 92 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10)); 93 writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), 94 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12)); 95 writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), 96 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21)); 97 writel((m[11] & 0x1fff) << 16, 98 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22)); 99 100 writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff), 101 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1)); 102 writel(m[20] & 0xfff, 103 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2)); 104 105 writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, 106 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); 107 } 108 109 static void meson_viu_set_osd_matrix(struct meson_drm *priv, 110 enum viu_matrix_sel_e m_select, 111 int *m, bool csc_on) 112 { 113 if (m_select == VIU_MATRIX_OSD) { 114 /* osd matrix, VIU_MATRIX_0 */ 115 writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), 116 priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1)); 117 writel(m[2] & 0xfff, 118 priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2)); 119 writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), 120 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01)); 121 writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), 122 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10)); 123 writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), 124 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12)); 125 writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), 126 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21)); 127 128 if (m[21]) { 129 writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff), 130 priv->io_base + 131 _REG(VIU_OSD1_MATRIX_COEF22_30)); 132 writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff), 133 priv->io_base + 134 _REG(VIU_OSD1_MATRIX_COEF31_32)); 135 writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff), 136 priv->io_base + 137 _REG(VIU_OSD1_MATRIX_COEF40_41)); 138 writel(m[17] & 0x1fff, priv->io_base + 139 _REG(VIU_OSD1_MATRIX_COLMOD_COEF42)); 140 } else 141 writel((m[11] & 0x1fff) << 16, priv->io_base + 142 _REG(VIU_OSD1_MATRIX_COEF22_30)); 143 144 writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff), 145 priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1)); 146 writel(m[20] & 0xfff, 147 priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2)); 148 149 writel_bits_relaxed(3 << 30, m[21] << 30, 150 priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42)); 151 writel_bits_relaxed(7 << 16, m[22] << 16, 152 priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42)); 153 154 /* 23 reserved for clipping control */ 155 writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, 156 priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL)); 157 writel_bits_relaxed(BIT(1), 0, 158 priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL)); 159 } else if (m_select == VIU_MATRIX_OSD_EOTF) { 160 int i; 161 162 /* osd eotf matrix, VIU_MATRIX_OSD_EOTF */ 163 for (i = 0; i < 5; i++) 164 writel(((m[i * 2] & 0x1fff) << 16) | 165 (m[i * 2 + 1] & 0x1fff), priv->io_base + 166 _REG(VIU_OSD1_EOTF_CTL + i + 1)); 167 168 writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0, 169 priv->io_base + _REG(VIU_OSD1_EOTF_CTL)); 170 writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0, 171 priv->io_base + _REG(VIU_OSD1_EOTF_CTL)); 172 } 173 } 174 175 #define OSD_EOTF_LUT_SIZE 33 176 #define OSD_OETF_LUT_SIZE 41 177 178 static void 179 meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, 180 unsigned int *r_map, unsigned int *g_map, 181 unsigned int *b_map, bool csc_on) 182 { 183 unsigned int addr_port; 184 unsigned int data_port; 185 unsigned int ctrl_port; 186 int i; 187 188 if (lut_sel == VIU_LUT_OSD_EOTF) { 189 addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT; 190 data_port = VIU_OSD1_EOTF_LUT_DATA_PORT; 191 ctrl_port = VIU_OSD1_EOTF_CTL; 192 } else if (lut_sel == VIU_LUT_OSD_OETF) { 193 addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT; 194 data_port = VIU_OSD1_OETF_LUT_DATA_PORT; 195 ctrl_port = VIU_OSD1_OETF_CTL; 196 } else 197 return; 198 199 if (lut_sel == VIU_LUT_OSD_OETF) { 200 writel(0, priv->io_base + _REG(addr_port)); 201 202 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++) 203 writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16), 204 priv->io_base + _REG(data_port)); 205 206 writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16), 207 priv->io_base + _REG(data_port)); 208 209 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++) 210 writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16), 211 priv->io_base + _REG(data_port)); 212 213 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++) 214 writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16), 215 priv->io_base + _REG(data_port)); 216 217 writel(b_map[OSD_OETF_LUT_SIZE - 1], 218 priv->io_base + _REG(data_port)); 219 220 if (csc_on) 221 writel_bits_relaxed(0x7 << 29, 7 << 29, 222 priv->io_base + _REG(ctrl_port)); 223 else 224 writel_bits_relaxed(0x7 << 29, 0, 225 priv->io_base + _REG(ctrl_port)); 226 } else if (lut_sel == VIU_LUT_OSD_EOTF) { 227 writel(0, priv->io_base + _REG(addr_port)); 228 229 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++) 230 writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16), 231 priv->io_base + _REG(data_port)); 232 233 writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16), 234 priv->io_base + _REG(data_port)); 235 236 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++) 237 writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16), 238 priv->io_base + _REG(data_port)); 239 240 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++) 241 writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16), 242 priv->io_base + _REG(data_port)); 243 244 writel(b_map[OSD_EOTF_LUT_SIZE - 1], 245 priv->io_base + _REG(data_port)); 246 247 if (csc_on) 248 writel_bits_relaxed(7 << 27, 7 << 27, 249 priv->io_base + _REG(ctrl_port)); 250 else 251 writel_bits_relaxed(7 << 27, 0, 252 priv->io_base + _REG(ctrl_port)); 253 254 writel_bits_relaxed(BIT(31), BIT(31), 255 priv->io_base + _REG(ctrl_port)); 256 } 257 } 258 259 /* eotf lut: linear */ 260 static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = { 261 0x0000, 0x0200, 0x0400, 0x0600, 262 0x0800, 0x0a00, 0x0c00, 0x0e00, 263 0x1000, 0x1200, 0x1400, 0x1600, 264 0x1800, 0x1a00, 0x1c00, 0x1e00, 265 0x2000, 0x2200, 0x2400, 0x2600, 266 0x2800, 0x2a00, 0x2c00, 0x2e00, 267 0x3000, 0x3200, 0x3400, 0x3600, 268 0x3800, 0x3a00, 0x3c00, 0x3e00, 269 0x4000 270 }; 271 272 /* osd oetf lut: linear */ 273 static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = { 274 0, 0, 0, 0, 275 0, 32, 64, 96, 276 128, 160, 196, 224, 277 256, 288, 320, 352, 278 384, 416, 448, 480, 279 512, 544, 576, 608, 280 640, 672, 704, 736, 281 768, 800, 832, 864, 282 896, 928, 960, 992, 283 1023, 1023, 1023, 1023, 284 1023 285 }; 286 287 static void meson_viu_load_matrix(struct meson_drm *priv) 288 { 289 /* eotf lut bypass */ 290 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF, 291 eotf_33_linear_mapping, /* R */ 292 eotf_33_linear_mapping, /* G */ 293 eotf_33_linear_mapping, /* B */ 294 false); 295 296 /* eotf matrix bypass */ 297 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF, 298 eotf_bypass_coeff, 299 false); 300 301 /* oetf lut bypass */ 302 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF, 303 oetf_41_linear_mapping, /* R */ 304 oetf_41_linear_mapping, /* G */ 305 oetf_41_linear_mapping, /* B */ 306 false); 307 308 /* osd matrix RGB709 to YUV709 limit */ 309 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD, 310 RGB709_to_YUV709l_coeff, 311 true); 312 } 313 314 /* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */ 315 void meson_viu_osd1_reset(struct meson_drm *priv) 316 { 317 uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2; 318 319 /* Save these 2 registers state */ 320 osd1_fifo_ctrl_stat = readl_relaxed( 321 priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); 322 osd1_ctrl_stat2 = readl_relaxed( 323 priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 324 325 /* Reset OSD1 */ 326 writel_bits_relaxed(BIT(0), BIT(0), 327 priv->io_base + _REG(VIU_SW_RESET)); 328 writel_bits_relaxed(BIT(0), 0, 329 priv->io_base + _REG(VIU_SW_RESET)); 330 331 /* Rewrite these registers state lost in the reset */ 332 writel_relaxed(osd1_fifo_ctrl_stat, 333 priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); 334 writel_relaxed(osd1_ctrl_stat2, 335 priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 336 337 /* Reload the conversion matrix */ 338 meson_viu_load_matrix(priv); 339 } 340 341 void meson_viu_init(struct meson_drm *priv) 342 { 343 uint32_t reg; 344 345 /* Disable OSDs */ 346 writel_bits_relaxed(BIT(0) | BIT(21), 0, 347 priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); 348 writel_bits_relaxed(BIT(0) | BIT(21), 0, 349 priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); 350 351 /* On GXL/GXM, Use the 10bit HDR conversion matrix */ 352 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || 353 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) 354 meson_viu_load_matrix(priv); 355 else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) 356 meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff, 357 true); 358 359 /* Initialize OSD1 fifo control register */ 360 reg = BIT(0) | /* Urgent DDR request priority */ 361 (4 << 5); /* hold_fifo_lines */ 362 if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) 363 reg |= (1 << 10) | /* burst length 32 */ 364 (32 << 12) | /* fifo_depth_val: 32*8=256 */ 365 (2 << 22) | /* 4 words in 1 burst */ 366 (2 << 24) | 367 (1 << 31); 368 else 369 reg |= (3 << 10) | /* burst length 64 */ 370 (32 << 12) | /* fifo_depth_val: 32*8=256 */ 371 (2 << 22) | /* 4 words in 1 burst */ 372 (2 << 24); 373 writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); 374 writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); 375 376 /* Set OSD alpha replace value */ 377 writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT, 378 0xff << OSD_REPLACE_SHIFT, 379 priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 380 writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT, 381 0xff << OSD_REPLACE_SHIFT, 382 priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); 383 384 /* Disable VD1 AFBC */ 385 /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */ 386 writel_bits_relaxed(0x7 << 16, 0, 387 priv->io_base + _REG(VIU_MISC_CTRL0)); 388 /* afbc vd1 set=0 */ 389 writel_bits_relaxed(BIT(20), 0, 390 priv->io_base + _REG(VIU_MISC_CTRL0)); 391 writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); 392 393 writel_relaxed(0x00FF00C0, 394 priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE)); 395 writel_relaxed(0x00FF00C0, 396 priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); 397 398 if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { 399 writel_relaxed(4 << 29 | 400 1 << 27 | 401 1 << 26 | /* blend_din0 input to blend0 */ 402 1 << 25 | /* blend1_dout to blend2 */ 403 1 << 24 | /* blend1_din3 input to blend1 */ 404 1 << 20 | 405 0 << 16 | 406 1, 407 priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); 408 writel_relaxed(1 << 20, 409 priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); 410 writel_relaxed(1 << 20, 411 priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); 412 writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); 413 writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); 414 writel_relaxed(0, 415 priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); 416 writel_relaxed(0, 417 priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); 418 writel_bits_relaxed(0x3 << 2, 0x3 << 2, 419 priv->io_base + _REG(DOLBY_PATH_CTRL)); 420 } 421 422 priv->viu.osd1_enabled = false; 423 priv->viu.osd1_commit = false; 424 priv->viu.osd1_interlace = false; 425 } 426