Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <narmstrong@baylibre.com> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * Copyright (C) 2014 Endless Mobile */ #include <linux/export.h> #include "meson_drv.h" #include "meson_registers.h" #include "meson_vpp.h" /** * DOC: Video Post Processing * * VPP Handles all the Post Processing after the Scanout from the VIU * We handle the following post processings : * * - Postblend, Blends the OSD1 only * We exclude OSD2, VS1, VS1 and Preblend output * - Vertical OSD Scaler for OSD1 only, we disable vertical scaler and * use it only for interlace scanout * - Intermediate FIFO with default Amlogic values * * What is missing : * * - Preblend for video overlay pre-scaling * - OSD2 support for cursor framebuffer * - Video pre-scaling before postblend * - Full Vertical/Horizontal OSD scaling to support TV overscan * - HDR conversion */ void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux) { writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL)); } static unsigned int vpp_filter_coefs_4point_bspline[] = { 0x15561500, 0x14561600, 0x13561700, 0x12561800, 0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00, 0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200, 0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700, 0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01, 0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201, 0x05473301, 0x05463401, 0x04453601, 0x04433702, 0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02, 0x033d3d03 }; static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv, const unsigned int *coefs, bool is_horizontal) { int i; writel_relaxed(is_horizontal ? VPP_SCALE_HORIZONTAL_COEF : 0, priv->io_base + _REG(VPP_OSD_SCALE_COEF_IDX)); for (i = 0; i < 33; i++) writel_relaxed(coefs[i], priv->io_base + _REG(VPP_OSD_SCALE_COEF)); } static const uint32_t vpp_filter_coefs_bicubic[] = { 0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300, 0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900, 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff, 0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe, 0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd, 0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb, 0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa, 0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9, 0xf84848f8 }; static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv, const unsigned int *coefs, bool is_horizontal) { int i; writel_relaxed(is_horizontal ? VPP_SCALE_HORIZONTAL_COEF : 0, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); for (i = 0; i < 33; i++) writel_relaxed(coefs[i], priv->io_base + _REG(VPP_SCALE_COEF)); } void meson_vpp_init(struct meson_drm *priv) { /* set dummy data default YUV black */ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) writel_relaxed(0x108080, priv->io_base + _REG(VPP_DUMMY_DATA1)); else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) { writel_bits_relaxed(0xff << 16, 0xff << 16, priv->io_base + _REG(VIU_MISC_CTRL1)); writel_relaxed(VPP_PPS_DUMMY_DATA_MODE, priv->io_base + _REG(VPP_DOLBY_CTRL)); writel_relaxed(0x1020080, priv->io_base + _REG(VPP_DUMMY_DATA1)); writel_relaxed(0x42020, priv->io_base + _REG(VPP_DUMMY_DATA)); } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) writel_relaxed(0xf, priv->io_base + _REG(DOLBY_PATH_CTRL)); /* Initialize vpu fifo control registers */ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) writel_relaxed(VPP_OFIFO_SIZE_DEFAULT, priv->io_base + _REG(VPP_OFIFO_SIZE)); else writel_bits_relaxed(VPP_OFIFO_SIZE_MASK, 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); writel_relaxed(VPP_POSTBLEND_HOLD_LINES(4) | VPP_PREBLEND_HOLD_LINES(4), priv->io_base + _REG(VPP_HOLD_LINES)); if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { /* Turn off preblend */ writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0, priv->io_base + _REG(VPP_MISC)); /* Turn off POSTBLEND */ writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, priv->io_base + _REG(VPP_MISC)); /* Force all planes off */ writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, priv->io_base + _REG(VPP_MISC)); /* Setup default VD settings */ writel_relaxed(4096, priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); writel_relaxed(4096, priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); } /* Disable Scalers */ writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); /* Set horizontal/vertical bank length and enable video scale out */ writel_relaxed(VPP_VSC_BANK_LENGTH(4) | VPP_HSC_BANK_LENGTH(4) | VPP_SC_VD_EN_ENABLE, priv->io_base + _REG(VPP_SC_MISC)); /* Enable minus black level for vadj1 */ writel_relaxed(VPP_MINUS_BLACK_LVL_VADJ1_ENABLE, priv->io_base + _REG(VPP_VADJ_CTRL)); /* Write in the proper filter coefficients. */ meson_vpp_write_scaling_filter_coefs(priv, vpp_filter_coefs_4point_bspline, false); meson_vpp_write_scaling_filter_coefs(priv, vpp_filter_coefs_4point_bspline, true); /* Write the VD proper filter coefficients. */ meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic, false); meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic, true); } |