| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2016 BayLibre, SAS |
|---|
| 3 | 4 | * Author: Neil Armstrong <narmstrong@baylibre.com> |
|---|
| 4 | 5 | * Copyright (C) 2015 Amlogic, Inc. All rights reserved. |
|---|
| 5 | 6 | * 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 | 7 | */ |
|---|
| 20 | 8 | |
|---|
| 21 | | -#include <linux/kernel.h> |
|---|
| 22 | | -#include <linux/module.h> |
|---|
| 23 | | -#include <drm/drmP.h> |
|---|
| 9 | +#include <linux/export.h> |
|---|
| 10 | +#include <linux/bitfield.h> |
|---|
| 11 | + |
|---|
| 12 | +#include <drm/drm_fourcc.h> |
|---|
| 13 | + |
|---|
| 24 | 14 | #include "meson_drv.h" |
|---|
| 25 | 15 | #include "meson_viu.h" |
|---|
| 26 | | -#include "meson_vpp.h" |
|---|
| 27 | | -#include "meson_venc.h" |
|---|
| 28 | | -#include "meson_canvas.h" |
|---|
| 29 | 16 | #include "meson_registers.h" |
|---|
| 30 | 17 | |
|---|
| 31 | 18 | /** |
|---|
| .. | .. |
|---|
| 91 | 78 | EOTF_COEFF_RIGHTSHIFT /* right shift */ |
|---|
| 92 | 79 | }; |
|---|
| 93 | 80 | |
|---|
| 94 | | -void meson_viu_set_osd_matrix(struct meson_drm *priv, |
|---|
| 95 | | - enum viu_matrix_sel_e m_select, |
|---|
| 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), |
|---|
| 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, |
|---|
| 96 | 111 | int *m, bool csc_on) |
|---|
| 97 | 112 | { |
|---|
| 98 | 113 | if (m_select == VIU_MATRIX_OSD) { |
|---|
| .. | .. |
|---|
| 160 | 175 | #define OSD_EOTF_LUT_SIZE 33 |
|---|
| 161 | 176 | #define OSD_OETF_LUT_SIZE 41 |
|---|
| 162 | 177 | |
|---|
| 163 | | -void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, |
|---|
| 164 | | - unsigned int *r_map, unsigned int *g_map, |
|---|
| 165 | | - unsigned int *b_map, |
|---|
| 166 | | - bool csc_on) |
|---|
| 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) |
|---|
| 167 | 182 | { |
|---|
| 168 | 183 | unsigned int addr_port; |
|---|
| 169 | 184 | unsigned int data_port; |
|---|
| .. | .. |
|---|
| 296 | 311 | true); |
|---|
| 297 | 312 | } |
|---|
| 298 | 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(VIU_SW_RESET_OSD1, VIU_SW_RESET_OSD1, |
|---|
| 327 | + priv->io_base + _REG(VIU_SW_RESET)); |
|---|
| 328 | + writel_bits_relaxed(VIU_SW_RESET_OSD1, 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 | +#define OSD1_MALI_ORDER_ABGR \ |
|---|
| 342 | + (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER, \ |
|---|
| 343 | + VIU_OSD1_MALI_REORDER_A) | \ |
|---|
| 344 | + FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER, \ |
|---|
| 345 | + VIU_OSD1_MALI_REORDER_B) | \ |
|---|
| 346 | + FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER, \ |
|---|
| 347 | + VIU_OSD1_MALI_REORDER_G) | \ |
|---|
| 348 | + FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER, \ |
|---|
| 349 | + VIU_OSD1_MALI_REORDER_R)) |
|---|
| 350 | + |
|---|
| 351 | +#define OSD1_MALI_ORDER_ARGB \ |
|---|
| 352 | + (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER, \ |
|---|
| 353 | + VIU_OSD1_MALI_REORDER_A) | \ |
|---|
| 354 | + FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER, \ |
|---|
| 355 | + VIU_OSD1_MALI_REORDER_R) | \ |
|---|
| 356 | + FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER, \ |
|---|
| 357 | + VIU_OSD1_MALI_REORDER_G) | \ |
|---|
| 358 | + FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER, \ |
|---|
| 359 | + VIU_OSD1_MALI_REORDER_B)) |
|---|
| 360 | + |
|---|
| 361 | +void meson_viu_g12a_enable_osd1_afbc(struct meson_drm *priv) |
|---|
| 362 | +{ |
|---|
| 363 | + u32 afbc_order = OSD1_MALI_ORDER_ARGB; |
|---|
| 364 | + |
|---|
| 365 | + /* Enable Mali AFBC Unpack */ |
|---|
| 366 | + writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, |
|---|
| 367 | + VIU_OSD1_MALI_UNPACK_EN, |
|---|
| 368 | + priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); |
|---|
| 369 | + |
|---|
| 370 | + switch (priv->afbcd.format) { |
|---|
| 371 | + case DRM_FORMAT_XBGR8888: |
|---|
| 372 | + case DRM_FORMAT_ABGR8888: |
|---|
| 373 | + afbc_order = OSD1_MALI_ORDER_ABGR; |
|---|
| 374 | + break; |
|---|
| 375 | + } |
|---|
| 376 | + |
|---|
| 377 | + /* Setup RGBA Reordering */ |
|---|
| 378 | + writel_bits_relaxed(VIU_OSD1_MALI_AFBCD_A_REORDER | |
|---|
| 379 | + VIU_OSD1_MALI_AFBCD_B_REORDER | |
|---|
| 380 | + VIU_OSD1_MALI_AFBCD_G_REORDER | |
|---|
| 381 | + VIU_OSD1_MALI_AFBCD_R_REORDER, |
|---|
| 382 | + afbc_order, |
|---|
| 383 | + priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); |
|---|
| 384 | + |
|---|
| 385 | + /* Select AFBCD path for OSD1 */ |
|---|
| 386 | + writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, |
|---|
| 387 | + OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, |
|---|
| 388 | + priv->io_base + _REG(OSD_PATH_MISC_CTRL)); |
|---|
| 389 | +} |
|---|
| 390 | + |
|---|
| 391 | +void meson_viu_g12a_disable_osd1_afbc(struct meson_drm *priv) |
|---|
| 392 | +{ |
|---|
| 393 | + /* Disable AFBCD path for OSD1 */ |
|---|
| 394 | + writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, 0, |
|---|
| 395 | + priv->io_base + _REG(OSD_PATH_MISC_CTRL)); |
|---|
| 396 | + |
|---|
| 397 | + /* Disable AFBCD unpack */ |
|---|
| 398 | + writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, 0, |
|---|
| 399 | + priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); |
|---|
| 400 | +} |
|---|
| 401 | + |
|---|
| 402 | +void meson_viu_gxm_enable_osd1_afbc(struct meson_drm *priv) |
|---|
| 403 | +{ |
|---|
| 404 | + writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x90), |
|---|
| 405 | + priv->io_base + _REG(VIU_MISC_CTRL1)); |
|---|
| 406 | +} |
|---|
| 407 | + |
|---|
| 408 | +void meson_viu_gxm_disable_osd1_afbc(struct meson_drm *priv) |
|---|
| 409 | +{ |
|---|
| 410 | + writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x00), |
|---|
| 411 | + priv->io_base + _REG(VIU_MISC_CTRL1)); |
|---|
| 412 | +} |
|---|
| 413 | + |
|---|
| 299 | 414 | void meson_viu_init(struct meson_drm *priv) |
|---|
| 300 | 415 | { |
|---|
| 301 | 416 | uint32_t reg; |
|---|
| 302 | 417 | |
|---|
| 303 | 418 | /* Disable OSDs */ |
|---|
| 304 | | - writel_bits_relaxed(BIT(0) | BIT(21), 0, |
|---|
| 305 | | - priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); |
|---|
| 306 | | - writel_bits_relaxed(BIT(0) | BIT(21), 0, |
|---|
| 307 | | - priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); |
|---|
| 419 | + writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, |
|---|
| 420 | + priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); |
|---|
| 421 | + writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, |
|---|
| 422 | + priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); |
|---|
| 308 | 423 | |
|---|
| 309 | 424 | /* On GXL/GXM, Use the 10bit HDR conversion matrix */ |
|---|
| 310 | | - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
|---|
| 311 | | - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) |
|---|
| 425 | + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || |
|---|
| 426 | + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) |
|---|
| 312 | 427 | meson_viu_load_matrix(priv); |
|---|
| 428 | + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { |
|---|
| 429 | + meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff, |
|---|
| 430 | + true); |
|---|
| 431 | + /* fix green/pink color distortion from vendor u-boot */ |
|---|
| 432 | + writel_bits_relaxed(OSD1_HDR2_CTRL_REG_ONLY_MAT | |
|---|
| 433 | + OSD1_HDR2_CTRL_VDIN0_HDR2_TOP_EN, 0, |
|---|
| 434 | + priv->io_base + _REG(OSD1_HDR2_CTRL)); |
|---|
| 435 | + } |
|---|
| 313 | 436 | |
|---|
| 314 | 437 | /* Initialize OSD1 fifo control register */ |
|---|
| 315 | | - reg = BIT(0) | /* Urgent DDR request priority */ |
|---|
| 316 | | - (4 << 5) | /* hold_fifo_lines */ |
|---|
| 317 | | - (3 << 10) | /* burst length 64 */ |
|---|
| 318 | | - (32 << 12) | /* fifo_depth_val: 32*8=256 */ |
|---|
| 319 | | - (2 << 22) | /* 4 words in 1 burst */ |
|---|
| 320 | | - (2 << 24); |
|---|
| 438 | + reg = VIU_OSD_DDR_PRIORITY_URGENT | |
|---|
| 439 | + VIU_OSD_HOLD_FIFO_LINES(31) | |
|---|
| 440 | + VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */ |
|---|
| 441 | + VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */ |
|---|
| 442 | + VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */ |
|---|
| 443 | + |
|---|
| 444 | + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) |
|---|
| 445 | + reg |= VIU_OSD_BURST_LENGTH_32; |
|---|
| 446 | + else |
|---|
| 447 | + reg |= VIU_OSD_BURST_LENGTH_64; |
|---|
| 448 | + |
|---|
| 321 | 449 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); |
|---|
| 322 | 450 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); |
|---|
| 323 | 451 | |
|---|
| .. | .. |
|---|
| 329 | 457 | 0xff << OSD_REPLACE_SHIFT, |
|---|
| 330 | 458 | priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); |
|---|
| 331 | 459 | |
|---|
| 460 | + /* Disable VD1 AFBC */ |
|---|
| 461 | + /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/ |
|---|
| 462 | + writel_bits_relaxed(VIU_CTRL0_VD1_AFBC_MASK, 0, |
|---|
| 463 | + priv->io_base + _REG(VIU_MISC_CTRL0)); |
|---|
| 464 | + writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); |
|---|
| 465 | + |
|---|
| 466 | + writel_relaxed(0x00FF00C0, |
|---|
| 467 | + priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE)); |
|---|
| 468 | + writel_relaxed(0x00FF00C0, |
|---|
| 469 | + priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); |
|---|
| 470 | + |
|---|
| 471 | + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { |
|---|
| 472 | + u32 val = (u32)VIU_OSD_BLEND_REORDER(0, 1) | |
|---|
| 473 | + (u32)VIU_OSD_BLEND_REORDER(1, 0) | |
|---|
| 474 | + (u32)VIU_OSD_BLEND_REORDER(2, 0) | |
|---|
| 475 | + (u32)VIU_OSD_BLEND_REORDER(3, 0) | |
|---|
| 476 | + (u32)VIU_OSD_BLEND_DIN_EN(1) | |
|---|
| 477 | + (u32)VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 | |
|---|
| 478 | + (u32)VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 | |
|---|
| 479 | + (u32)VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 | |
|---|
| 480 | + (u32)VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) | |
|---|
| 481 | + (u32)VIU_OSD_BLEND_HOLD_LINES(4); |
|---|
| 482 | + writel_relaxed(val, priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); |
|---|
| 483 | + |
|---|
| 484 | + writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, |
|---|
| 485 | + priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); |
|---|
| 486 | + writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, |
|---|
| 487 | + priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); |
|---|
| 488 | + writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); |
|---|
| 489 | + writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); |
|---|
| 490 | + writel_relaxed(0, |
|---|
| 491 | + priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); |
|---|
| 492 | + writel_relaxed(0, |
|---|
| 493 | + priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); |
|---|
| 494 | + |
|---|
| 495 | + writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc), |
|---|
| 496 | + priv->io_base + _REG(DOLBY_PATH_CTRL)); |
|---|
| 497 | + |
|---|
| 498 | + meson_viu_g12a_disable_osd1_afbc(priv); |
|---|
| 499 | + } |
|---|
| 500 | + |
|---|
| 501 | + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) |
|---|
| 502 | + meson_viu_gxm_disable_osd1_afbc(priv); |
|---|
| 503 | + |
|---|
| 332 | 504 | priv->viu.osd1_enabled = false; |
|---|
| 333 | 505 | priv->viu.osd1_commit = false; |
|---|
| 334 | 506 | priv->viu.osd1_interlace = false; |
|---|