Linux Audio

Check our new training course

Loading...
v6.13.7
  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}
v4.17
 
  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}