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