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