diff options
Diffstat (limited to 'drivers/gpu/drm/meson')
24 files changed, 1559 insertions, 862 deletions
diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig index c28b69f48555..9f9281dd49f8 100644 --- a/drivers/gpu/drm/meson/Kconfig +++ b/drivers/gpu/drm/meson/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config DRM_MESON tristate "DRM Support for Amlogic Meson Display Controller" depends on DRM && OF && (ARM || ARM64) @@ -14,3 +15,4 @@ config DRM_MESON_DW_HDMI depends on DRM_MESON default y if DRM_MESON select DRM_DW_HDMI + imply DRM_DW_HDMI_I2S_AUDIO diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile index 7709f2fbb9f7..c389e2399133 100644 --- a/drivers/gpu/drm/meson/Makefile +++ b/drivers/gpu/drm/meson/Makefile @@ -1,5 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o -meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_overlay.o +meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o obj-$(CONFIG_DRM_MESON) += meson-drm.o obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c deleted file mode 100644 index 5de11aa7c775..000000000000 --- a/drivers/gpu/drm/meson/meson_canvas.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2016 BayLibre, SAS - * Author: Neil Armstrong <[email protected]> - * Copyright (C) 2015 Amlogic, Inc. All rights reserved. - * Copyright (C) 2014 Endless Mobile - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include "meson_drv.h" -#include "meson_canvas.h" -#include "meson_registers.h" - -/** - * DOC: Canvas - * - * CANVAS is a memory zone where physical memory frames information - * are stored for the VIU to scanout. - */ - -/* DMC Registers */ -#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */ -#define CANVAS_WIDTH_LBIT 29 -#define CANVAS_WIDTH_LWID 3 -#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */ -#define CANVAS_WIDTH_HBIT 0 -#define CANVAS_HEIGHT_BIT 9 -#define CANVAS_BLKMODE_BIT 24 -#define CANVAS_ENDIAN_BIT 26 -#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */ -#define CANVAS_LUT_WR_EN (0x2 << 8) -#define CANVAS_LUT_RD_EN (0x1 << 8) - -void meson_canvas_setup(struct meson_drm *priv, - uint32_t canvas_index, uint32_t addr, - uint32_t stride, uint32_t height, - unsigned int wrap, - unsigned int blkmode, - unsigned int endian) -{ - unsigned int val; - - regmap_write(priv->dmc, DMC_CAV_LUT_DATAL, - (((addr + 7) >> 3)) | - (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT)); - - regmap_write(priv->dmc, DMC_CAV_LUT_DATAH, - ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) << - CANVAS_WIDTH_HBIT) | - (height << CANVAS_HEIGHT_BIT) | - (wrap << 22) | - (blkmode << CANVAS_BLKMODE_BIT) | - (endian << CANVAS_ENDIAN_BIT)); - - regmap_write(priv->dmc, DMC_CAV_LUT_ADDR, - CANVAS_LUT_WR_EN | canvas_index); - - /* Force a read-back to make sure everything is flushed. */ - regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val); -} diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h deleted file mode 100644 index 85dbf26e2826..000000000000 --- a/drivers/gpu/drm/meson/meson_canvas.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016 BayLibre, SAS - * Author: Neil Armstrong <[email protected]> - * Copyright (C) 2014 Endless Mobile - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* Canvas LUT Memory */ - -#ifndef __MESON_CANVAS_H -#define __MESON_CANVAS_H - -#define MESON_CANVAS_ID_OSD1 0x4e -#define MESON_CANVAS_ID_VD1_0 0x60 -#define MESON_CANVAS_ID_VD1_1 0x61 -#define MESON_CANVAS_ID_VD1_2 0x62 - -/* Canvas configuration. */ -#define MESON_CANVAS_WRAP_NONE 0x00 -#define MESON_CANVAS_WRAP_X 0x01 -#define MESON_CANVAS_WRAP_Y 0x02 - -#define MESON_CANVAS_BLKMODE_LINEAR 0x00 -#define MESON_CANVAS_BLKMODE_32x32 0x01 -#define MESON_CANVAS_BLKMODE_64x64 0x02 - -#define MESON_CANVAS_ENDIAN_SWAP16 0x1 -#define MESON_CANVAS_ENDIAN_SWAP32 0x3 -#define MESON_CANVAS_ENDIAN_SWAP64 0x7 -#define MESON_CANVAS_ENDIAN_SWAP128 0xf - -void meson_canvas_setup(struct meson_drm *priv, - uint32_t canvas_index, uint32_t addr, - uint32_t stride, uint32_t height, - unsigned int wrap, - unsigned int blkmode, - unsigned int endian); - -#endif /* __MESON_CANVAS_H */ diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 43e29984f8b1..57ae1c13d1e6 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -1,44 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <[email protected]> */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> #include <linux/bitfield.h> -#include <drm/drmP.h> -#include <drm/drm_atomic.h> +#include <linux/soc/amlogic/meson-canvas.h> + #include <drm/drm_atomic_helper.h> -#include <drm/drm_flip_work.h> +#include <drm/drm_device.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "meson_crtc.h" #include "meson_plane.h" +#include "meson_registers.h" #include "meson_venc.h" -#include "meson_vpp.h" #include "meson_viu.h" -#include "meson_canvas.h" -#include "meson_registers.h" +#include "meson_vpp.h" + +#define MESON_G12A_VIU_OFFSET 0x5ec0 /* CRTC definition */ @@ -46,6 +33,9 @@ struct meson_crtc { struct drm_crtc base; struct drm_pending_vblank_event *event; struct meson_drm *priv; + void (*enable_osd1)(struct meson_drm *priv); + void (*enable_vd1)(struct meson_drm *priv); + unsigned int viu_offset; }; #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) @@ -81,6 +71,42 @@ static const struct drm_crtc_funcs meson_crtc_funcs = { }; +static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct meson_crtc *meson_crtc = to_meson_crtc(crtc); + struct drm_crtc_state *crtc_state = crtc->state; + struct meson_drm *priv = meson_crtc->priv; + + DRM_DEBUG_DRIVER("\n"); + + if (!crtc_state) { + DRM_ERROR("Invalid crtc_state\n"); + return; + } + + /* VD1 Preblend vertical start/end */ + writel(FIELD_PREP(GENMASK(11, 0), 2303), + priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); + + /* Setup Blender */ + writel(crtc_state->mode.hdisplay | + crtc_state->mode.vdisplay << 16, + priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); + + writel_relaxed(0 << 16 | + (crtc_state->mode.hdisplay - 1), + priv->io_base + _REG(VPP_OSD1_BLD_H_SCOPE)); + writel_relaxed(0 << 16 | + (crtc_state->mode.vdisplay - 1), + priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE)); + writel_relaxed(crtc_state->mode.hdisplay << 16 | + crtc_state->mode.vdisplay, + priv->io_base + _REG(VPP_OUT_H_V_SIZE)); + + drm_crtc_vblank_on(crtc); +} + static void meson_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -107,8 +133,31 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, priv->io_base + _REG(VPP_MISC)); drm_crtc_vblank_on(crtc); +} + +static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct meson_crtc *meson_crtc = to_meson_crtc(crtc); + struct meson_drm *priv = meson_crtc->priv; + + DRM_DEBUG_DRIVER("\n"); - priv->viu.osd1_enabled = true; + drm_crtc_vblank_off(crtc); + + priv->viu.osd1_enabled = false; + priv->viu.osd1_commit = false; + + priv->viu.vd1_enabled = false; + priv->viu.vd1_commit = false; + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + + crtc->state->event = NULL; + } } static void meson_crtc_atomic_disable(struct drm_crtc *crtc, @@ -174,6 +223,55 @@ static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { .atomic_disable = meson_crtc_atomic_disable, }; +static const struct drm_crtc_helper_funcs meson_g12a_crtc_helper_funcs = { + .atomic_begin = meson_crtc_atomic_begin, + .atomic_flush = meson_crtc_atomic_flush, + .atomic_enable = meson_g12a_crtc_atomic_enable, + .atomic_disable = meson_g12a_crtc_atomic_disable, +}; + +static void meson_crtc_enable_osd1(struct meson_drm *priv) +{ + writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, + priv->io_base + _REG(VPP_MISC)); +} + +static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv) +{ + writel_relaxed(priv->viu.osd_blend_din0_scope_h, + priv->io_base + + _REG(VIU_OSD_BLEND_DIN0_SCOPE_H)); + writel_relaxed(priv->viu.osd_blend_din0_scope_v, + priv->io_base + + _REG(VIU_OSD_BLEND_DIN0_SCOPE_V)); + writel_relaxed(priv->viu.osb_blend0_size, + priv->io_base + + _REG(VIU_OSD_BLEND_BLEND0_SIZE)); + writel_relaxed(priv->viu.osb_blend1_size, + priv->io_base + + _REG(VIU_OSD_BLEND_BLEND1_SIZE)); + writel_bits_relaxed(3 << 8, 3 << 8, + priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); +} + +static void meson_crtc_enable_vd1(struct meson_drm *priv) +{ + writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | + VPP_COLOR_MNG_ENABLE, + VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | + VPP_COLOR_MNG_ENABLE, + priv->io_base + _REG(VPP_MISC)); +} + +static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv) +{ + writel_relaxed(VD_BLEND_PREBLD_SRC_VD1 | + VD_BLEND_PREBLD_PREMULT_EN | + VD_BLEND_POSTBLD_SRC_VD1 | + VD_BLEND_POSTBLD_PREMULT_EN, + priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); +} + void meson_crtc_irq(struct meson_drm *priv) { struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); @@ -214,20 +312,14 @@ void meson_crtc_irq(struct meson_drm *priv) writel_relaxed(priv->viu.osd_sc_v_ctrl0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); - if (priv->canvas) - meson_canvas_config(priv->canvas, priv->canvas_id_osd1, - priv->viu.osd1_addr, priv->viu.osd1_stride, - priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, 0); - else - meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, + meson_canvas_config(priv->canvas, priv->canvas_id_osd1, priv->viu.osd1_addr, priv->viu.osd1_stride, priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR, 0); /* Enable OSD1 */ - writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, - priv->io_base + _REG(VPP_MISC)); + if (meson_crtc->enable_osd1) + meson_crtc->enable_osd1(priv); priv->viu.osd1_commit = false; } @@ -237,148 +329,170 @@ void meson_crtc_irq(struct meson_drm *priv) switch (priv->viu.vd1_planes) { case 3: - if (priv->canvas) - meson_canvas_config(priv->canvas, - priv->canvas_id_vd1_2, - priv->viu.vd1_addr2, - priv->viu.vd1_stride2, - priv->viu.vd1_height2, - MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, - MESON_CANVAS_ENDIAN_SWAP64); - else - meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_2, - priv->viu.vd1_addr2, - priv->viu.vd1_stride2, - priv->viu.vd1_height2, - MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, - MESON_CANVAS_ENDIAN_SWAP64); + meson_canvas_config(priv->canvas, + priv->canvas_id_vd1_2, + priv->viu.vd1_addr2, + priv->viu.vd1_stride2, + priv->viu.vd1_height2, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); /* fallthrough */ case 2: - if (priv->canvas) - meson_canvas_config(priv->canvas, - priv->canvas_id_vd1_1, - priv->viu.vd1_addr1, - priv->viu.vd1_stride1, - priv->viu.vd1_height1, - MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, - MESON_CANVAS_ENDIAN_SWAP64); - else - meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_1, - priv->viu.vd1_addr2, - priv->viu.vd1_stride2, - priv->viu.vd1_height2, - MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, - MESON_CANVAS_ENDIAN_SWAP64); + meson_canvas_config(priv->canvas, + priv->canvas_id_vd1_1, + priv->viu.vd1_addr1, + priv->viu.vd1_stride1, + priv->viu.vd1_height1, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); /* fallthrough */ case 1: - if (priv->canvas) - meson_canvas_config(priv->canvas, - priv->canvas_id_vd1_0, - priv->viu.vd1_addr0, - priv->viu.vd1_stride0, - priv->viu.vd1_height0, - MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, - MESON_CANVAS_ENDIAN_SWAP64); - else - meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0, - priv->viu.vd1_addr2, - priv->viu.vd1_stride2, - priv->viu.vd1_height2, - MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, - MESON_CANVAS_ENDIAN_SWAP64); + meson_canvas_config(priv->canvas, + priv->canvas_id_vd1_0, + priv->viu.vd1_addr0, + priv->viu.vd1_stride0, + priv->viu.vd1_height0, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); }; writel_relaxed(priv->viu.vd1_if0_gen_reg, - priv->io_base + _REG(VD1_IF0_GEN_REG)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_GEN_REG)); writel_relaxed(priv->viu.vd1_if0_gen_reg, - priv->io_base + _REG(VD2_IF0_GEN_REG)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_GEN_REG)); writel_relaxed(priv->viu.vd1_if0_gen_reg2, - priv->io_base + _REG(VD1_IF0_GEN_REG2)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_GEN_REG2)); writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, - priv->io_base + _REG(VIU_VD1_FMT_CTRL)); + priv->io_base + meson_crtc->viu_offset + + _REG(VIU_VD1_FMT_CTRL)); writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, - priv->io_base + _REG(VIU_VD2_FMT_CTRL)); + priv->io_base + meson_crtc->viu_offset + + _REG(VIU_VD2_FMT_CTRL)); writel_relaxed(priv->viu.viu_vd1_fmt_w, - priv->io_base + _REG(VIU_VD1_FMT_W)); + priv->io_base + meson_crtc->viu_offset + + _REG(VIU_VD1_FMT_W)); writel_relaxed(priv->viu.viu_vd1_fmt_w, - priv->io_base + _REG(VIU_VD2_FMT_W)); + priv->io_base + meson_crtc->viu_offset + + _REG(VIU_VD2_FMT_W)); writel_relaxed(priv->viu.vd1_if0_canvas0, - priv->io_base + _REG(VD1_IF0_CANVAS0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CANVAS0)); writel_relaxed(priv->viu.vd1_if0_canvas0, - priv->io_base + _REG(VD1_IF0_CANVAS1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CANVAS1)); writel_relaxed(priv->viu.vd1_if0_canvas0, - priv->io_base + _REG(VD2_IF0_CANVAS0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CANVAS0)); writel_relaxed(priv->viu.vd1_if0_canvas0, - priv->io_base + _REG(VD2_IF0_CANVAS1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CANVAS1)); writel_relaxed(priv->viu.vd1_if0_luma_x0, - priv->io_base + _REG(VD1_IF0_LUMA_X0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_LUMA_X0)); writel_relaxed(priv->viu.vd1_if0_luma_x0, - priv->io_base + _REG(VD1_IF0_LUMA_X1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_LUMA_X1)); writel_relaxed(priv->viu.vd1_if0_luma_x0, - priv->io_base + _REG(VD2_IF0_LUMA_X0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_LUMA_X0)); writel_relaxed(priv->viu.vd1_if0_luma_x0, - priv->io_base + _REG(VD2_IF0_LUMA_X1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_LUMA_X1)); writel_relaxed(priv->viu.vd1_if0_luma_y0, - priv->io_base + _REG(VD1_IF0_LUMA_Y0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_LUMA_Y0)); writel_relaxed(priv->viu.vd1_if0_luma_y0, - priv->io_base + _REG(VD1_IF0_LUMA_Y1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_LUMA_Y1)); writel_relaxed(priv->viu.vd1_if0_luma_y0, - priv->io_base + _REG(VD2_IF0_LUMA_Y0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_LUMA_Y0)); writel_relaxed(priv->viu.vd1_if0_luma_y0, - priv->io_base + _REG(VD2_IF0_LUMA_Y1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_LUMA_Y1)); writel_relaxed(priv->viu.vd1_if0_chroma_x0, - priv->io_base + _REG(VD1_IF0_CHROMA_X0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CHROMA_X0)); writel_relaxed(priv->viu.vd1_if0_chroma_x0, - priv->io_base + _REG(VD1_IF0_CHROMA_X1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CHROMA_X1)); writel_relaxed(priv->viu.vd1_if0_chroma_x0, - priv->io_base + _REG(VD2_IF0_CHROMA_X0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CHROMA_X0)); writel_relaxed(priv->viu.vd1_if0_chroma_x0, - priv->io_base + _REG(VD2_IF0_CHROMA_X1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CHROMA_X1)); writel_relaxed(priv->viu.vd1_if0_chroma_y0, - priv->io_base + _REG(VD1_IF0_CHROMA_Y0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CHROMA_Y0)); writel_relaxed(priv->viu.vd1_if0_chroma_y0, - priv->io_base + _REG(VD1_IF0_CHROMA_Y1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CHROMA_Y1)); writel_relaxed(priv->viu.vd1_if0_chroma_y0, - priv->io_base + _REG(VD2_IF0_CHROMA_Y0)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CHROMA_Y0)); writel_relaxed(priv->viu.vd1_if0_chroma_y0, - priv->io_base + _REG(VD2_IF0_CHROMA_Y1)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CHROMA_Y1)); writel_relaxed(priv->viu.vd1_if0_repeat_loop, - priv->io_base + _REG(VD1_IF0_RPT_LOOP)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_RPT_LOOP)); writel_relaxed(priv->viu.vd1_if0_repeat_loop, - priv->io_base + _REG(VD2_IF0_RPT_LOOP)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_RPT_LOOP)); writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, - priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_LUMA0_RPT_PAT)); writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, - priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_LUMA0_RPT_PAT)); writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, - priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_LUMA1_RPT_PAT)); writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, - priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_LUMA1_RPT_PAT)); writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, - priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CHROMA0_RPT_PAT)); writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, - priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CHROMA0_RPT_PAT)); writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, - priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CHROMA1_RPT_PAT)); writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, - priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT)); - writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL)); - writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL)); - writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL)); - writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CHROMA1_RPT_PAT)); + writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_LUMA_PSEL)); + writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_CHROMA_PSEL)); + writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_LUMA_PSEL)); + writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + + _REG(VD2_IF0_CHROMA_PSEL)); writel_relaxed(priv->viu.vd1_range_map_y, - priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_RANGE_MAP_Y)); writel_relaxed(priv->viu.vd1_range_map_cb, - priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB)); + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_RANGE_MAP_CB)); writel_relaxed(priv->viu.vd1_range_map_cr, - priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR)); - writel_relaxed(0x78404, + priv->io_base + meson_crtc->viu_offset + + _REG(VD1_IF0_RANGE_MAP_CR)); + writel_relaxed(VPP_VSC_BANK_LENGTH(4) | + VPP_HSC_BANK_LENGTH(4) | + VPP_SC_VD_EN_ENABLE | + VPP_SC_TOP_EN_ENABLE | + VPP_SC_HSC_EN_ENABLE | + VPP_SC_VSC_EN_ENABLE, priv->io_base + _REG(VPP_SC_MISC)); writel_relaxed(priv->viu.vpp_pic_in_height, priv->io_base + _REG(VPP_PIC_IN_HEIGHT)); @@ -423,11 +537,8 @@ void meson_crtc_irq(struct meson_drm *priv) writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); /* Enable VD1 */ - writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | - VPP_COLOR_MNG_ENABLE, - VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | - VPP_COLOR_MNG_ENABLE, - priv->io_base + _REG(VPP_MISC)); + if (meson_crtc->enable_vd1) + meson_crtc->enable_vd1(priv); priv->viu.vd1_commit = false; } @@ -464,7 +575,16 @@ int meson_crtc_create(struct meson_drm *priv) return ret; } - drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1; + meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1; + meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; + drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs); + } else { + meson_crtc->enable_osd1 = meson_crtc_enable_osd1; + meson_crtc->enable_vd1 = meson_crtc_enable_vd1; + drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); + } priv->crtc = crtc; diff --git a/drivers/gpu/drm/meson/meson_crtc.h b/drivers/gpu/drm/meson/meson_crtc.h index b62b9e51764d..8e3998cabf14 100644 --- a/drivers/gpu/drm/meson/meson_crtc.h +++ b/drivers/gpu/drm/meson/meson_crtc.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <[email protected]> */ diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 8a4ebcb6405c..397c33182f4f 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -1,55 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <[email protected]> */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> #include <linux/component.h> +#include <linux/module.h> #include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/soc/amlogic/meson-canvas.h> -#include <drm/drmP.h> -#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_flip_work.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_irq.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_rect.h> +#include <drm/drm_vblank.h> +#include "meson_crtc.h" #include "meson_drv.h" -#include "meson_plane.h" #include "meson_overlay.h" -#include "meson_crtc.h" +#include "meson_plane.h" +#include "meson_registers.h" #include "meson_venc_cvbs.h" - -#include "meson_vpp.h" #include "meson_viu.h" -#include "meson_venc.h" -#include "meson_canvas.h" -#include "meson_registers.h" +#include "meson_vpp.h" #define DRIVER_NAME "meson" #define DRIVER_DESC "Amlogic Meson DRM driver" @@ -91,12 +73,22 @@ static irqreturn_t meson_irq(int irq, void *arg) return IRQ_HANDLED; } +static int meson_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + /* + * We need 64bytes aligned stride, and PAGE aligned size + */ + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), SZ_64); + args->size = PAGE_ALIGN(args->pitch * args->height); + + return drm_gem_cma_dumb_create_internal(file, dev, args); +} + DEFINE_DRM_GEM_CMA_FOPS(fops); static struct drm_driver meson_driver = { - .driver_features = DRIVER_GEM | - DRIVER_MODESET | DRIVER_PRIME | - DRIVER_ATOMIC, + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, /* IRQ */ .irq_handler = meson_irq, @@ -104,8 +96,6 @@ static struct drm_driver meson_driver = { /* PRIME Ops */ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import = drm_gem_prime_import, - .gem_prime_export = drm_gem_prime_export, .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, .gem_prime_vmap = drm_gem_cma_prime_vmap, @@ -113,7 +103,7 @@ static struct drm_driver meson_driver = { .gem_prime_mmap = drm_gem_cma_prime_mmap, /* GEM Ops */ - .dumb_create = drm_gem_cma_dumb_create, + .dumb_create = meson_dumb_create, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, @@ -150,10 +140,28 @@ static struct regmap_config meson_regmap_config = { static void meson_vpu_init(struct meson_drm *priv) { - writel_relaxed(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); - writel_relaxed(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); - writel_relaxed(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); - writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); + u32 value; + + /* + * Slave dc0 and dc5 connected to master port 1. + * By default other slaves are connected to master port 0. + */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1) | + VPU_RDARB_SLAVE_TO_MASTER_PORT(5, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); + + /* Slave dc0 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); + + /* Slave dc4 and dc7 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(4, 1) | + VPU_RDARB_SLAVE_TO_MASTER_PORT(7, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); + + /* Slave dc1 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(1, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); } static void meson_remove_framebuffers(void) @@ -201,6 +209,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) priv->drm = drm; priv->dev = dev; + priv->compat = (enum vpu_compatible)of_device_get_match_data(priv->dev); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) { @@ -231,50 +241,31 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) } priv->canvas = meson_canvas_get(dev); - if (!IS_ERR(priv->canvas)) { - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); - if (ret) - goto free_drm; - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); - if (ret) { - meson_canvas_free(priv->canvas, priv->canvas_id_osd1); - goto free_drm; - } - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); - if (ret) { - meson_canvas_free(priv->canvas, priv->canvas_id_osd1); - meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); - goto free_drm; - } - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); - if (ret) { - meson_canvas_free(priv->canvas, priv->canvas_id_osd1); - meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); - meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); - goto free_drm; - } - } else { - priv->canvas = NULL; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); - if (!res) { - ret = -EINVAL; - goto free_drm; - } - /* Simply ioremap since it may be a shared register zone */ - regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) { - ret = -EADDRNOTAVAIL; - goto free_drm; - } + if (IS_ERR(priv->canvas)) { + ret = PTR_ERR(priv->canvas); + goto free_drm; + } - priv->dmc = devm_regmap_init_mmio(dev, regs, - &meson_regmap_config); - if (IS_ERR(priv->dmc)) { - dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); - ret = PTR_ERR(priv->dmc); - goto free_drm; - } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); + if (ret) + goto free_drm; + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + goto free_drm; + } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + goto free_drm; + } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); + goto free_drm; } priv->vsync_irq = platform_get_irq(pdev, 0); @@ -381,6 +372,33 @@ static const struct component_master_ops meson_drv_master_ops = { .unbind = meson_drv_unbind, }; +static int __maybe_unused meson_drv_pm_suspend(struct device *dev) +{ + struct meson_drm *priv = dev_get_drvdata(dev); + + if (!priv) + return 0; + + return drm_mode_config_helper_suspend(priv->drm); +} + +static int __maybe_unused meson_drv_pm_resume(struct device *dev) +{ + struct meson_drm *priv = dev_get_drvdata(dev); + + if (!priv) + return 0; + + meson_vpu_init(priv); + meson_venc_init(priv); + meson_vpp_init(priv); + meson_viu_init(priv); + + drm_mode_config_helper_resume(priv->drm); + + return 0; +} + static int compare_of(struct device *dev, void *data) { DRM_DEBUG_DRIVER("Comparing of node %pOF with %pOF\n", @@ -464,18 +482,28 @@ static int meson_drv_probe(struct platform_device *pdev) }; static const struct of_device_id dt_match[] = { - { .compatible = "amlogic,meson-gxbb-vpu" }, - { .compatible = "amlogic,meson-gxl-vpu" }, - { .compatible = "amlogic,meson-gxm-vpu" }, + { .compatible = "amlogic,meson-gxbb-vpu", + .data = (void *)VPU_COMPATIBLE_GXBB }, + { .compatible = "amlogic,meson-gxl-vpu", + .data = (void *)VPU_COMPATIBLE_GXL }, + { .compatible = "amlogic,meson-gxm-vpu", + .data = (void *)VPU_COMPATIBLE_GXM }, + { .compatible = "amlogic,meson-g12a-vpu", + .data = (void *)VPU_COMPATIBLE_G12A }, {} }; MODULE_DEVICE_TABLE(of, dt_match); +static const struct dev_pm_ops meson_drv_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(meson_drv_pm_suspend, meson_drv_pm_resume) +}; + static struct platform_driver meson_drm_platform_driver = { .probe = meson_drv_probe, .driver = { .name = "meson-drm", .of_match_table = dt_match, + .pm = &meson_drv_pm_ops, }, }; diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 4dccf4cd042a..820d07bdd42a 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -1,35 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __MESON_DRV_H #define __MESON_DRV_H -#include <linux/platform_device.h> -#include <linux/regmap.h> +#include <linux/device.h> #include <linux/of.h> -#include <linux/soc/amlogic/meson-canvas.h> -#include <drm/drmP.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +struct drm_crtc; +struct drm_device; +struct drm_plane; +struct meson_drm; + +enum vpu_compatible { + VPU_COMPATIBLE_GXBB = 0, + VPU_COMPATIBLE_GXL = 1, + VPU_COMPATIBLE_GXM = 2, + VPU_COMPATIBLE_G12A = 3, +}; struct meson_drm { struct device *dev; + enum vpu_compatible compat; void __iomem *io_base; struct regmap *hhi; - struct regmap *dmc; int vsync_irq; struct meson_canvas *canvas; @@ -63,6 +62,10 @@ struct meson_drm { uint32_t osd_sc_h_phase_step; uint32_t osd_sc_h_ctrl0; uint32_t osd_sc_v_ctrl0; + uint32_t osd_blend_din0_scope_h; + uint32_t osd_blend_din0_scope_v; + uint32_t osb_blend0_size; + uint32_t osb_blend1_size; bool vd1_enabled; bool vd1_commit; @@ -122,9 +125,9 @@ struct meson_drm { }; static inline int meson_vpu_is_compatible(struct meson_drm *priv, - const char *compat) + enum vpu_compatible family) { - return of_device_is_compatible(priv->dev->of_node, compat); + return priv->compat == family; } #endif /* __MESON_DRV_H */ diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index 563953ec6ad0..3bb7ffe5fc39 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -1,44 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include <linux/clk.h> +#include <linux/component.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/component.h> +#include <linux/of_device.h> #include <linux/of_graph.h> -#include <linux/reset.h> -#include <linux/clk.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> -#include <drm/drmP.h> +#include <drm/bridge/dw_hdmi.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_device.h> #include <drm/drm_edid.h> #include <drm/drm_probe_helper.h> -#include <drm/bridge/dw_hdmi.h> +#include <drm/drm_print.h> -#include <uapi/linux/media-bus-format.h> -#include <uapi/linux/videodev2.h> +#include <linux/media-bus-format.h> +#include <linux/videodev2.h> #include "meson_drv.h" -#include "meson_venc.h" -#include "meson_vclk.h" #include "meson_dw_hdmi.h" #include "meson_registers.h" +#include "meson_vclk.h" +#include "meson_venc.h" #define DRIVER_NAME "meson-dw-hdmi" #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" @@ -105,6 +95,7 @@ #define HDMITX_TOP_ADDR_REG 0x0 #define HDMITX_TOP_DATA_REG 0x4 #define HDMITX_TOP_CTRL_REG 0x8 +#define HDMITX_TOP_G12A_OFFSET 0x8000 /* Controller Communication Channel */ #define HDMITX_DWC_ADDR_REG 0x10 @@ -118,6 +109,8 @@ #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ +#define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */ +#define HHI_HDMI_PHY_CNTL5 0x3b4 /* 0xed */ static DEFINE_SPINLOCK(reg_lock); @@ -127,12 +120,26 @@ enum meson_venc_source { MESON_VENC_SOURCE_ENCP = 2, }; +struct meson_dw_hdmi; + +struct meson_dw_hdmi_data { + unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr); + void (*top_write)(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data); + unsigned int (*dwc_read)(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr); + void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data); +}; + struct meson_dw_hdmi { struct drm_encoder encoder; struct dw_hdmi_plat_data dw_plat_data; struct meson_drm *priv; struct device *dev; void __iomem *hdmitx; + const struct meson_dw_hdmi_data *data; struct reset_control *hdmitx_apb; struct reset_control *hdmitx_ctrl; struct reset_control *hdmitx_phy; @@ -174,6 +181,12 @@ static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi, return data; } +static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr) +{ + return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); +} + static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, unsigned int addr, unsigned int data) { @@ -191,18 +204,24 @@ static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, spin_unlock_irqrestore(®_lock, flags); } +static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data) +{ + writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); +} + /* Helper to change specific bits in PHY registers */ static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, unsigned int addr, unsigned int mask, unsigned int val) { - unsigned int data = dw_hdmi_top_read(dw_hdmi, addr); + unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr); data &= ~mask; data |= val; - dw_hdmi_top_write(dw_hdmi, addr, data); + dw_hdmi->data->top_write(dw_hdmi, addr, data); } static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, @@ -226,6 +245,12 @@ static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, return data; } +static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr) +{ + return readb(dw_hdmi->hdmitx + addr); +} + static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, unsigned int addr, unsigned int data) { @@ -243,18 +268,24 @@ static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, spin_unlock_irqrestore(®_lock, flags); } +static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data) +{ + writeb(data, dw_hdmi->hdmitx + addr); +} + /* Helper to change specific bits in controller registers */ static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, unsigned int addr, unsigned int mask, unsigned int val) { - unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr); + unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr); data &= ~mask; data |= val; - dw_hdmi_dwc_write(dw_hdmi, addr, data); + dw_hdmi->data->dwc_write(dw_hdmi, addr, data); } /* Bridge */ @@ -300,6 +331,24 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); } + } else if (dw_hdmi_is_compatible(dw_hdmi, + "amlogic,meson-g12a-dw-hdmi")) { + if (pixel_clock >= 371250) { + /* 5.94Gbps, 3.7125Gbps */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b); + } else if (pixel_clock >= 297000) { + /* 2.97Gbps */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); + } else { + /* 1.485Gbps, and below */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); + } } } @@ -375,33 +424,36 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); /* Bring out of reset */ - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 0x3, 0x3); + + /* Enable cec_clk and hdcp22_tmdsclk_en */ dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 0x3 << 4, 0x3 << 4); /* Enable normal output to PHY */ - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); /* TMDS pattern setup (TOFIX Handle the YUV420 case) */ if (mode->clock > 340000) { - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0); - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, + 0); + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x03ff03ff); } else { - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f); - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f); } /* Load TMDS pattern */ - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); msleep(20); - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); /* Setup PHY parameters */ meson_hdmi_phy_setup_mode(dw_hdmi, mode); @@ -412,7 +464,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, /* BIT_INVERT */ if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || - dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) + dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || + dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, BIT(17), 0); else @@ -480,7 +533,7 @@ static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, { struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; - return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ? + return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ? connector_status_connected : connector_status_disconnected; } @@ -490,11 +543,11 @@ static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi, struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; /* Setup HPD Filter */ - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, (0xa << 12) | 0xa0); /* Clear interrupts */ - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); /* Unmask interrupts */ @@ -515,8 +568,8 @@ static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id) struct meson_dw_hdmi *dw_hdmi = dev_id; u32 stat; - stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); - dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); + stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); /* HPD Events, handle in the threaded interrupt handler */ if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { @@ -686,7 +739,9 @@ static const struct drm_encoder_helper_funcs static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, unsigned int *result) { - *result = dw_hdmi_dwc_read(context, reg); + struct meson_dw_hdmi *dw_hdmi = context; + + *result = dw_hdmi->data->dwc_read(dw_hdmi, reg); return 0; @@ -695,7 +750,9 @@ static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, unsigned int val) { - dw_hdmi_dwc_write(context, reg, val); + struct meson_dw_hdmi *dw_hdmi = context; + + dw_hdmi->data->dwc_write(dw_hdmi, reg, val); return 0; } @@ -709,6 +766,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = { .fast_io = true, }; +static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = { + .top_read = dw_hdmi_top_read, + .top_write = dw_hdmi_top_write, + .dwc_read = dw_hdmi_dwc_read, + .dwc_write = dw_hdmi_dwc_write, +}; + +static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { + .top_read = dw_hdmi_g12a_top_read, + .top_write = dw_hdmi_g12a_top_write, + .dwc_read = dw_hdmi_g12a_dwc_read, + .dwc_write = dw_hdmi_g12a_dwc_write, +}; + static bool meson_hdmi_connector_is_available(struct device *dev) { struct device_node *ep, *remote; @@ -731,10 +802,52 @@ static bool meson_hdmi_connector_is_available(struct device *dev) return false; } +static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) +{ + struct meson_drm *priv = meson_dw_hdmi->priv; + + /* Enable clocks */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); + + /* Bring HDMITX MEM output of power down */ + regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); + + /* Reset HDMITX APB & TX & PHY */ + reset_control_reset(meson_dw_hdmi->hdmitx_apb); + reset_control_reset(meson_dw_hdmi->hdmitx_ctrl); + reset_control_reset(meson_dw_hdmi->hdmitx_phy); + + /* Enable APB3 fail on error */ + if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + writel_bits_relaxed(BIT(15), BIT(15), + meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); + writel_bits_relaxed(BIT(15), BIT(15), + meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); + } + + /* Bring out of reset */ + meson_dw_hdmi->data->top_write(meson_dw_hdmi, + HDMITX_TOP_SW_RESET, 0); + + msleep(20); + + meson_dw_hdmi->data->top_write(meson_dw_hdmi, + HDMITX_TOP_CLK_CNTL, 0xff); + + /* Enable HDMI-TX Interrupt */ + meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, + HDMITX_TOP_INTR_CORE); + + meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, + HDMITX_TOP_INTR_CORE); + +} + static int meson_dw_hdmi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); + const struct meson_dw_hdmi_data *match; struct meson_dw_hdmi *meson_dw_hdmi; struct drm_device *drm = data; struct meson_drm *priv = drm->dev_private; @@ -751,6 +864,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, return -ENODEV; } + match = of_device_get_match_data(&pdev->dev); + if (!match) { + dev_err(&pdev->dev, "failed to get match data\n"); + return -ENODEV; + } + meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), GFP_KERNEL); if (!meson_dw_hdmi) @@ -758,6 +877,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, meson_dw_hdmi->priv = priv; meson_dw_hdmi->dev = dev; + meson_dw_hdmi->data = match; dw_plat_data = &meson_dw_hdmi->dw_plat_data; encoder = &meson_dw_hdmi->encoder; @@ -846,36 +966,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, DRM_DEBUG_DRIVER("encoder initialized\n"); - /* Enable clocks */ - regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); - - /* Bring HDMITX MEM output of power down */ - regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); - - /* Reset HDMITX APB & TX & PHY */ - reset_control_reset(meson_dw_hdmi->hdmitx_apb); - reset_control_reset(meson_dw_hdmi->hdmitx_ctrl); - reset_control_reset(meson_dw_hdmi->hdmitx_phy); - - /* Enable APB3 fail on error */ - writel_bits_relaxed(BIT(15), BIT(15), - meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); - writel_bits_relaxed(BIT(15), BIT(15), - meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); - - /* Bring out of reset */ - dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0); - - msleep(20); - - dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff); - - /* Enable HDMI-TX Interrupt */ - dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, - HDMITX_TOP_INTR_CORE); - - dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, - HDMITX_TOP_INTR_CORE); + meson_dw_hdmi_init(meson_dw_hdmi); /* Bridge / Connector */ @@ -886,6 +977,11 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; + if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || + dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || + dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) + dw_plat_data->use_drm_infoframe = true; + platform_set_drvdata(pdev, meson_dw_hdmi); meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder, @@ -911,6 +1007,34 @@ static const struct component_ops meson_dw_hdmi_ops = { .unbind = meson_dw_hdmi_unbind, }; +static int __maybe_unused meson_dw_hdmi_pm_suspend(struct device *dev) +{ + struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev); + + if (!meson_dw_hdmi) + return 0; + + /* Reset TOP */ + meson_dw_hdmi->data->top_write(meson_dw_hdmi, + HDMITX_TOP_SW_RESET, 0); + + return 0; +} + +static int __maybe_unused meson_dw_hdmi_pm_resume(struct device *dev) +{ + struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev); + + if (!meson_dw_hdmi) + return 0; + + meson_dw_hdmi_init(meson_dw_hdmi); + + dw_hdmi_resume(meson_dw_hdmi->hdmi); + + return 0; +} + static int meson_dw_hdmi_probe(struct platform_device *pdev) { return component_add(&pdev->dev, &meson_dw_hdmi_ops); @@ -923,10 +1047,20 @@ static int meson_dw_hdmi_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops meson_dw_hdmi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(meson_dw_hdmi_pm_suspend, + meson_dw_hdmi_pm_resume) +}; + static const struct of_device_id meson_dw_hdmi_of_table[] = { - { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, - { .compatible = "amlogic,meson-gxl-dw-hdmi" }, - { .compatible = "amlogic,meson-gxm-dw-hdmi" }, + { .compatible = "amlogic,meson-gxbb-dw-hdmi", + .data = &meson_dw_hdmi_gx_data }, + { .compatible = "amlogic,meson-gxl-dw-hdmi", + .data = &meson_dw_hdmi_gx_data }, + { .compatible = "amlogic,meson-gxm-dw-hdmi", + .data = &meson_dw_hdmi_gx_data }, + { .compatible = "amlogic,meson-g12a-dw-hdmi", + .data = &meson_dw_hdmi_g12a_data }, { } }; MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); @@ -937,6 +1071,7 @@ static struct platform_driver meson_dw_hdmi_platform_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = meson_dw_hdmi_of_table, + .pm = &meson_dw_hdmi_pm_ops, }, }; module_platform_driver(meson_dw_hdmi_platform_driver); diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h index 0b81183125e3..08e1c14e4ea0 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.h +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h @@ -1,29 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __MESON_DW_HDMI_H #define __MESON_DW_HDMI_H /* - * Bit 7 RW Reserved. Default 1. - * Bit 6 RW Reserved. Default 1. - * Bit 5 RW Reserved. Default 1. + * Bit 15-10: RW Reserved. Default 1 starting from G12A + * Bit 9 RW sw_reset_i2c starting from G12A + * Bit 8 RW sw_reset_axiarb starting from G12A + * Bit 7 RW Reserved. Default 1, sw_reset_emp starting from G12A + * Bit 6 RW Reserved. Default 1, sw_reset_flt starting from G12A + * Bit 5 RW Reserved. Default 1, sw_reset_hdcp22 starting from G12A * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset. * Default 1. * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset; @@ -39,12 +30,16 @@ #define HDMITX_TOP_SW_RESET (0x000) /* + * Bit 31 RW free_clk_en: 0=Enable clock gating for power saving; 1= Disable * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0. * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0. * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0. * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0. * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0. - * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. + * Bit 7 RW hdcp22_skpclk_en: starting from G12A, 1=enable; 0=disable + * Bit 6 RW hdcp22_esmclk_en: starting from G12A, 1=enable; 0=disable + * Bit 5 RW hdcp22_tmdsclk_en: starting from G12A, 1=enable; 0=disable + * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. Reserved for G12A * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0. * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0. * Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0. @@ -53,6 +48,8 @@ #define HDMITX_TOP_CLK_CNTL (0x001) /* + * Bit 31:28 RW rxsense_glitch_width: starting from G12A + * Bit 27:16 RW rxsense_valid_width: starting from G12A * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0. * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0. */ @@ -61,6 +58,9 @@ /* * intr_maskn: MASK_N, one bit per interrupt source. * 1=Enable interrupt source; 0=Disable interrupt source. Default 0. + * [ 7] rxsense_fall starting from G12A + * [ 6] rxsense_rise starting from G12A + * [ 5] err_i2c_timeout starting from G12A * [ 4] hdcp22_rndnum_err * [ 3] nonce_rfrsh_rise * [ 2] hpd_fall_intr @@ -73,6 +73,9 @@ * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt * bit, read back the interrupt status. * Bit 31 R IP interrupt status + * Bit 7 RW rxsense_fall starting from G12A + * Bit 6 RW rxsense_rise starting from G12A + * Bit 5 RW err_i2c_timeout starting from G12A * Bit 2 RW hpd_fall * Bit 1 RW hpd_rise * Bit 0 RW IP interrupt @@ -80,6 +83,9 @@ #define HDMITX_TOP_INTR_STAT (0x004) /* + * [7] rxsense_fall starting from G12A + * [6] rxsense_rise starting from G12A + * [5] err_i2c_timeout starting from G12A * [4] hdcp22_rndnum_err * [3] nonce_rfrsh_rise * [2] hpd_fall @@ -91,8 +97,11 @@ #define HDMITX_TOP_INTR_CORE BIT(0) #define HDMITX_TOP_INTR_HPD_RISE BIT(1) #define HDMITX_TOP_INTR_HPD_FALL BIT(2) +#define HDMITX_TOP_INTR_RXSENSE_RISE BIT(6) +#define HDMITX_TOP_INTR_RXSENSE_FALL BIT(7) -/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; +/* + * Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. * Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern * every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0. @@ -127,7 +136,8 @@ /* Bit 9: 0 RW tmds_clk_pttn[29:20]. Default 0. */ #define HDMITX_TOP_TMDS_CLK_PTTN_23 (0x00B) -/* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, +/* + * Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, * used when TMDS CLK rate = TMDS character rate /4. Default 0. * Bit 0 R Reserved. Default 0. * [ 1] shift_tmds_clk_pttn @@ -135,12 +145,16 @@ */ #define HDMITX_TOP_TMDS_CLK_PTTN_CNTL (0x00C) -/* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM +/* + * Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM * failure, write 1 to clear the failure flag. Default 0. */ #define HDMITX_TOP_REVOCMEM_STAT (0x00D) -/* Bit 0 R filtered HPD status. */ +/* + * Bit 1 R filtered RxSense status + * Bit 0 R filtered HPD status. + */ #define HDMITX_TOP_STAT0 (0x00E) #endif /* __MESON_DW_HDMI_H */ diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c index 691a9fd16b36..2468b0212d52 100644 --- a/drivers/gpu/drm/meson/meson_overlay.c +++ b/drivers/gpu/drm/meson/meson_overlay.c @@ -5,25 +5,21 @@ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> #include <linux/bitfield.h> -#include <linux/platform_device.h> -#include <drm/drmP.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_device.h> +#include <drm/drm_fourcc.h> #include <drm/drm_plane_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_rect.h> #include "meson_overlay.h" -#include "meson_vpp.h" -#include "meson_viu.h" -#include "meson_canvas.h" #include "meson_registers.h" +#include "meson_viu.h" +#include "meson_vpp.h" /* VD1_IF0_GEN_REG */ #define VD_URGENT_CHROMA BIT(28) @@ -350,13 +346,6 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, DRM_DEBUG_DRIVER("\n"); - /* Fallback is canvas provider is not available */ - if (!priv->canvas) { - priv->canvas_id_vd1_0 = MESON_CANVAS_ID_VD1_0; - priv->canvas_id_vd1_1 = MESON_CANVAS_ID_VD1_1; - priv->canvas_id_vd1_2 = MESON_CANVAS_ID_VD1_2; - } - interlace_mode = state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE; spin_lock_irqsave(&priv->drm->event_lock, flags); @@ -466,7 +455,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, } /* Update Canvas with buffer address */ - priv->viu.vd1_planes = drm_format_num_planes(fb->format->format); + priv->viu.vd1_planes = fb->format->num_planes; switch (priv->viu.vd1_planes) { case 3: @@ -474,8 +463,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2]; priv->viu.vd1_stride2 = fb->pitches[2]; priv->viu.vd1_height2 = - drm_format_plane_height(fb->height, - fb->format->format, 2); + drm_format_info_plane_height(fb->format, + fb->height, 2); DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n", priv->viu.vd1_addr2, priv->viu.vd1_stride2, @@ -486,8 +475,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1]; priv->viu.vd1_stride1 = fb->pitches[1]; priv->viu.vd1_height1 = - drm_format_plane_height(fb->height, - fb->format->format, 1); + drm_format_info_plane_height(fb->format, + fb->height, 1); DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n", priv->viu.vd1_addr1, priv->viu.vd1_stride1, @@ -498,8 +487,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0]; priv->viu.vd1_stride0 = fb->pitches[0]; priv->viu.vd1_height0 = - drm_format_plane_height(fb->height, - fb->format->format, 0); + drm_format_info_plane_height(fb->format, + fb->height, 0); DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n", priv->viu.vd1_addr0, priv->viu.vd1_stride0, @@ -524,8 +513,14 @@ static void meson_overlay_atomic_disable(struct drm_plane *plane, priv->viu.vd1_enabled = false; /* Disable VD1 */ - writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, - priv->io_base + _REG(VPP_MISC)); + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); + writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); + writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0)); + writel_relaxed(0, priv->io_base + _REG(VD2_IF0_GEN_REG + 0x17b0)); + } else + writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, + priv->io_base + _REG(VPP_MISC)); } @@ -580,6 +575,9 @@ int meson_overlay_create(struct meson_drm *priv) drm_plane_helper_add(plane, &meson_overlay_helper_funcs); + /* For now, VD Overlay plane is always on the back */ + drm_plane_create_zpos_immutable_property(plane, 0); + priv->overlay_plane = plane; DRM_DEBUG_DRIVER("\n"); diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 6119a0224278..ed543227b00d 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -1,45 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <[email protected]> */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> #include <linux/bitfield.h> -#include <linux/platform_device.h> -#include <drm/drmP.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_device.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_rect.h> +#include <drm/drm_plane_helper.h> #include "meson_plane.h" -#include "meson_vpp.h" -#include "meson_viu.h" -#include "meson_canvas.h" #include "meson_registers.h" +#include "meson_viu.h" /* OSD_SCI_WH_M1 */ #define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w) @@ -148,17 +131,14 @@ static void meson_plane_atomic_update(struct drm_plane *plane, (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | OSD_BLK0_ENABLE; - if (priv->canvas) - canvas_id_osd1 = priv->canvas_id_osd1; - else - canvas_id_osd1 = MESON_CANVAS_ID_OSD1; + canvas_id_osd1 = priv->canvas_id_osd1; /* Set up BLK0 to point to the right canvas */ priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) | OSD_ENDIANNESS_LE); /* On GXBB, Use the old non-HDR RGB2YUV converter */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB; switch (fb->format->format) { @@ -169,6 +149,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | OSD_COLOR_MATRIX_32_ARGB; break; + case DRM_FORMAT_XBGR8888: + /* For XRGB, replace the pixel's alpha by 0xFF */ + writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ABGR; + break; case DRM_FORMAT_ARGB8888: /* For ARGB, use the pixel's alpha */ writel_bits_relaxed(OSD_REPLACE_EN, 0, @@ -176,6 +163,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | OSD_COLOR_MATRIX_32_ARGB; break; + case DRM_FORMAT_ABGR8888: + /* For ARGB, use the pixel's alpha */ + writel_bits_relaxed(OSD_REPLACE_EN, 0, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ABGR; + break; case DRM_FORMAT_RGB888: priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | OSD_COLOR_MATRIX_24_RGB; @@ -298,6 +292,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1; + priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1; + priv->viu.osb_blend0_size = dst_h << 16 | dst_w; + priv->viu.osb_blend1_size = dst_h << 16 | dst_w; + } + /* Update Canvas with buffer address */ gem = drm_fb_cma_get_gem_obj(fb, 0); @@ -307,13 +308,15 @@ static void meson_plane_atomic_update(struct drm_plane *plane, if (!meson_plane->enabled) { /* Reset OSD1 before enabling it on GXL+ SoCs */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) meson_viu_osd1_reset(priv); meson_plane->enabled = true; } + priv->viu.osd1_enabled = true; + spin_unlock_irqrestore(&priv->drm->event_lock, flags); } @@ -324,11 +327,15 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, struct meson_drm *priv = meson_plane->priv; /* Disable OSD1 */ - writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, - priv->io_base + _REG(VPP_MISC)); + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0, + priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); + else + writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, + priv->io_base + _REG(VPP_MISC)); meson_plane->enabled = false; - + priv->viu.osd1_enabled = false; } static const struct drm_plane_helper_funcs meson_plane_helper_funcs = { @@ -349,7 +356,9 @@ static const struct drm_plane_funcs meson_plane_funcs = { static const uint32_t supported_drm_formats[] = { DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, DRM_FORMAT_RGB888, DRM_FORMAT_RGB565, }; @@ -376,6 +385,9 @@ int meson_plane_create(struct meson_drm *priv) drm_plane_helper_add(plane, &meson_plane_helper_funcs); + /* For now, OSD Primary plane is always on the front */ + drm_plane_create_zpos_immutable_property(plane, 1); + priv->primary_plane = plane; return 0; diff --git a/drivers/gpu/drm/meson/meson_plane.h b/drivers/gpu/drm/meson/meson_plane.h index e26b8b0aa1fa..1460e182cd22 100644 --- a/drivers/gpu/drm/meson/meson_plane.h +++ b/drivers/gpu/drm/meson/meson_plane.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <[email protected]> */ diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h index 5c7e02c703bc..05fce48ceee0 100644 --- a/drivers/gpu/drm/meson/meson_registers.h +++ b/drivers/gpu/drm/meson/meson_registers.h @@ -1,26 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2015 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * */ #ifndef __MESON_REGISTERS_H #define __MESON_REGISTERS_H +#include <linux/io.h> + /* Shift all registers by 2 */ #define _REG(reg) ((reg) << 2) #define writel_bits_relaxed(mask, val, addr) \ - writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) + writel_relaxed((readl_relaxed(addr) & ~(mask)) | ((val) & (mask)), addr) /* vpp2 */ #define VPP2_DUMMY_DATA 0x1900 @@ -146,11 +138,19 @@ #define VIU_ADDR_START 0x1a00 #define VIU_ADDR_END 0x1aff #define VIU_SW_RESET 0x1a01 +#define VIU_SW_RESET_OSD1 BIT(0) #define VIU_MISC_CTRL0 0x1a06 +#define VIU_CTRL0_VD1_AFBC_MASK 0x170000 #define VIU_MISC_CTRL1 0x1a07 #define D2D3_INTF_LENGTH 0x1a08 #define D2D3_INTF_CTRL0 0x1a09 #define VIU_OSD1_CTRL_STAT 0x1a10 +#define VIU_OSD1_OSD_BLK_ENABLE BIT(0) +#define VIU_OSD1_POSTBLD_SRC_VD1 (1 << 8) +#define VIU_OSD1_POSTBLD_SRC_VD2 (2 << 8) +#define VIU_OSD1_POSTBLD_SRC_OSD1 (3 << 8) +#define VIU_OSD1_POSTBLD_SRC_OSD2 (4 << 8) +#define VIU_OSD1_OSD_ENABLE BIT(21) #define VIU_OSD1_CTRL_STAT2 0x1a2d #define VIU_OSD1_COLOR_ADDR 0x1a11 #define VIU_OSD1_COLOR 0x1a12 @@ -216,6 +216,35 @@ #define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b #define VIU_OSD2_TEST_RDDATA 0x1a4c #define VIU_OSD2_PROT_CTRL 0x1a4e +#define VIU_OSD2_MALI_UNPACK_CTRL 0x1abd +#define VIU_OSD2_DIMM_CTRL 0x1acf + +#define VIU_OSD3_CTRL_STAT 0x3d80 +#define VIU_OSD3_CTRL_STAT2 0x3d81 +#define VIU_OSD3_COLOR_ADDR 0x3d82 +#define VIU_OSD3_COLOR 0x3d83 +#define VIU_OSD3_TCOLOR_AG0 0x3d84 +#define VIU_OSD3_TCOLOR_AG1 0x3d85 +#define VIU_OSD3_TCOLOR_AG2 0x3d86 +#define VIU_OSD3_TCOLOR_AG3 0x3d87 +#define VIU_OSD3_BLK0_CFG_W0 0x3d88 +#define VIU_OSD3_BLK0_CFG_W1 0x3d8c +#define VIU_OSD3_BLK0_CFG_W2 0x3d90 +#define VIU_OSD3_BLK0_CFG_W3 0x3d94 +#define VIU_OSD3_BLK0_CFG_W4 0x3d98 +#define VIU_OSD3_BLK1_CFG_W4 0x3d99 +#define VIU_OSD3_BLK2_CFG_W4 0x3d9a +#define VIU_OSD3_FIFO_CTRL_STAT 0x3d9c +#define VIU_OSD3_TEST_RDDATA 0x3d9d +#define VIU_OSD3_PROT_CTRL 0x3d9e +#define VIU_OSD3_MALI_UNPACK_CTRL 0x3d9f +#define VIU_OSD3_DIMM_CTRL 0x3da0 + +#define VIU_OSD_DDR_PRIORITY_URGENT BIT(0) +#define VIU_OSD_HOLD_FIFO_LINES(lines) ((lines & 0x1f) << 5) +#define VIU_OSD_FIFO_DEPTH_VAL(val) ((val & 0x7f) << 12) +#define VIU_OSD_WORDS_PER_BURST(words) (((words & 0x4) >> 1) << 22) +#define VIU_OSD_FIFO_LIMITS(size) ((size & 0xf) << 24) #define VD1_IF0_GEN_REG 0x1a50 #define VD1_IF0_CANVAS0 0x1a51 @@ -287,6 +316,27 @@ #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f #define VD1_IF0_GEN_REG3 0x1aa7 + +#define VIU_OSD_BLENDO_H_START_END 0x1aa9 +#define VIU_OSD_BLENDO_V_START_END 0x1aaa +#define VIU_OSD_BLEND_GEN_CTRL0 0x1aab +#define VIU_OSD_BLEND_GEN_CTRL1 0x1aac +#define VIU_OSD_BLEND_DUMMY_DATA 0x1aad +#define VIU_OSD_BLEND_CURRENT_XY 0x1aae + +#define VIU_OSD2_MATRIX_CTRL 0x1ab0 +#define VIU_OSD2_MATRIX_COEF00_01 0x1ab1 +#define VIU_OSD2_MATRIX_COEF02_10 0x1ab2 +#define VIU_OSD2_MATRIX_COEF11_12 0x1ab3 +#define VIU_OSD2_MATRIX_COEF20_21 0x1ab4 +#define VIU_OSD2_MATRIX_COEF22 0x1ab5 +#define VIU_OSD2_MATRIX_OFFSET0_1 0x1ab6 +#define VIU_OSD2_MATRIX_OFFSET2 0x1ab7 +#define VIU_OSD2_MATRIX_PRE_OFFSET0_1 0x1ab8 +#define VIU_OSD2_MATRIX_PRE_OFFSET2 0x1ab9 +#define VIU_OSD2_MATRIX_PROBE_COLOR 0x1aba +#define VIU_OSD2_MATRIX_HL_COLOR 0x1abb +#define VIU_OSD2_MATRIX_PROBE_POS 0x1abc #define VIU_OSD1_EOTF_CTL 0x1ad4 #define VIU_OSD1_EOTF_COEF00_01 0x1ad5 #define VIU_OSD1_EOTF_COEF02_10 0x1ad6 @@ -305,6 +355,7 @@ #define VPP_LINE_IN_LENGTH 0x1d01 #define VPP_PIC_IN_HEIGHT 0x1d02 #define VPP_SCALE_COEF_IDX 0x1d03 +#define VPP_SCALE_HORIZONTAL_COEF BIT(8) #define VPP_SCALE_COEF 0x1d04 #define VPP_VSC_REGION12_STARTP 0x1d05 #define VPP_VSC_REGION34_STARTP 0x1d06 @@ -326,6 +377,12 @@ #define VPP_HSC_REGION4_PHASE_SLOPE 0x1d17 #define VPP_HSC_PHASE_CTRL 0x1d18 #define VPP_SC_MISC 0x1d19 +#define VPP_SC_VD_EN_ENABLE BIT(15) +#define VPP_SC_TOP_EN_ENABLE BIT(16) +#define VPP_SC_HSC_EN_ENABLE BIT(17) +#define VPP_SC_VSC_EN_ENABLE BIT(18) +#define VPP_VSC_BANK_LENGTH(length) (length & 0x7) +#define VPP_HSC_BANK_LENGTH(length) ((length & 0x7) << 8) #define VPP_PREBLEND_VD1_H_START_END 0x1d1a #define VPP_PREBLEND_VD1_V_START_END 0x1d1b #define VPP_POSTBLEND_VD1_H_START_END 0x1d1c @@ -335,24 +392,28 @@ #define VPP_PREBLEND_H_SIZE 0x1d20 #define VPP_POSTBLEND_H_SIZE 0x1d21 #define VPP_HOLD_LINES 0x1d22 +#define VPP_POSTBLEND_HOLD_LINES(lines) (lines & 0xf) +#define VPP_PREBLEND_HOLD_LINES(lines) ((lines & 0xf) << 8) #define VPP_BLEND_ONECOLOR_CTRL 0x1d23 #define VPP_PREBLEND_CURRENT_XY 0x1d24 #define VPP_POSTBLEND_CURRENT_XY 0x1d25 #define VPP_MISC 0x1d26 -#define VPP_PREBLEND_ENABLE BIT(6) -#define VPP_POSTBLEND_ENABLE BIT(7) -#define VPP_OSD2_ALPHA_PREMULT BIT(8) -#define VPP_OSD1_ALPHA_PREMULT BIT(9) -#define VPP_VD1_POSTBLEND BIT(10) -#define VPP_VD2_POSTBLEND BIT(11) -#define VPP_OSD1_POSTBLEND BIT(12) -#define VPP_OSD2_POSTBLEND BIT(13) -#define VPP_VD1_PREBLEND BIT(14) -#define VPP_VD2_PREBLEND BIT(15) -#define VPP_OSD1_PREBLEND BIT(16) -#define VPP_OSD2_PREBLEND BIT(17) -#define VPP_COLOR_MNG_ENABLE BIT(28) +#define VPP_PREBLEND_ENABLE BIT(6) +#define VPP_POSTBLEND_ENABLE BIT(7) +#define VPP_OSD2_ALPHA_PREMULT BIT(8) +#define VPP_OSD1_ALPHA_PREMULT BIT(9) +#define VPP_VD1_POSTBLEND BIT(10) +#define VPP_VD2_POSTBLEND BIT(11) +#define VPP_OSD1_POSTBLEND BIT(12) +#define VPP_OSD2_POSTBLEND BIT(13) +#define VPP_VD1_PREBLEND BIT(14) +#define VPP_VD2_PREBLEND BIT(15) +#define VPP_OSD1_PREBLEND BIT(16) +#define VPP_OSD2_PREBLEND BIT(17) +#define VPP_COLOR_MNG_ENABLE BIT(28) #define VPP_OFIFO_SIZE 0x1d27 +#define VPP_OFIFO_SIZE_MASK GENMASK(13, 0) +#define VPP_OFIFO_SIZE_DEFAULT (0xfff << 20 | 0x1000) #define VPP_FIFO_STATUS 0x1d28 #define VPP_SMOKE_CTRL 0x1d29 #define VPP_SMOKE1_VAL 0x1d2a @@ -368,6 +429,8 @@ #define VPP_HSC_PHASE_CTRL1 0x1d34 #define VPP_HSC_INI_PAT_CTRL 0x1d35 #define VPP_VADJ_CTRL 0x1d40 +#define VPP_MINUS_BLACK_LVL_VADJ1_ENABLE BIT(1) + #define VPP_VADJ1_Y 0x1d41 #define VPP_VADJ1_MA_MB 0x1d42 #define VPP_VADJ1_MC_MD 0x1d43 @@ -427,6 +490,7 @@ #define VPP_PEAKING_VGAIN 0x1d92 #define VPP_PEAKING_NLP_1 0x1d93 #define VPP_DOLBY_CTRL 0x1d93 +#define VPP_PPS_DUMMY_DATA_MODE (1 << 17) #define VPP_PEAKING_NLP_2 0x1d94 #define VPP_PEAKING_NLP_3 0x1d95 #define VPP_PEAKING_NLP_4 0x1d96 @@ -481,6 +545,83 @@ #define VPP_OSD_SCALE_COEF 0x1dcd #define VPP_INT_LINE_NUM 0x1dce +#define VPP_WRAP_OSD1_MATRIX_COEF00_01 0x3d60 +#define VPP_WRAP_OSD1_MATRIX_COEF02_10 0x3d61 +#define VPP_WRAP_OSD1_MATRIX_COEF11_12 0x3d62 +#define VPP_WRAP_OSD1_MATRIX_COEF20_21 0x3d63 +#define VPP_WRAP_OSD1_MATRIX_COEF22 0x3d64 +#define VPP_WRAP_OSD1_MATRIX_COEF13_14 0x3d65 +#define VPP_WRAP_OSD1_MATRIX_COEF23_24 0x3d66 +#define VPP_WRAP_OSD1_MATRIX_COEF15_25 0x3d67 +#define VPP_WRAP_OSD1_MATRIX_CLIP 0x3d68 +#define VPP_WRAP_OSD1_MATRIX_OFFSET0_1 0x3d69 +#define VPP_WRAP_OSD1_MATRIX_OFFSET2 0x3d6a +#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1 0x3d6b +#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2 0x3d6c +#define VPP_WRAP_OSD1_MATRIX_EN_CTRL 0x3d6d + +#define VPP_WRAP_OSD2_MATRIX_COEF00_01 0x3d70 +#define VPP_WRAP_OSD2_MATRIX_COEF02_10 0x3d71 +#define VPP_WRAP_OSD2_MATRIX_COEF11_12 0x3d72 +#define VPP_WRAP_OSD2_MATRIX_COEF20_21 0x3d73 +#define VPP_WRAP_OSD2_MATRIX_COEF22 0x3d74 +#define VPP_WRAP_OSD2_MATRIX_COEF13_14 0x3d75 +#define VPP_WRAP_OSD2_MATRIX_COEF23_24 0x3d76 +#define VPP_WRAP_OSD2_MATRIX_COEF15_25 0x3d77 +#define VPP_WRAP_OSD2_MATRIX_CLIP 0x3d78 +#define VPP_WRAP_OSD2_MATRIX_OFFSET0_1 0x3d79 +#define VPP_WRAP_OSD2_MATRIX_OFFSET2 0x3d7a +#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1 0x3d7b +#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2 0x3d7c +#define VPP_WRAP_OSD2_MATRIX_EN_CTRL 0x3d7d + +#define VPP_WRAP_OSD3_MATRIX_COEF00_01 0x3db0 +#define VPP_WRAP_OSD3_MATRIX_COEF02_10 0x3db1 +#define VPP_WRAP_OSD3_MATRIX_COEF11_12 0x3db2 +#define VPP_WRAP_OSD3_MATRIX_COEF20_21 0x3db3 +#define VPP_WRAP_OSD3_MATRIX_COEF22 0x3db4 +#define VPP_WRAP_OSD3_MATRIX_COEF13_14 0x3db5 +#define VPP_WRAP_OSD3_MATRIX_COEF23_24 0x3db6 +#define VPP_WRAP_OSD3_MATRIX_COEF15_25 0x3db7 +#define VPP_WRAP_OSD3_MATRIX_CLIP 0x3db8 +#define VPP_WRAP_OSD3_MATRIX_OFFSET0_1 0x3db9 +#define VPP_WRAP_OSD3_MATRIX_OFFSET2 0x3dba +#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET0_1 0x3dbb +#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2 0x3dbc +#define VPP_WRAP_OSD3_MATRIX_EN_CTRL 0x3dbd + +/* osd2 scaler */ +#define OSD2_VSC_PHASE_STEP 0x3d00 +#define OSD2_VSC_INI_PHASE 0x3d01 +#define OSD2_VSC_CTRL0 0x3d02 +#define OSD2_HSC_PHASE_STEP 0x3d03 +#define OSD2_HSC_INI_PHASE 0x3d04 +#define OSD2_HSC_CTRL0 0x3d05 +#define OSD2_HSC_INI_PAT_CTRL 0x3d06 +#define OSD2_SC_DUMMY_DATA 0x3d07 +#define OSD2_SC_CTRL0 0x3d08 +#define OSD2_SCI_WH_M1 0x3d09 +#define OSD2_SCO_H_START_END 0x3d0a +#define OSD2_SCO_V_START_END 0x3d0b +#define OSD2_SCALE_COEF_IDX 0x3d18 +#define OSD2_SCALE_COEF 0x3d19 + +/* osd34 scaler */ +#define OSD34_SCALE_COEF_IDX 0x3d1e +#define OSD34_SCALE_COEF 0x3d1f +#define OSD34_VSC_PHASE_STEP 0x3d20 +#define OSD34_VSC_INI_PHASE 0x3d21 +#define OSD34_VSC_CTRL0 0x3d22 +#define OSD34_HSC_PHASE_STEP 0x3d23 +#define OSD34_HSC_INI_PHASE 0x3d24 +#define OSD34_HSC_CTRL0 0x3d25 +#define OSD34_HSC_INI_PAT_CTRL 0x3d26 +#define OSD34_SC_DUMMY_DATA 0x3d27 +#define OSD34_SC_CTRL0 0x3d28 +#define OSD34_SCI_WH_M1 0x3d29 +#define OSD34_SCO_H_START_END 0x3d2a +#define OSD34_SCO_V_START_END 0x3d2b + /* viu2 */ #define VIU2_ADDR_START 0x1e00 #define VIU2_ADDR_END 0x1eff @@ -594,6 +735,25 @@ #define VENC_UPSAMPLE_CTRL0 0x1b64 #define VENC_UPSAMPLE_CTRL1 0x1b65 #define VENC_UPSAMPLE_CTRL2 0x1b66 +#define VENC_UPSAMPLE_CTRL_F0_2_CLK_RATIO BIT(0) +#define VENC_UPSAMPLE_CTRL_F1_EN BIT(5) +#define VENC_UPSAMPLE_CTRL_F1_UPSAMPLE_EN BIT(6) +#define VENC_UPSAMPLE_CTRL_INTERLACE_HIGH_LUMA (0x0 << 12) +#define VENC_UPSAMPLE_CTRL_CVBS (0x1 << 12) +#define VENC_UPSAMPLE_CTRL_S_VIDEO_LUMA (0x2 << 12) +#define VENC_UPSAMPLE_CTRL_S_VIDEO_CHROMA (0x3 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_PB (0x4 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_PR (0x5 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_R (0x6 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_G (0x7 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_B (0x8 << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_Y (0x9 << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_PB (0xa << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_PR (0xb << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_R (0xc << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_G (0xd << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_B (0xe << 12) +#define VENC_UPSAMPLE_CTRL_VDAC_TEST_VALUE (0xf << 12) #define TCON_INVERT_CTL 0x1b67 #define VENC_VIDEO_PROG_MODE 0x1b68 #define VENC_ENCI_LINE 0x1b69 @@ -602,6 +762,7 @@ #define VENC_ENCP_PIXEL 0x1b6c #define VENC_STATA 0x1b6d #define VENC_INTCTRL 0x1b6e +#define VENC_INTCTRL_ENCI_LNRST_INT_EN BIT(1) #define VENC_INTFLAG 0x1b6f #define VENC_VIDEO_TST_EN 0x1b70 #define VENC_VIDEO_TST_MDSEL 0x1b71 @@ -612,6 +773,7 @@ #define VENC_VIDEO_TST_CLRBAR_WIDTH 0x1b76 #define VENC_VIDEO_TST_VDCNT_STSET 0x1b77 #define VENC_VDAC_DACSEL0 0x1b78 +#define VENC_VDAC_SEL_ATV_DMD BIT(5) #define VENC_VDAC_DACSEL1 0x1b79 #define VENC_VDAC_DACSEL2 0x1b7a #define VENC_VDAC_DACSEL3 0x1b7b @@ -632,6 +794,7 @@ #define VENC_VDAC_DAC5_GAINCTRL 0x1bfa #define VENC_VDAC_DAC5_OFFSET 0x1bfb #define VENC_VDAC_FIFO_CTRL 0x1bfc +#define VENC_VDAC_FIFO_EN_ENCI_ENABLE BIT(13) #define ENCL_TCON_INVERT_CTL 0x1bfd #define ENCP_VIDEO_EN 0x1b80 #define ENCP_VIDEO_SYNC_MODE 0x1b81 @@ -647,6 +810,7 @@ #define ENCP_VIDEO_SYNC_OFFST 0x1b8b #define ENCP_VIDEO_MACV_OFFST 0x1b8c #define ENCP_VIDEO_MODE 0x1b8d +#define ENCP_VIDEO_MODE_DE_V_HIGH BIT(14) #define ENCP_VIDEO_MODE_ADV 0x1b8e #define ENCP_DBG_PX_RST 0x1b90 #define ENCP_DBG_LN_RST 0x1b91 @@ -725,6 +889,11 @@ #define C656_FS_LNED 0x1be7 #define ENCI_VIDEO_MODE 0x1b00 #define ENCI_VIDEO_MODE_ADV 0x1b01 +#define ENCI_VIDEO_MODE_ADV_DMXMD(val) (val & 0x3) +#define ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 BIT(2) +#define ENCI_VIDEO_MODE_ADV_YBW_MEDIUM (0 << 4) +#define ENCI_VIDEO_MODE_ADV_YBW_LOW (0x1 << 4) +#define ENCI_VIDEO_MODE_ADV_YBW_HIGH (0x2 << 4) #define ENCI_VIDEO_FSC_ADJ 0x1b02 #define ENCI_VIDEO_BRIGHT 0x1b03 #define ENCI_VIDEO_CONT 0x1b04 @@ -795,13 +964,17 @@ #define ENCI_DBG_MAXPX 0x1b4c #define ENCI_DBG_MAXLN 0x1b4d #define ENCI_MACV_MAX_AMP 0x1b50 +#define ENCI_MACV_MAX_AMP_ENABLE_CHANGE BIT(15) +#define ENCI_MACV_MAX_AMP_VAL(val) (val & 0x83ff) #define ENCI_MACV_PULSE_LO 0x1b51 #define ENCI_MACV_PULSE_HI 0x1b52 #define ENCI_MACV_BKP_MAX 0x1b53 #define ENCI_CFILT_CTRL 0x1b54 +#define ENCI_CFILT_CMPT_SEL_HIGH BIT(1) #define ENCI_CFILT7 0x1b55 #define ENCI_YC_DELAY 0x1b56 #define ENCI_VIDEO_EN 0x1b57 +#define ENCI_VIDEO_EN_ENABLE BIT(0) #define ENCI_DVI_HSO_BEGIN 0x1c00 #define ENCI_DVI_HSO_END 0x1c01 #define ENCI_DVI_VSO_BLINE_EVN 0x1c02 @@ -813,6 +986,10 @@ #define ENCI_DVI_VSO_END_EVN 0x1c08 #define ENCI_DVI_VSO_END_ODD 0x1c09 #define ENCI_CFILT_CTRL2 0x1c0a +#define ENCI_CFILT_CMPT_CR_DLY(delay) (delay & 0xf) +#define ENCI_CFILT_CMPT_CB_DLY(delay) ((delay & 0xf) << 4) +#define ENCI_CFILT_CVBS_CR_DLY(delay) ((delay & 0xf) << 8) +#define ENCI_CFILT_CVBS_CB_DLY(delay) ((delay & 0xf) << 12) #define ENCI_DACSEL_0 0x1c0b #define ENCI_DACSEL_1 0x1c0c #define ENCP_DACSEL_0 0x1c0d @@ -827,6 +1004,8 @@ #define ENCI_TST_CLRBAR_WIDTH 0x1c16 #define ENCI_TST_VDCNT_STSET 0x1c17 #define ENCI_VFIFO2VD_CTL 0x1c18 +#define ENCI_VFIFO2VD_CTL_ENABLE BIT(0) +#define ENCI_VFIFO2VD_CTL_VD_SEL(val) ((val & 0xff) << 8) #define ENCI_VFIFO2VD_PIXEL_START 0x1c19 #define ENCI_VFIFO2VD_PIXEL_END 0x1c1a #define ENCI_VFIFO2VD_LINE_TOP_START 0x1c1b @@ -889,6 +1068,7 @@ #define VENC_VDAC_DAC5_FILT_CTRL0 0x1c56 #define VENC_VDAC_DAC5_FILT_CTRL1 0x1c57 #define VENC_VDAC_DAC0_FILT_CTRL0 0x1c58 +#define VENC_VDAC_DAC0_FILT_CTRL0_EN BIT(0) #define VENC_VDAC_DAC0_FILT_CTRL1 0x1c59 #define VENC_VDAC_DAC1_FILT_CTRL0 0x1c5a #define VENC_VDAC_DAC1_FILT_CTRL1 0x1c5b @@ -1294,6 +1474,18 @@ #define VIU2_SEL_VENC_ENCP (2 << 2) #define VIU2_SEL_VENC_ENCT (3 << 2) #define VPU_HDMI_SETTING 0x271b +#define VPU_HDMI_ENCI_DATA_TO_HDMI BIT(0) +#define VPU_HDMI_ENCP_DATA_TO_HDMI BIT(1) +#define VPU_HDMI_INV_HSYNC BIT(2) +#define VPU_HDMI_INV_VSYNC BIT(3) +#define VPU_HDMI_OUTPUT_CRYCB (0 << 5) +#define VPU_HDMI_OUTPUT_YCBCR (1 << 5) +#define VPU_HDMI_OUTPUT_YCRCB (2 << 5) +#define VPU_HDMI_OUTPUT_CBCRY (3 << 5) +#define VPU_HDMI_OUTPUT_CBYCR (4 << 5) +#define VPU_HDMI_OUTPUT_CRCBY (5 << 5) +#define VPU_HDMI_WR_RATE(rate) (((rate & 0x1f) - 1) << 8) +#define VPU_HDMI_RD_RATE(rate) (((rate & 0x1f) - 1) << 12) #define ENCI_INFO_READ 0x271c #define ENCP_INFO_READ 0x271d #define ENCT_INFO_READ 0x271e @@ -1370,6 +1562,7 @@ #define VPU_RDARB_MODE_L1C2 0x2799 #define VPU_RDARB_MODE_L2C1 0x279d #define VPU_WRARB_MODE_L2C1 0x27a2 +#define VPU_RDARB_SLAVE_TO_MASTER_PORT(dc, port) (port << (16 + dc)) /* osd super scale */ #define OSDSR_HV_SIZEIN 0x3130 @@ -1400,4 +1593,150 @@ #define OSDSR_YBIC_VCOEF0 0x3149 #define OSDSR_CBIC_VCOEF0 0x314a +/* osd afbcd on gxtvbb */ +#define OSD1_AFBCD_ENABLE 0x31a0 +#define OSD1_AFBCD_MODE 0x31a1 +#define OSD1_AFBCD_SIZE_IN 0x31a2 +#define OSD1_AFBCD_HDR_PTR 0x31a3 +#define OSD1_AFBCD_FRAME_PTR 0x31a4 +#define OSD1_AFBCD_CHROMA_PTR 0x31a5 +#define OSD1_AFBCD_CONV_CTRL 0x31a6 +#define OSD1_AFBCD_STATUS 0x31a8 +#define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 +#define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa + +/* add for gxm and 962e dv core2 */ +#define DOLBY_CORE2A_SWAP_CTRL1 0x3434 +#define DOLBY_CORE2A_SWAP_CTRL2 0x3435 + +/* osd afbc on g12a */ +#define VPU_MAFBC_BLOCK_ID 0x3a00 +#define VPU_MAFBC_IRQ_RAW_STATUS 0x3a01 +#define VPU_MAFBC_IRQ_CLEAR 0x3a02 +#define VPU_MAFBC_IRQ_MASK 0x3a03 +#define VPU_MAFBC_IRQ_STATUS 0x3a04 +#define VPU_MAFBC_COMMAND 0x3a05 +#define VPU_MAFBC_STATUS 0x3a06 +#define VPU_MAFBC_SURFACE_CFG 0x3a07 +#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10 +#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11 +#define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12 +#define VPU_MAFBC_BUFFER_WIDTH_S0 0x3a13 +#define VPU_MAFBC_BUFFER_HEIGHT_S0 0x3a14 +#define VPU_MAFBC_BOUNDING_BOX_X_START_S0 0x3a15 +#define VPU_MAFBC_BOUNDING_BOX_X_END_S0 0x3a16 +#define VPU_MAFBC_BOUNDING_BOX_Y_START_S0 0x3a17 +#define VPU_MAFBC_BOUNDING_BOX_Y_END_S0 0x3a18 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0 0x3a19 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0 0x3a1a +#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S0 0x3a1b +#define VPU_MAFBC_PREFETCH_CFG_S0 0x3a1c + +#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1 0x3a30 +#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1 0x3a31 +#define VPU_MAFBC_FORMAT_SPECIFIER_S1 0x3a32 +#define VPU_MAFBC_BUFFER_WIDTH_S1 0x3a33 +#define VPU_MAFBC_BUFFER_HEIGHT_S1 0x3a34 +#define VPU_MAFBC_BOUNDING_BOX_X_START_S1 0x3a35 +#define VPU_MAFBC_BOUNDING_BOX_X_END_S1 0x3a36 +#define VPU_MAFBC_BOUNDING_BOX_Y_START_S1 0x3a37 +#define VPU_MAFBC_BOUNDING_BOX_Y_END_S1 0x3a38 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1 0x3a39 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1 0x3a3a +#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S1 0x3a3b +#define VPU_MAFBC_PREFETCH_CFG_S1 0x3a3c + +#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S2 0x3a50 +#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S2 0x3a51 +#define VPU_MAFBC_FORMAT_SPECIFIER_S2 0x3a52 +#define VPU_MAFBC_BUFFER_WIDTH_S2 0x3a53 +#define VPU_MAFBC_BUFFER_HEIGHT_S2 0x3a54 +#define VPU_MAFBC_BOUNDING_BOX_X_START_S2 0x3a55 +#define VPU_MAFBC_BOUNDING_BOX_X_END_S2 0x3a56 +#define VPU_MAFBC_BOUNDING_BOX_Y_START_S2 0x3a57 +#define VPU_MAFBC_BOUNDING_BOX_Y_END_S2 0x3a58 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S2 0x3a59 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S2 0x3a5a +#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S2 0x3a5b +#define VPU_MAFBC_PREFETCH_CFG_S2 0x3a5c + +#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S3 0x3a70 +#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S3 0x3a71 +#define VPU_MAFBC_FORMAT_SPECIFIER_S3 0x3a72 +#define VPU_MAFBC_BUFFER_WIDTH_S3 0x3a73 +#define VPU_MAFBC_BUFFER_HEIGHT_S3 0x3a74 +#define VPU_MAFBC_BOUNDING_BOX_X_START_S3 0x3a75 +#define VPU_MAFBC_BOUNDING_BOX_X_END_S3 0x3a76 +#define VPU_MAFBC_BOUNDING_BOX_Y_START_S3 0x3a77 +#define VPU_MAFBC_BOUNDING_BOX_Y_END_S3 0x3a78 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S3 0x3a79 +#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S3 0x3a7a +#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S3 0x3a7b +#define VPU_MAFBC_PREFETCH_CFG_S3 0x3a7c + +#define DOLBY_PATH_CTRL 0x1a0c +#define DOLBY_BYPASS_EN(val) (val & 0xf) +#define OSD_PATH_MISC_CTRL 0x1a0e +#define MALI_AFBCD_TOP_CTRL 0x1a0f + +#define VIU_OSD_BLEND_CTRL 0x39b0 +#define VIU_OSD_BLEND_REORDER(dest, src) ((src) << (dest * 4)) +#define VIU_OSD_BLEND_DIN_EN(bits) ((bits & 0xf) << 20) +#define VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 BIT(24) +#define VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 BIT(25) +#define VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 BIT(26) +#define VIU_OSD_BLEND_BLEN2_PREMULT_EN(input) ((input & 0x3) << 27) +#define VIU_OSD_BLEND_HOLD_LINES(lines) ((lines & 0x7) << 29) +#define VIU_OSD_BLEND_CTRL1 0x39c0 +#define VIU_OSD_BLEND_DIN0_SCOPE_H 0x39b1 +#define VIU_OSD_BLEND_DIN0_SCOPE_V 0x39b2 +#define VIU_OSD_BLEND_DIN1_SCOPE_H 0x39b3 +#define VIU_OSD_BLEND_DIN1_SCOPE_V 0x39b4 +#define VIU_OSD_BLEND_DIN2_SCOPE_H 0x39b5 +#define VIU_OSD_BLEND_DIN2_SCOPE_V 0x39b6 +#define VIU_OSD_BLEND_DIN3_SCOPE_H 0x39b7 +#define VIU_OSD_BLEND_DIN3_SCOPE_V 0x39b8 +#define VIU_OSD_BLEND_DUMMY_DATA0 0x39b9 +#define VIU_OSD_BLEND_DUMMY_ALPHA 0x39ba +#define VIU_OSD_BLEND_BLEND0_SIZE 0x39bb +#define VIU_OSD_BLEND_BLEND1_SIZE 0x39bc +#define VIU_OSD_BLEND_RO_CURRENT_XY 0x39bf + +#define VPP_OUT_H_V_SIZE 0x1da5 + +#define VPP_VD2_HDR_IN_SIZE 0x1df0 +#define VPP_OSD1_IN_SIZE 0x1df1 +#define VPP_GCLK_CTRL2 0x1df2 +#define VD2_PPS_DUMMY_DATA 0x1df4 +#define VPP_OSD1_BLD_H_SCOPE 0x1df5 +#define VPP_OSD1_BLD_V_SCOPE 0x1df6 +#define VPP_OSD2_BLD_H_SCOPE 0x1df7 +#define VPP_OSD2_BLD_V_SCOPE 0x1df8 +#define VPP_WRBAK_CTRL 0x1df9 +#define VPP_SLEEP_CTRL 0x1dfa +#define VD1_BLEND_SRC_CTRL 0x1dfb +#define VD2_BLEND_SRC_CTRL 0x1dfc +#define VD_BLEND_PREBLD_SRC_VD1 (1 << 0) +#define VD_BLEND_PREBLD_SRC_VD2 (2 << 0) +#define VD_BLEND_PREBLD_SRC_OSD1 (3 << 0) +#define VD_BLEND_PREBLD_SRC_OSD2 (4 << 0) +#define VD_BLEND_PREBLD_PREMULT_EN BIT(4) +#define VD_BLEND_POSTBLD_SRC_VD1 (1 << 8) +#define VD_BLEND_POSTBLD_SRC_VD2 (2 << 8) +#define VD_BLEND_POSTBLD_SRC_OSD1 (3 << 8) +#define VD_BLEND_POSTBLD_SRC_OSD2 (4 << 8) +#define VD_BLEND_POSTBLD_PREMULT_EN BIT(16) +#define OSD1_BLEND_SRC_CTRL 0x1dfd +#define OSD2_BLEND_SRC_CTRL 0x1dfe +#define OSD_BLEND_POSTBLD_SRC_VD1 (1 << 8) +#define OSD_BLEND_POSTBLD_SRC_VD2 (2 << 8) +#define OSD_BLEND_POSTBLD_SRC_OSD1 (3 << 8) +#define OSD_BLEND_POSTBLD_SRC_OSD2 (4 << 8) +#define OSD_BLEND_PATH_SEL_ENABLE BIT(20) + +#define VPP_POST_BLEND_BLEND_DUMMY_DATA 0x3968 +#define VPP_POST_BLEND_DUMMY_ALPHA 0x3969 +#define VPP_RDARB_MODE 0x3978 +#define VPP_RDARB_REQEN_SLV 0x3979 + #endif /* __MESON_REGISTERS_H */ diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index f6ba35a405f8..f690793ae2d5 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -1,25 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <drm/drmP.h> +#include <linux/export.h> + +#include <drm/drm_print.h> + #include "meson_drv.h" #include "meson_vclk.h" @@ -108,14 +97,18 @@ #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ #define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ +#define HHI_HDMI_PLL_CNTL_EN BIT(30) #define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ #define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ +#define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */ #define HDMI_PLL_RESET BIT(28) +#define HDMI_PLL_RESET_G12A BIT(29) #define HDMI_PLL_LOCK BIT(31) +#define HDMI_PLL_LOCK_G12A (3 << 30) #define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001) @@ -249,7 +242,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) unsigned int val; /* Setup PLL to output 1.485GHz */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); @@ -257,8 +250,12 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d); - } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, + (val & HDMI_PLL_LOCK), 10, 0); + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0xa6212844); @@ -271,11 +268,26 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) HDMI_PLL_RESET, HDMI_PLL_RESET); regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, HDMI_PLL_RESET, 0); - } - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, - (val & HDMI_PLL_LOCK), 10, 0); + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, + (val & HDMI_PLL_LOCK), 10, 0); + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00010000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x6a28dc00); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x56540000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x3a0504f7); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, + ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A), + 10, 0); + } /* Disable VCLK2 */ regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); @@ -288,8 +300,13 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) VCLK2_DIV_MASK, (55 - 1)); /* select vid_pll for vclk2 */ - regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, - VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, + VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT)); + else + regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, + VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); + /* enable vclk2 gate */ regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN); @@ -396,8 +413,8 @@ struct meson_vclk_params { }, [MESON_VCLK_HDMI_297000] = { .pixel_freq = 297000, - .pll_base_freq = 2970000, - .pll_od1 = 1, + .pll_base_freq = 5940000, + .pll_od1 = 2, .pll_od2 = 1, .pll_od3 = 1, .vid_pll_div = VID_PLL_DIV_5, @@ -438,7 +455,7 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, { unsigned int val; - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m); if (frac) regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, @@ -453,13 +470,13 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, /* Enable and unreset */ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - 0x7 << 28, 0x4 << 28); + 0x7 << 28, HHI_HDMI_PLL_CNTL_EN); /* Poll for lock bit */ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, (val & HDMI_PLL_LOCK), 10, 0); - } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); @@ -476,32 +493,90 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, /* Poll for lock bit */ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, (val & HDMI_PLL_LOCK), 10, 0); + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m); + + /* Enable and reset */ + /* TODO: add specific macro for g12a here */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 0x3 << 28, 0x3 << 28); + + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); + + /* G12A HDMI PLL Needs specific parameters for 5.4GHz */ + if (m >= 0xf7) { + if (frac < 0x10000) { + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, + 0x6a685c00); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, + 0x11551293); + } else { + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, + 0xea68dc00); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, + 0x65771290); + } + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000); + } else { + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000); + } + + do { + /* Reset PLL */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A); + + /* UN-Reset PLL */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + HDMI_PLL_RESET_G12A, 0); + + /* Poll for lock bits */ + if (!regmap_read_poll_timeout(priv->hhi, + HHI_HDMI_PLL_CNTL, val, + ((val & HDMI_PLL_LOCK_G12A) + == HDMI_PLL_LOCK_G12A), + 10, 100)) + break; + } while(1); } - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, 3 << 16, pll_od_to_reg(od1) << 16); - else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, 3 << 21, pll_od_to_reg(od1) << 21); + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 3 << 16, pll_od_to_reg(od1) << 16); - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, 3 << 22, pll_od_to_reg(od2) << 22); - else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, 3 << 23, pll_od_to_reg(od2) << 23); + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 3 << 18, pll_od_to_reg(od2) << 18); - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, 3 << 18, pll_od_to_reg(od3) << 18); - else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, 3 << 19, pll_od_to_reg(od3) << 19); - + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 3 << 20, pll_od_to_reg(od3) << 20); } #define XTAL_FREQ 24000 @@ -510,7 +585,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, unsigned int pll_freq) { /* The GXBB PLL has a /2 pre-multiplier */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) pll_freq /= 2; return pll_freq / XTAL_FREQ; @@ -518,6 +593,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, #define HDMI_FRAC_MAX_GXBB 4096 #define HDMI_FRAC_MAX_GXL 1024 +#define HDMI_FRAC_MAX_G12A 131072 static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, unsigned int m, @@ -529,11 +605,14 @@ static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, unsigned int frac; /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) { frac_max = HDMI_FRAC_MAX_GXBB; parent_freq *= 2; } + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + frac_max = HDMI_FRAC_MAX_G12A; + /* We can have a perfect match !*/ if (pll_freq / m == parent_freq && pll_freq % m == 0) @@ -552,19 +631,25 @@ static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, unsigned int m, unsigned int frac) { - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) { /* Empiric supported min/max dividers */ if (m < 53 || m > 123) return false; if (frac >= HDMI_FRAC_MAX_GXBB) return false; - } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) { /* Empiric supported min/max dividers */ if (m < 106 || m > 247) return false; if (frac >= HDMI_FRAC_MAX_GXL) return false; + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + /* Empiric supported min/max dividers */ + if (m < 106 || m > 247) + return false; + if (frac >= HDMI_FRAC_MAX_G12A) + return false; } return true; @@ -679,7 +764,7 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, /* Set HDMI PLL rate */ if (!od1 && !od2 && !od3) { meson_hdmi_pll_generic_set(priv, pll_base_freq); - } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) { switch (pll_base_freq) { case 2970000: m = 0x3d; @@ -696,8 +781,8 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, } meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); - } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) { switch (pll_base_freq) { case 2970000: m = 0x7b; @@ -714,6 +799,23 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, } meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + switch (pll_base_freq) { + case 2970000: + m = 0x7b; + frac = vic_alternate_clock ? 0x140b4 : 0x18000; + break; + case 4320000: + m = vic_alternate_clock ? 0xb3 : 0xb4; + frac = vic_alternate_clock ? 0x1a3ee : 0; + break; + case 5940000: + m = 0xf7; + frac = vic_alternate_clock ? 0x8148 : 0x10000; + break; + } + + meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); } /* Setup vid_pll divider */ @@ -875,7 +977,8 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, meson_venci_cvbs_clock_config(priv); return; } else if (target == MESON_VCLK_TARGET_DMT) { - /* The DMT clock path is fixed after the PLL: + /* + * The DMT clock path is fixed after the PLL: * - automatic PLL freq + OD management * - vid_pll_div = VID_PLL_DIV_5 * - vclk_div = 2 diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h index 4bd8752da02a..b62125540aef 100644 --- a/drivers/gpu/drm/meson/meson_vclk.h +++ b/drivers/gpu/drm/meson/meson_vclk.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* Video Clock */ @@ -21,6 +9,10 @@ #ifndef __MESON_VCLK_H #define __MESON_VCLK_H +#include <drm/drm_modes.h> + +struct meson_drm; + enum { MESON_VCLK_TARGET_CVBS = 0, MESON_VCLK_TARGET_HDMI = 1, diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 66d73a932d19..4efd7864d5bf 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -1,30 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <drm/drmP.h> +#include <linux/export.h> + +#include <drm/drm_modes.h> + #include "meson_drv.h" +#include "meson_registers.h" #include "meson_venc.h" #include "meson_vpp.h" -#include "meson_vclk.h" -#include "meson_registers.h" /** * DOC: Video Encoder @@ -73,7 +61,9 @@ /* HHI Registers */ #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ +#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbb offset in data sheet */ #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ +#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbc offset in data sheet */ #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { @@ -202,7 +192,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = { .hso_end = 129, .vso_even = 3, .vso_odd = 260, - .macv_max_amp = 0x810b, + .macv_max_amp = 0xb, .video_prog_mode = 0xf0, .video_mode = 0x8, .sch_adjust = 0x20, @@ -222,7 +212,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = { .hso_end = 129, .vso_even = 3, .vso_odd = 260, - .macv_max_amp = 8107, + .macv_max_amp = 0x7, .video_prog_mode = 0xff, .video_mode = 0x13, .sch_adjust = 0x28, @@ -986,6 +976,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int eof_lines; unsigned int sof_lines; unsigned int vsync_lines; + u32 reg; /* Use VENCI for 480i and 576i and double HDMI pixels */ if (mode->flags & DRM_MODE_FLAG_DBLCLK) { @@ -1058,8 +1049,11 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int lines_f1; /* CVBS Filter settings */ - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); + writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0x10, + priv->io_base + _REG(ENCI_CFILT_CTRL)); + writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2) | + ENCI_CFILT_CMPT_CB_DLY(1), + priv->io_base + _REG(ENCI_CFILT_CTRL2)); /* Digital Video Select : Interlace, clk27 clk, external */ writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); @@ -1081,8 +1075,9 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); /* Macrovision max amplitude change */ - writel_relaxed(vmode->enci.macv_max_amp, - priv->io_base + _REG(ENCI_MACV_MAX_AMP)); + writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE | + ENCI_MACV_MAX_AMP_VAL(vmode->enci.macv_max_amp), + priv->io_base + _REG(ENCI_MACV_MAX_AMP)); /* Video mode */ writel_relaxed(vmode->enci.video_prog_mode, @@ -1090,7 +1085,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, writel_relaxed(vmode->enci.video_mode, priv->io_base + _REG(ENCI_VIDEO_MODE)); - /* Advanced Video Mode : + /* + * Advanced Video Mode : * Demux shifting 0x2 * Blank line end at line17/22 * High bandwidth Luma Filter @@ -1098,7 +1094,10 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, * Bypass luma low pass filter * No macrovision on CSYNC */ - writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + writel_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2) | + ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 | + ENCI_VIDEO_MODE_ADV_YBW_HIGH, + priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); writel(vmode->enci.sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH)); @@ -1114,8 +1113,17 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, /* UNreset Interlaced TV Encoder */ writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); - /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ - writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); + /* + * Enable Vfifo2vd and set Y_Cb_Y_Cr: + * Corresponding value: + * Y => 00 or 10 + * Cb => 01 + * Cr => 11 + * Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y + */ + writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE | + ENCI_VFIFO2VD_CTL_VD_SEL(0x4e), + priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); /* Timings */ writel_relaxed(vmode->enci.pixel_start, @@ -1137,7 +1145,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); /* Interlace video enable */ - writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + writel_relaxed(ENCI_VIDEO_EN_ENABLE, + priv->io_base + _REG(ENCI_VIDEO_EN)); lines_f0 = mode->vtotal >> 1; lines_f1 = lines_f0 + 1; @@ -1384,7 +1393,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); /* Set DE signal’s polarity is active high */ - writel_bits_relaxed(BIT(14), BIT(14), + writel_bits_relaxed(ENCP_VIDEO_MODE_DE_V_HIGH, + ENCP_VIDEO_MODE_DE_V_HIGH, priv->io_base + _REG(ENCP_VIDEO_MODE)); /* Program DE timing */ @@ -1503,13 +1513,39 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCP); } - writel_relaxed((use_enci ? 1 : 2) | - (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) | - (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) | - 4 << 5 | - (venc_repeat ? 1 << 8 : 0) | - (hdmi_repeat ? 1 << 12 : 0), - priv->io_base + _REG(VPU_HDMI_SETTING)); + /* Set VPU HDMI setting */ + /* Select ENCP or ENCI data to HDMI */ + if (use_enci) + reg = VPU_HDMI_ENCI_DATA_TO_HDMI; + else + reg = VPU_HDMI_ENCP_DATA_TO_HDMI; + + /* Invert polarity of HSYNC from VENC */ + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + reg |= VPU_HDMI_INV_HSYNC; + + /* Invert polarity of VSYNC from VENC */ + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + reg |= VPU_HDMI_INV_VSYNC; + + /* Output data format: CbYCr */ + reg |= VPU_HDMI_OUTPUT_CBYCR; + + /* + * Write rate to the async FIFO between VENC and HDMI. + * One write every 2 wr_clk. + */ + if (venc_repeat) + reg |= VPU_HDMI_WR_RATE(2); + + /* + * Read rate to the async FIFO between VENC and HDMI. + * One read every 2 wr_clk. + */ + if (hdmi_repeat) + reg |= VPU_HDMI_RD_RATE(2); + + writel_relaxed(reg, priv->io_base + _REG(VPU_HDMI_SETTING)); priv->venc.hdmi_repeat = hdmi_repeat; priv->venc.venc_repeat = venc_repeat; @@ -1522,12 +1558,17 @@ EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set); void meson_venci_cvbs_mode_set(struct meson_drm *priv, struct meson_cvbs_enci_mode *mode) { + u32 reg; + if (mode->mode_tag == priv->venc.current_mode) return; /* CVBS Filter settings */ - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); + writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0x10, + priv->io_base + _REG(ENCI_CFILT_CTRL)); + writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2) | + ENCI_CFILT_CMPT_CB_DLY(1), + priv->io_base + _REG(ENCI_CFILT_CTRL2)); /* Digital Video Select : Interlace, clk27 clk, external */ writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); @@ -1549,8 +1590,9 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); /* Macrovision max amplitude change */ - writel_relaxed(0x8100 + mode->macv_max_amp, - priv->io_base + _REG(ENCI_MACV_MAX_AMP)); + writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE | + ENCI_MACV_MAX_AMP_VAL(mode->macv_max_amp), + priv->io_base + _REG(ENCI_MACV_MAX_AMP)); /* Video mode */ writel_relaxed(mode->video_prog_mode, @@ -1558,7 +1600,8 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, writel_relaxed(mode->video_mode, priv->io_base + _REG(ENCI_VIDEO_MODE)); - /* Advanced Video Mode : + /* + * Advanced Video Mode : * Demux shifting 0x2 * Blank line end at line17/22 * High bandwidth Luma Filter @@ -1566,7 +1609,10 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, * Bypass luma low pass filter * No macrovision on CSYNC */ - writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + writel_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2) | + ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 | + ENCI_VIDEO_MODE_ADV_YBW_HIGH, + priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); writel(mode->sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH)); @@ -1598,16 +1644,50 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, /* UNreset Interlaced TV Encoder */ writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); - /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ - writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); + /* + * Enable Vfifo2vd and set Y_Cb_Y_Cr: + * Corresponding value: + * Y => 00 or 10 + * Cb => 01 + * Cr => 11 + * Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y + */ + writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE | + ENCI_VFIFO2VD_CTL_VD_SEL(0x4e), + priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); /* Power UP Dacs */ writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_SETTING)); /* Video Upsampling */ - writel_relaxed(0x0061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL0)); - writel_relaxed(0x4061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL1)); - writel_relaxed(0x5061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL2)); + /* + * CTRL0, CTRL1 and CTRL2: + * Filter0: input data sample every 2 cloks + * Filter1: filtering and upsample enable + */ + reg = VENC_UPSAMPLE_CTRL_F0_2_CLK_RATIO | VENC_UPSAMPLE_CTRL_F1_EN | + VENC_UPSAMPLE_CTRL_F1_UPSAMPLE_EN; + + /* + * Upsample CTRL0: + * Interlace High Bandwidth Luma + */ + writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_HIGH_LUMA | reg, + priv->io_base + _REG(VENC_UPSAMPLE_CTRL0)); + + /* + * Upsample CTRL1: + * Interlace Pb + */ + writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PB | reg, + priv->io_base + _REG(VENC_UPSAMPLE_CTRL1)); + + /* + * Upsample CTRL2: + * Interlace R + */ + writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PR | reg, + priv->io_base + _REG(VENC_UPSAMPLE_CTRL2)); /* Select Interlace Y DACs */ writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); @@ -1621,14 +1701,16 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); /* Enable ENCI FIFO */ - writel_relaxed(0x2000, priv->io_base + _REG(VENC_VDAC_FIFO_CTRL)); + writel_relaxed(VENC_VDAC_FIFO_EN_ENCI_ENABLE, + priv->io_base + _REG(VENC_VDAC_FIFO_CTRL)); /* Select ENCI DACs 0, 1, 4, and 5 */ writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_0)); writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_1)); /* Interlace video enable */ - writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + writel_relaxed(ENCI_VIDEO_EN_ENABLE, + priv->io_base + _REG(ENCI_VIDEO_EN)); /* Configure Video Saturation / Contrast / Brightness / Hue */ writel_relaxed(mode->video_saturation, @@ -1641,7 +1723,8 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, priv->io_base + _REG(ENCI_VIDEO_HUE)); /* Enable DAC0 Filter */ - writel_relaxed(0x1, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0)); + writel_relaxed(VENC_VDAC_DAC0_FILT_CTRL0_EN, + priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0)); writel_relaxed(0xfc48, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL1)); /* 0 in Macrovision register 0 */ @@ -1662,7 +1745,8 @@ unsigned int meson_venci_get_field(struct meson_drm *priv) void meson_venc_enable_vsync(struct meson_drm *priv) { - writel_relaxed(2, priv->io_base + _REG(VENC_INTCTRL)); + writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN, + priv->io_base + _REG(VENC_INTCTRL)); regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25)); } @@ -1675,8 +1759,13 @@ void meson_venc_disable_vsync(struct meson_drm *priv) void meson_venc_init(struct meson_drm *priv) { /* Disable CVBS VDAC */ - regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); - regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); + regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8); + } else { + regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); + regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); + } /* Power Down Dacs */ writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); @@ -1685,7 +1774,8 @@ void meson_venc_init(struct meson_drm *priv) regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); /* Disable HDMI */ - writel_bits_relaxed(0x3, 0, + writel_bits_relaxed(VPU_HDMI_ENCI_DATA_TO_HDMI | + VPU_HDMI_ENCP_DATA_TO_HDMI, 0, priv->io_base + _REG(VPU_HDMI_SETTING)); /* Disable all encoders */ diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h index 97eaebbfa0c4..576768bdd08d 100644 --- a/drivers/gpu/drm/meson/meson_venc.h +++ b/drivers/gpu/drm/meson/meson_venc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* @@ -26,6 +14,8 @@ #ifndef __MESON_VENC_H #define __MESON_VENC_H +struct drm_display_mode; + enum { MESON_VENC_MODE_NONE = 0, MESON_VENC_MODE_CVBS_PAL, diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index d622d817b6df..9ab27aecfcf3 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -1,43 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <[email protected]> */ -#include <linux/kernel.h> -#include <linux/module.h> +#include <linux/export.h> #include <linux/of_graph.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_device.h> #include <drm/drm_edid.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_print.h> -#include "meson_venc_cvbs.h" -#include "meson_venc.h" -#include "meson_vclk.h" #include "meson_registers.h" +#include "meson_vclk.h" +#include "meson_venc_cvbs.h" /* HHI VDAC Registers */ #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ +#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ +#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ struct meson_venc_cvbs { struct drm_encoder encoder; @@ -166,8 +155,13 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder) struct meson_drm *priv = meson_venc_cvbs->priv; /* Disable CVBS VDAC */ - regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); - regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); + regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); + } else { + regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); + regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); + } } static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) @@ -177,15 +171,20 @@ static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) struct meson_drm *priv = meson_venc_cvbs->priv; /* VDAC0 source is not from ATV */ - writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); + writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0, + priv->io_base + _REG(VENC_VDAC_DACSEL0)); - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) { regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1); - else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) { regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001); - - regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); + regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); + } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001); + regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); + } } static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.h b/drivers/gpu/drm/meson/meson_venc_cvbs.h index 9256ccf9d931..ab7f76ba469c 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.h +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <[email protected]> */ diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index e46e05f50bad..68cf2c2eca5f 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -1,31 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * Copyright (C) 2014 Endless Mobile - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <drm/drmP.h> +#include <linux/export.h> + #include "meson_drv.h" #include "meson_viu.h" -#include "meson_vpp.h" -#include "meson_venc.h" -#include "meson_canvas.h" #include "meson_registers.h" /** @@ -91,8 +75,36 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { EOTF_COEFF_RIGHTSHIFT /* right shift */ }; -void meson_viu_set_osd_matrix(struct meson_drm *priv, - enum viu_matrix_sel_e m_select, +static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, + int *m, bool csc_on) +{ + /* VPP WRAP OSD1 matrix */ + writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1)); + writel(m[2] & 0xfff, + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2)); + writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01)); + writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10)); + writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12)); + writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21)); + writel((m[11] & 0x1fff) << 16, + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22)); + + writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff), + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1)); + writel(m[20] & 0xfff, + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2)); + + writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); +} + +static void meson_viu_set_osd_matrix(struct meson_drm *priv, + enum viu_matrix_sel_e m_select, int *m, bool csc_on) { if (m_select == VIU_MATRIX_OSD) { @@ -160,10 +172,10 @@ void meson_viu_set_osd_matrix(struct meson_drm *priv, #define OSD_EOTF_LUT_SIZE 33 #define OSD_OETF_LUT_SIZE 41 -void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, - unsigned int *r_map, unsigned int *g_map, - unsigned int *b_map, - bool csc_on) +static void +meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, + unsigned int *r_map, unsigned int *g_map, + unsigned int *b_map, bool csc_on) { unsigned int addr_port; unsigned int data_port; @@ -308,9 +320,9 @@ void meson_viu_osd1_reset(struct meson_drm *priv) priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); /* Reset OSD1 */ - writel_bits_relaxed(BIT(0), BIT(0), + writel_bits_relaxed(VIU_SW_RESET_OSD1, VIU_SW_RESET_OSD1, priv->io_base + _REG(VIU_SW_RESET)); - writel_bits_relaxed(BIT(0), 0, + writel_bits_relaxed(VIU_SW_RESET_OSD1, 0, priv->io_base + _REG(VIU_SW_RESET)); /* Rewrite these registers state lost in the reset */ @@ -323,28 +335,43 @@ void meson_viu_osd1_reset(struct meson_drm *priv) meson_viu_load_matrix(priv); } +static inline uint32_t meson_viu_osd_burst_length_reg(uint32_t length) +{ + uint32_t val = (((length & 0x80) % 24) / 12); + + return (((val & 0x3) << 10) | (((val & 0x4) >> 2) << 31)); +} + void meson_viu_init(struct meson_drm *priv) { uint32_t reg; /* Disable OSDs */ - writel_bits_relaxed(BIT(0) | BIT(21), 0, - priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); - writel_bits_relaxed(BIT(0) | BIT(21), 0, - priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); + writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); + writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, + priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); /* On GXL/GXM, Use the 10bit HDR conversion matrix */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) meson_viu_load_matrix(priv); + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff, + true); /* Initialize OSD1 fifo control register */ - reg = BIT(0) | /* Urgent DDR request priority */ - (4 << 5) | /* hold_fifo_lines */ - (3 << 10) | /* burst length 64 */ - (32 << 12) | /* fifo_depth_val: 32*8=256 */ - (2 << 22) | /* 4 words in 1 burst */ - (2 << 24); + reg = VIU_OSD_DDR_PRIORITY_URGENT | + VIU_OSD_HOLD_FIFO_LINES(4) | + VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */ + VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */ + VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */ + + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + reg |= meson_viu_osd_burst_length_reg(32); + else + reg |= meson_viu_osd_burst_length_reg(64); + writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); @@ -357,12 +384,9 @@ void meson_viu_init(struct meson_drm *priv) priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); /* Disable VD1 AFBC */ - /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */ - writel_bits_relaxed(0x7 << 16, 0, - priv->io_base + _REG(VIU_MISC_CTRL0)); - /* afbc vd1 set=0 */ - writel_bits_relaxed(BIT(20), 0, - priv->io_base + _REG(VIU_MISC_CTRL0)); + /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/ + writel_bits_relaxed(VIU_CTRL0_VD1_AFBC_MASK, 0, + priv->io_base + _REG(VIU_MISC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); writel_relaxed(0x00FF00C0, @@ -370,6 +394,33 @@ void meson_viu_init(struct meson_drm *priv) writel_relaxed(0x00FF00C0, priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) | + VIU_OSD_BLEND_REORDER(1, 0) | + VIU_OSD_BLEND_REORDER(2, 0) | + VIU_OSD_BLEND_REORDER(3, 0) | + VIU_OSD_BLEND_DIN_EN(1) | + VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 | + VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 | + VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 | + VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) | + VIU_OSD_BLEND_HOLD_LINES(4), + priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); + + writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, + priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); + writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, + priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); + writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); + writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); + writel_relaxed(0, + priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); + writel_relaxed(0, + priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); + + writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc), + priv->io_base + _REG(DOLBY_PATH_CTRL)); + } priv->viu.osd1_enabled = false; priv->viu.osd1_commit = false; diff --git a/drivers/gpu/drm/meson/meson_viu.h b/drivers/gpu/drm/meson/meson_viu.h index 0f84bddd2ff0..a112e8d18850 100644 --- a/drivers/gpu/drm/meson/meson_viu.h +++ b/drivers/gpu/drm/meson/meson_viu.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* Video Input Unit */ diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index f9efb431e953..154837688ab0 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -1,29 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * Copyright (C) 2014 Endless Mobile - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <drm/drmP.h> +#include <linux/export.h> + #include "meson_drv.h" -#include "meson_vpp.h" #include "meson_registers.h" +#include "meson_vpp.h" /** * DOC: Video Post Processing @@ -69,7 +56,7 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv, { int i; - writel_relaxed(is_horizontal ? BIT(8) : 0, + 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], @@ -94,7 +81,7 @@ static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv, { int i; - writel_relaxed(is_horizontal ? BIT(8) : 0, + 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], @@ -104,49 +91,63 @@ static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv, void meson_vpp_init(struct meson_drm *priv) { /* set dummy data default YUV black */ - if (meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + 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, "amlogic,meson-gxm-vpu")) { + 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(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL)); + writel_relaxed(VPP_PPS_DUMMY_DATA_MODE, + priv->io_base + _REG(VPP_DOLBY_CTRL)); writel_relaxed(0x1020080, priv->io_base + _REG(VPP_DUMMY_DATA1)); - } + } 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 */ - writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | - 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); - writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES)); - - /* 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)); + 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)); - writel_relaxed(4 | (4 << 8) | BIT(15), + + /* 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)); - writel_relaxed(1, priv->io_base + _REG(VPP_VADJ_CTRL)); + /* 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, diff --git a/drivers/gpu/drm/meson/meson_vpp.h b/drivers/gpu/drm/meson/meson_vpp.h index 815177cc7dfd..afc9553ed8d3 100644 --- a/drivers/gpu/drm/meson/meson_vpp.h +++ b/drivers/gpu/drm/meson/meson_vpp.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <[email protected]> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* Video Post Process */ @@ -21,6 +9,9 @@ #ifndef __MESON_VPP_H #define __MESON_VPP_H +struct drm_rect; +struct meson_drm; + /* Mux VIU/VPP to ENCI */ #define MESON_VIU_VPP_MUX_ENCI 0x5 /* Mux VIU/VPP to ENCP */ |