mirror of https://github.com/armbian/build.git
2132 lines
70 KiB
Diff
2132 lines
70 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
|
Date: Sun, 5 May 2019 02:29:42 +0200
|
|
Subject: drm/meson: Add support for the Meson8/8b/8m2 TranSwitch HDMI
|
|
transmitter - WiP
|
|
|
|
WiP
|
|
|
|
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
|
---
|
|
drivers/gpu/drm/meson/Kconfig | 10 +
|
|
drivers/gpu/drm/meson/Makefile | 1 +
|
|
drivers/gpu/drm/meson/meson_transwitch_hdmi.c | 1537 ++++++++++
|
|
drivers/gpu/drm/meson/meson_transwitch_hdmi.h | 536 ++++
|
|
4 files changed, 2084 insertions(+)
|
|
|
|
diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/gpu/drm/meson/Kconfig
|
|
+++ b/drivers/gpu/drm/meson/Kconfig
|
|
@@ -25,3 +25,13 @@ config DRM_MESON_DW_MIPI_DSI
|
|
default y if DRM_MESON
|
|
select DRM_DW_MIPI_DSI
|
|
select GENERIC_PHY_MIPI_DPHY
|
|
+
|
|
+config DRM_MESON_TRANSWITCH_HDMI
|
|
+ tristate "Amlogic Meson8/8b/8m2 TranSwitch HDMI 1.4 Controller support"
|
|
+ depends on ARM || COMPILE_TEST
|
|
+ depends on DRM_MESON
|
|
+ default y if DRM_MESON
|
|
+ select DRM_DISPLAY_HDMI_HELPER
|
|
+ select DRM_DISPLAY_HELPER
|
|
+ select REGMAP_MMIO
|
|
+ select SND_SOC_HDMI_CODEC if SND_SOC
|
|
diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/gpu/drm/meson/Makefile
|
|
+++ b/drivers/gpu/drm/meson/Makefile
|
|
@@ -7,3 +7,4 @@ meson-drm-y += meson_encoder_hdmi.o meson_encoder_dsi.o
|
|
obj-$(CONFIG_DRM_MESON) += meson-drm.o
|
|
obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
|
|
obj-$(CONFIG_DRM_MESON_DW_MIPI_DSI) += meson_dw_mipi_dsi.o
|
|
+obj-$(CONFIG_DRM_MESON_TRANSWITCH_HDMI) += meson_transwitch_hdmi.o
|
|
diff --git a/drivers/gpu/drm/meson/meson_transwitch_hdmi.c b/drivers/gpu/drm/meson/meson_transwitch_hdmi.c
|
|
new file mode 100644
|
|
index 000000000000..111111111111
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/meson/meson_transwitch_hdmi.c
|
|
@@ -0,0 +1,1537 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
|
+ *
|
|
+ * All registers and magic values are taken from Amlogic's GPL kernel sources:
|
|
+ * Copyright (C) 2010 Amlogic, Inc.
|
|
+ */
|
|
+
|
|
+#include <linux/clk.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/phy/phy.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/regmap.h>
|
|
+
|
|
+#include <drm/display/drm_hdmi_helper.h>
|
|
+#include <drm/drm_atomic_helper.h>
|
|
+#include <drm/drm_bridge.h>
|
|
+#include <drm/drm_connector.h>
|
|
+#include <drm/drm_device.h>
|
|
+#include <drm/drm_edid.h>
|
|
+#include <drm/drm_probe_helper.h>
|
|
+#include <drm/drm_print.h>
|
|
+
|
|
+#include <sound/hdmi-codec.h>
|
|
+
|
|
+#include <uapi/linux/media-bus-format.h>
|
|
+
|
|
+#include "meson_transwitch_hdmi.h"
|
|
+
|
|
+#define HDMI_ADDR_PORT 0x0
|
|
+#define HDMI_DATA_PORT 0x4
|
|
+#define HDMI_CTRL_PORT 0x8
|
|
+ #define HDMI_CTRL_PORT_APB3_ERR_EN BIT(15)
|
|
+
|
|
+struct meson_txc_hdmi {
|
|
+ struct device *dev;
|
|
+
|
|
+ struct regmap *regmap;
|
|
+
|
|
+ struct clk *pclk;
|
|
+ struct clk *sys_clk;
|
|
+
|
|
+ struct phy *phy;
|
|
+ bool phy_is_on;
|
|
+
|
|
+ struct mutex codec_mutex;
|
|
+ enum drm_connector_status last_connector_status;
|
|
+ hdmi_codec_plugged_cb codec_plugged_cb;
|
|
+ struct device *codec_dev;
|
|
+
|
|
+ struct platform_device *hdmi_codec_pdev;
|
|
+
|
|
+ struct drm_connector *current_connector;
|
|
+
|
|
+ struct drm_bridge bridge;
|
|
+ struct drm_bridge *next_bridge;
|
|
+};
|
|
+
|
|
+#define bridge_to_meson_txc_hdmi(x) container_of(x, struct meson_txc_hdmi, bridge)
|
|
+
|
|
+static const struct regmap_range meson_txc_hdmi_regmap_ranges[] = {
|
|
+ regmap_reg_range(0x0000, 0x07ff),
|
|
+ regmap_reg_range(0x8000, 0x800c),
|
|
+};
|
|
+
|
|
+static const struct regmap_access_table meson_txc_hdmi_regmap_access = {
|
|
+ .yes_ranges = meson_txc_hdmi_regmap_ranges,
|
|
+ .n_yes_ranges = ARRAY_SIZE(meson_txc_hdmi_regmap_ranges),
|
|
+};
|
|
+
|
|
+static int meson_txc_hdmi_reg_read(void *context, unsigned int addr,
|
|
+ unsigned int *data)
|
|
+{
|
|
+ void __iomem *base = context;
|
|
+
|
|
+ writel(addr, base + HDMI_ADDR_PORT);
|
|
+ writel(addr, base + HDMI_ADDR_PORT);
|
|
+
|
|
+ *data = readl(base + HDMI_DATA_PORT);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_reg_write(void *context, unsigned int addr,
|
|
+ unsigned int data)
|
|
+{
|
|
+ void __iomem *base = context;
|
|
+
|
|
+ writel(addr, base + HDMI_ADDR_PORT);
|
|
+ writel(addr, base + HDMI_ADDR_PORT);
|
|
+
|
|
+ writel(data, base + HDMI_DATA_PORT);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct regmap_config meson_txc_hdmi_regmap_config = {
|
|
+ .reg_bits = 16,
|
|
+ .val_bits = 16,
|
|
+ .reg_stride = 1,
|
|
+ .reg_read = meson_txc_hdmi_reg_read,
|
|
+ .reg_write = meson_txc_hdmi_reg_write,
|
|
+ .rd_table = &meson_txc_hdmi_regmap_access,
|
|
+ .wr_table = &meson_txc_hdmi_regmap_access,
|
|
+ .max_register = HDMI_OTHER_RX_PACKET_INTR_CLR,
|
|
+ .fast_io = true,
|
|
+};
|
|
+
|
|
+static void meson_txc_hdmi_write_infoframe(struct regmap *regmap,
|
|
+ unsigned int tx_pkt_reg, u8 *buf,
|
|
+ unsigned int len, bool enable)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ /* Write the data bytes by starting at register offset 1 */
|
|
+ for (i = HDMI_INFOFRAME_HEADER_SIZE; i < len; i++)
|
|
+ regmap_write(regmap,
|
|
+ tx_pkt_reg + i - HDMI_INFOFRAME_HEADER_SIZE + 1,
|
|
+ buf[i]);
|
|
+
|
|
+ /* Zero all remaining data bytes */
|
|
+ for (; i < 0x1c; i++)
|
|
+ regmap_write(regmap, tx_pkt_reg + i, 0x00);
|
|
+
|
|
+ /* Write the header (which we skipped above) */
|
|
+ regmap_write(regmap, tx_pkt_reg + 0x00, buf[3]);
|
|
+ regmap_write(regmap, tx_pkt_reg + 0x1c, buf[0]);
|
|
+ regmap_write(regmap, tx_pkt_reg + 0x1d, buf[1]);
|
|
+ regmap_write(regmap, tx_pkt_reg + 0x1e, buf[2]);
|
|
+
|
|
+ regmap_write(regmap, tx_pkt_reg + 0x1f, enable ? 0xff : 0x00);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_disable_infoframe(struct meson_txc_hdmi *priv,
|
|
+ unsigned int tx_pkt_reg)
|
|
+{
|
|
+ u8 buf[HDMI_INFOFRAME_HEADER_SIZE] = { 0 };
|
|
+
|
|
+ meson_txc_hdmi_write_infoframe(priv->regmap, tx_pkt_reg, buf,
|
|
+ HDMI_INFOFRAME_HEADER_SIZE, false);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_sys5_reset_assert(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ /* A comment in the vendor driver says: bit5,6 is converted */
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2,
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH3_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH0_RST_IN);
|
|
+ usleep_range(10, 20);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2,
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN);
|
|
+ usleep_range(10, 20);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1,
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_PIXEL_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_I2S_RESET_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH2 |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH1 |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH0);
|
|
+ usleep_range(10, 20);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_sys5_reset_deassert(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ /* Release the resets except tmds_clk */
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1,
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN);
|
|
+ usleep_range(10, 20);
|
|
+
|
|
+ /* Release the tmds_clk reset as well */
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, 0x0);
|
|
+ usleep_range(10, 20);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2,
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_SR_RST);
|
|
+ usleep_range(10, 20);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2,
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN);
|
|
+ usleep_range(10, 20);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_config_hdcp_registers(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ regmap_write(priv->regmap, TX_HDCP_CONFIG0,
|
|
+ FIELD_PREP(TX_HDCP_CONFIG0_ROM_ENCRYPT_OFF, 0x3));
|
|
+ regmap_write(priv->regmap, TX_HDCP_MEM_CONFIG, 0x0);
|
|
+ regmap_write(priv->regmap, TX_HDCP_ENCRYPT_BYTE, 0x0);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_HDCP_MODE, TX_HDCP_MODE_CLEAR_AVMUTE);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_HDCP_MODE, TX_HDCP_MODE_ESS_CONFIG);
|
|
+}
|
|
+
|
|
+static u8 meson_txc_hdmi_bus_fmt_to_color_depth(unsigned int bus_format)
|
|
+{
|
|
+ switch (bus_format) {
|
|
+ case MEDIA_BUS_FMT_RGB888_1X24:
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ case MEDIA_BUS_FMT_UYVY8_1X16:
|
|
+ /* 8 bit */
|
|
+ return 0x0;
|
|
+
|
|
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ case MEDIA_BUS_FMT_UYVY10_1X20:
|
|
+ /* 10 bit */
|
|
+ return 0x1;
|
|
+
|
|
+ case MEDIA_BUS_FMT_RGB121212_1X36:
|
|
+ case MEDIA_BUS_FMT_YUV12_1X36:
|
|
+ case MEDIA_BUS_FMT_UYVY12_1X24:
|
|
+ /* 12 bit */
|
|
+ return 0x2;
|
|
+
|
|
+ case MEDIA_BUS_FMT_RGB161616_1X48:
|
|
+ case MEDIA_BUS_FMT_YUV16_1X48:
|
|
+ /* 16 bit */
|
|
+ return 0x3;
|
|
+
|
|
+ default:
|
|
+ /* unknown, default to 8 bit */
|
|
+ return 0x0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static u8 meson_txc_hdmi_bus_fmt_to_color_format(unsigned int bus_format)
|
|
+{
|
|
+ switch (bus_format) {
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ case MEDIA_BUS_FMT_YUV12_1X36:
|
|
+ case MEDIA_BUS_FMT_YUV16_1X48:
|
|
+ /* Documented as YCbCr444 */
|
|
+ return 0x1;
|
|
+
|
|
+ case MEDIA_BUS_FMT_UYVY8_1X16:
|
|
+ case MEDIA_BUS_FMT_UYVY10_1X20:
|
|
+ case MEDIA_BUS_FMT_UYVY12_1X24:
|
|
+ /* Documented as YCbCr422 */
|
|
+ return 0x3;
|
|
+
|
|
+ case MEDIA_BUS_FMT_RGB888_1X24:
|
|
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
+ case MEDIA_BUS_FMT_RGB121212_1X36:
|
|
+ case MEDIA_BUS_FMT_RGB161616_1X48:
|
|
+ default:
|
|
+ /* Documented as RGB444 */
|
|
+ return 0x0;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_config_color_space(struct meson_txc_hdmi *priv,
|
|
+ unsigned int input_bus_format,
|
|
+ unsigned int output_bus_format,
|
|
+ enum hdmi_quantization_range quant_range,
|
|
+ enum hdmi_colorimetry colorimetry)
|
|
+{
|
|
+ unsigned int regval;
|
|
+
|
|
+ regmap_write(priv->regmap, TX_VIDEO_DTV_MODE,
|
|
+ FIELD_PREP(TX_VIDEO_DTV_MODE_COLOR_DEPTH,
|
|
+ meson_txc_hdmi_bus_fmt_to_color_depth(output_bus_format)));
|
|
+
|
|
+ regmap_write(priv->regmap, TX_VIDEO_DTV_OPTION_L,
|
|
+ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_FORMAT,
|
|
+ meson_txc_hdmi_bus_fmt_to_color_format(output_bus_format)) |
|
|
+ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_FORMAT,
|
|
+ meson_txc_hdmi_bus_fmt_to_color_format(input_bus_format)) |
|
|
+ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_DEPTH,
|
|
+ meson_txc_hdmi_bus_fmt_to_color_depth(output_bus_format)) |
|
|
+ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_DEPTH,
|
|
+ meson_txc_hdmi_bus_fmt_to_color_depth(input_bus_format)));
|
|
+
|
|
+ if (quant_range == HDMI_QUANTIZATION_RANGE_LIMITED)
|
|
+ regval = FIELD_PREP(TX_VIDEO_DTV_OPTION_H_OUTPUT_COLOR_RANGE,
|
|
+ TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_16_235) |
|
|
+ FIELD_PREP(TX_VIDEO_DTV_OPTION_H_INPUT_COLOR_RANGE,
|
|
+ TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_16_235);
|
|
+ else
|
|
+ regval = FIELD_PREP(TX_VIDEO_DTV_OPTION_H_OUTPUT_COLOR_RANGE,
|
|
+ TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_0_255) |
|
|
+ FIELD_PREP(TX_VIDEO_DTV_OPTION_H_INPUT_COLOR_RANGE,
|
|
+ TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_0_255);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_VIDEO_DTV_OPTION_H, regval);
|
|
+
|
|
+ if (colorimetry == HDMI_COLORIMETRY_ITU_601) {
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B0, 0x2f);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B1, 0x1d);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R0, 0x8b);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R1, 0x4c);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB0, 0x18);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB1, 0x58);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR0, 0xd0);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR1, 0xb6);
|
|
+ } else {
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B0, 0x7b);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B1, 0x12);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R0, 0x6c);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R1, 0x36);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB0, 0xf2);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB1, 0x2f);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR0, 0xd4);
|
|
+ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR1, 0x77);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_config_serializer_clock(struct meson_txc_hdmi *priv,
|
|
+ enum hdmi_colorimetry colorimetry)
|
|
+{
|
|
+ /* Serializer Internal clock setting */
|
|
+ if (colorimetry == HDMI_COLORIMETRY_ITU_601)
|
|
+ regmap_write(priv->regmap, TX_SYS1_PLL, 0x24);
|
|
+ else
|
|
+ regmap_write(priv->regmap, TX_SYS1_PLL, 0x22);
|
|
+
|
|
+#if 0
|
|
+ // TODO: not ported yet
|
|
+ if ((param->VIC==HDMI_1080p60)&&(param->color_depth==COLOR_30BIT)&&(hdmi_rd_reg(0x018)==0x22)) {
|
|
+ regmap_write(priv->regmap, TX_SYS1_PLL, 0x12);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_reconfig_packet_setting(struct meson_txc_hdmi *priv,
|
|
+ u8 cea_mode)
|
|
+{
|
|
+ u8 alloc_active2, alloc_eof1, alloc_sof1, alloc_sof2;
|
|
+
|
|
+ regmap_write(priv->regmap, TX_PACKET_CONTROL_1,
|
|
+ FIELD_PREP(TX_PACKET_CONTROL_1_PACKET_START_LATENCY, 58));
|
|
+ regmap_write(priv->regmap, TX_PACKET_CONTROL_2,
|
|
+ TX_PACKET_CONTROL_2_HORIZONTAL_GC_PACKET_TRANSPORT_EN);
|
|
+
|
|
+ switch (cea_mode) {
|
|
+ case 31:
|
|
+ /* 1920x1080p50 */
|
|
+ alloc_active2 = 0x12;
|
|
+ alloc_eof1 = 0x10;
|
|
+ alloc_sof1 = 0xb6;
|
|
+ alloc_sof2 = 0x11;
|
|
+ break;
|
|
+ case 93:
|
|
+ /* 3840x2160p24 */
|
|
+ alloc_active2 = 0x12;
|
|
+ alloc_eof1 = 0x47;
|
|
+ alloc_sof1 = 0xf8;
|
|
+ alloc_sof2 = 0x52;
|
|
+ break;
|
|
+ case 94:
|
|
+ /* 3840x2160p25 */
|
|
+ alloc_active2 = 0x12;
|
|
+ alloc_eof1 = 0x44;
|
|
+ alloc_sof1 = 0xda;
|
|
+ alloc_sof2 = 0x52;
|
|
+ break;
|
|
+ case 95:
|
|
+ /* 3840x2160p30 */
|
|
+ alloc_active2 = 0x0f;
|
|
+ alloc_eof1 = 0x3a;
|
|
+ alloc_sof1 = 0x60;
|
|
+ alloc_sof2 = 0x52;
|
|
+ break;
|
|
+ case 98:
|
|
+ /* 4096x2160p24 */
|
|
+ alloc_active2 = 0x12;
|
|
+ alloc_eof1 = 0x47;
|
|
+ alloc_sof1 = 0xf8;
|
|
+ alloc_sof2 = 0x52;
|
|
+ break;
|
|
+ default:
|
|
+ /* Disable the special packet settings only */
|
|
+ regmap_write(priv->regmap, TX_PACKET_ALLOC_ACTIVE_1, 0x00);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * The vendor driver says: manually configure these register to get
|
|
+ * stable video timings.
|
|
+ */
|
|
+ regmap_write(priv->regmap, TX_PACKET_ALLOC_ACTIVE_1, 0x01);
|
|
+ regmap_write(priv->regmap, TX_PACKET_ALLOC_ACTIVE_2, alloc_active2);
|
|
+ regmap_write(priv->regmap, TX_PACKET_ALLOC_EOF_1, alloc_eof1);
|
|
+ regmap_write(priv->regmap, TX_PACKET_ALLOC_EOF_2, 0x12);
|
|
+ regmap_write(priv->regmap, TX_CORE_ALLOC_VSYNC_0, 0x01);
|
|
+ regmap_write(priv->regmap, TX_CORE_ALLOC_VSYNC_1, 0x00);
|
|
+ regmap_write(priv->regmap, TX_CORE_ALLOC_VSYNC_2, 0x0a);
|
|
+ regmap_write(priv->regmap, TX_PACKET_ALLOC_SOF_1, alloc_sof1);
|
|
+ regmap_write(priv->regmap, TX_PACKET_ALLOC_SOF_2, alloc_sof2);
|
|
+ regmap_update_bits(priv->regmap, TX_PACKET_CONTROL_1,
|
|
+ TX_PACKET_CONTROL_1_FORCE_PACKET_TIMING,
|
|
+ TX_PACKET_CONTROL_1_FORCE_PACKET_TIMING);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_set_avi_infoframe(struct meson_txc_hdmi *priv,
|
|
+ struct drm_connector *conn,
|
|
+ const struct drm_display_mode *mode,
|
|
+ const struct drm_connector_state *conn_state,
|
|
+ unsigned int output_bus_format,
|
|
+ enum hdmi_quantization_range quant_range,
|
|
+ enum hdmi_colorimetry colorimetry)
|
|
+{
|
|
+ u8 buf[HDMI_INFOFRAME_SIZE(AVI)], *video_code;
|
|
+ struct hdmi_avi_infoframe frame;
|
|
+ int ret;
|
|
+
|
|
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, conn, mode);
|
|
+ if (ret < 0) {
|
|
+ drm_err(priv->bridge.dev,
|
|
+ "Failed to setup AVI infoframe: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ switch (output_bus_format) {
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ case MEDIA_BUS_FMT_YUV12_1X36:
|
|
+ case MEDIA_BUS_FMT_YUV16_1X48:
|
|
+ frame.colorspace = HDMI_COLORSPACE_YUV444;
|
|
+ break;
|
|
+
|
|
+ case MEDIA_BUS_FMT_UYVY8_1X16:
|
|
+ case MEDIA_BUS_FMT_UYVY10_1X20:
|
|
+ case MEDIA_BUS_FMT_UYVY12_1X24:
|
|
+ frame.colorspace = HDMI_COLORSPACE_YUV422;
|
|
+ break;
|
|
+
|
|
+ case MEDIA_BUS_FMT_RGB888_1X24:
|
|
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
+ case MEDIA_BUS_FMT_RGB121212_1X36:
|
|
+ case MEDIA_BUS_FMT_RGB161616_1X48:
|
|
+ default:
|
|
+ frame.colorspace = HDMI_COLORSPACE_RGB;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ drm_hdmi_avi_infoframe_colorimetry(&frame, conn_state);
|
|
+ drm_hdmi_avi_infoframe_quant_range(&frame, conn, mode, quant_range);
|
|
+ drm_hdmi_avi_infoframe_bars(&frame, conn_state);
|
|
+
|
|
+ ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf));
|
|
+ if (ret < 0) {
|
|
+ drm_err(priv->bridge.dev,
|
|
+ "Failed to pack AVI infoframe: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ video_code = &buf[HDMI_INFOFRAME_HEADER_SIZE + 3];
|
|
+ if (*video_code > 108) {
|
|
+ regmap_write(priv->regmap, TX_PKT_REG_EXCEPT0_BASE_ADDR,
|
|
+ *video_code);
|
|
+ *video_code = 0x00;
|
|
+ } else {
|
|
+ regmap_write(priv->regmap, TX_PKT_REG_EXCEPT0_BASE_ADDR,
|
|
+ 0x00);
|
|
+ }
|
|
+
|
|
+ meson_txc_hdmi_write_infoframe(priv->regmap,
|
|
+ TX_PKT_REG_AVI_INFO_BASE_ADDR, buf,
|
|
+ sizeof(buf), true);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_set_vendor_infoframe(struct meson_txc_hdmi *priv,
|
|
+ struct drm_connector *conn,
|
|
+ const struct drm_display_mode *mode)
|
|
+{
|
|
+ u8 buf[HDMI_INFOFRAME_HEADER_SIZE + 6];
|
|
+ struct hdmi_vendor_infoframe frame;
|
|
+ int ret;
|
|
+
|
|
+ ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, conn, mode);
|
|
+ if (ret) {
|
|
+ drm_dbg(priv->bridge.dev,
|
|
+ "Failed to setup vendor infoframe: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = hdmi_vendor_infoframe_pack(&frame, buf, sizeof(buf));
|
|
+ if (ret < 0) {
|
|
+ drm_err(priv->bridge.dev,
|
|
+ "Failed to pack vendor infoframe: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ meson_txc_hdmi_write_infoframe(priv->regmap,
|
|
+ TX_PKT_REG_VEND_INFO_BASE_ADDR, buf,
|
|
+ sizeof(buf), true);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_set_spd_infoframe(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ u8 buf[HDMI_INFOFRAME_SIZE(SPD)];
|
|
+ struct hdmi_spd_infoframe frame;
|
|
+ int ret;
|
|
+
|
|
+ ret = hdmi_spd_infoframe_init(&frame, "Amlogic", "Meson TXC HDMI");
|
|
+ if (ret < 0) {
|
|
+ drm_err(priv->bridge.dev,
|
|
+ "Failed to setup SPD infoframe: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = hdmi_spd_infoframe_pack(&frame, buf, sizeof(buf));
|
|
+ if (ret < 0) {
|
|
+ drm_err(priv->bridge.dev,
|
|
+ "Failed to pack SDP infoframe: %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ meson_txc_hdmi_write_infoframe(priv->regmap,
|
|
+ TX_PKT_REG_SPD_INFO_BASE_ADDR, buf,
|
|
+ sizeof(buf), true);
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_handle_plugged_change(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ bool plugged;
|
|
+
|
|
+ plugged = priv->last_connector_status == connector_status_connected;
|
|
+
|
|
+ if (priv->codec_dev && priv->codec_plugged_cb)
|
|
+ priv->codec_plugged_cb(priv->codec_dev, plugged);
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_bridge_attach(struct drm_bridge *bridge,
|
|
+ enum drm_bridge_attach_flags flags)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = bridge->driver_private;
|
|
+
|
|
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
|
|
+ drm_err(bridge->dev,
|
|
+ "DRM_BRIDGE_ATTACH_NO_CONNECTOR flag is not set but needed\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge,
|
|
+ flags);
|
|
+}
|
|
+
|
|
+/* Can return a maximum of 11 possible output formats for a mode/connector */
|
|
+#define MAX_OUTPUT_SEL_FORMATS 11
|
|
+
|
|
+static u32 *
|
|
+meson_txc_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
|
+ struct drm_bridge_state *bridge_state,
|
|
+ struct drm_crtc_state *crtc_state,
|
|
+ struct drm_connector_state *conn_state,
|
|
+ unsigned int *num_output_fmts)
|
|
+{
|
|
+ struct drm_connector *conn = conn_state->connector;
|
|
+ struct drm_display_info *info = &conn->display_info;
|
|
+ u8 max_bpc = conn_state->max_requested_bpc;
|
|
+ unsigned int i = 0;
|
|
+ u32 *output_fmts;
|
|
+
|
|
+ *num_output_fmts = 0;
|
|
+
|
|
+ output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
|
|
+ GFP_KERNEL);
|
|
+ if (!output_fmts)
|
|
+ return NULL;
|
|
+
|
|
+ /* If we are the only bridge, avoid negotiating with ourselves */
|
|
+ if (list_is_singular(&bridge->encoder->bridge_chain)) {
|
|
+ *num_output_fmts = 1;
|
|
+ output_fmts[0] = MEDIA_BUS_FMT_FIXED;
|
|
+
|
|
+ return output_fmts;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Order bus formats from 16bit to 8bit and from YUV422 to RGB
|
|
+ * if supported. In any case the default RGB888 format is added
|
|
+ */
|
|
+
|
|
+ if (max_bpc >= 16 && info->bpc == 16) {
|
|
+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
|
+
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
|
+ }
|
|
+
|
|
+ if (max_bpc >= 12 && info->bpc >= 12) {
|
|
+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
|
+
|
|
+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
|
+
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
|
+ }
|
|
+
|
|
+ if (max_bpc >= 10 && info->bpc >= 10) {
|
|
+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
|
+
|
|
+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
|
+
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
|
+ }
|
|
+
|
|
+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
|
+
|
|
+ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
|
+
|
|
+ /* Default 8bit RGB fallback */
|
|
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
+
|
|
+ *num_output_fmts = i;
|
|
+
|
|
+ return output_fmts;
|
|
+}
|
|
+
|
|
+/* Can return a maximum of 3 possible input formats for an output format */
|
|
+#define MAX_INPUT_SEL_FORMATS 3
|
|
+
|
|
+static u32 *
|
|
+meson_txc_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
|
+ struct drm_bridge_state *bridge_state,
|
|
+ struct drm_crtc_state *crtc_state,
|
|
+ struct drm_connector_state *conn_state,
|
|
+ u32 output_fmt,
|
|
+ unsigned int *num_input_fmts)
|
|
+{
|
|
+ u32 *input_fmts;
|
|
+ unsigned int i = 0;
|
|
+
|
|
+ *num_input_fmts = 0;
|
|
+
|
|
+ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
|
|
+ GFP_KERNEL);
|
|
+ if (!input_fmts)
|
|
+ return NULL;
|
|
+
|
|
+ switch (output_fmt) {
|
|
+ /* If MEDIA_BUS_FMT_FIXED is tested, return default bus format */
|
|
+ case MEDIA_BUS_FMT_FIXED:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
+ break;
|
|
+
|
|
+ /* 8bit */
|
|
+ case MEDIA_BUS_FMT_RGB888_1X24:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_UYVY8_1X16:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
|
+ break;
|
|
+
|
|
+ /* 10bit */
|
|
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_UYVY10_1X20:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
|
+ break;
|
|
+
|
|
+ /* 12bit */
|
|
+ case MEDIA_BUS_FMT_RGB121212_1X36:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_YUV12_1X36:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_UYVY12_1X24:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
|
+ break;
|
|
+
|
|
+ /* 16bit */
|
|
+ case MEDIA_BUS_FMT_RGB161616_1X48:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
|
+ break;
|
|
+ case MEDIA_BUS_FMT_YUV16_1X48:
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
|
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ *num_input_fmts = i;
|
|
+
|
|
+ if (*num_input_fmts == 0) {
|
|
+ kfree(input_fmts);
|
|
+ input_fmts = NULL;
|
|
+ }
|
|
+
|
|
+ return input_fmts;
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_bridge_atomic_enable(struct drm_bridge *bridge,
|
|
+ struct drm_bridge_state *old_bridge_state)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge);
|
|
+ struct drm_atomic_state *state = old_bridge_state->base.state;
|
|
+ enum hdmi_quantization_range quant_range;
|
|
+ struct drm_connector_state *conn_state;
|
|
+ struct drm_bridge_state *bridge_state;
|
|
+ const struct drm_display_mode *mode;
|
|
+ enum hdmi_colorimetry colorimetry;
|
|
+ struct drm_crtc_state *crtc_state;
|
|
+ struct drm_connector *connector;
|
|
+ unsigned int i;
|
|
+ u8 cea_mode;
|
|
+
|
|
+ bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
|
|
+
|
|
+ connector = drm_atomic_get_new_connector_for_encoder(state,
|
|
+ bridge->encoder);
|
|
+ if (WARN_ON(!connector))
|
|
+ return;
|
|
+
|
|
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
|
|
+ if (WARN_ON(!conn_state))
|
|
+ return;
|
|
+
|
|
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
|
|
+ if (WARN_ON(!crtc_state))
|
|
+ return;
|
|
+
|
|
+ priv->current_connector = connector;
|
|
+
|
|
+ mode = &crtc_state->adjusted_mode;
|
|
+
|
|
+ cea_mode = drm_match_cea_mode(mode);
|
|
+
|
|
+ if (connector->display_info.is_hdmi) {
|
|
+ quant_range = drm_default_rgb_quant_range(mode);
|
|
+
|
|
+ switch (cea_mode) {
|
|
+ case 2 ... 3:
|
|
+ case 6 ... 7:
|
|
+ case 17 ... 18:
|
|
+ case 21 ... 22:
|
|
+ colorimetry = HDMI_COLORIMETRY_ITU_601;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ colorimetry = HDMI_COLORIMETRY_ITU_709;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ meson_txc_hdmi_set_avi_infoframe(priv, connector, mode,
|
|
+ conn_state,
|
|
+ bridge_state->output_bus_cfg.format,
|
|
+ quant_range, colorimetry);
|
|
+ meson_txc_hdmi_set_vendor_infoframe(priv, connector, mode);
|
|
+ meson_txc_hdmi_set_spd_infoframe(priv);
|
|
+ } else {
|
|
+ quant_range = HDMI_QUANTIZATION_RANGE_FULL;
|
|
+ colorimetry = HDMI_COLORIMETRY_NONE;
|
|
+ }
|
|
+
|
|
+ meson_txc_hdmi_sys5_reset_assert(priv);
|
|
+
|
|
+ meson_txc_hdmi_config_hdcp_registers(priv);
|
|
+
|
|
+ if (cea_mode == 39)
|
|
+ regmap_write(priv->regmap, TX_VIDEO_DTV_TIMING, 0x0);
|
|
+ else
|
|
+ regmap_write(priv->regmap, TX_VIDEO_DTV_TIMING,
|
|
+ TX_VIDEO_DTV_TIMING_DISABLE_VIC39_CORRECTION);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_CORE_DATA_CAPTURE_2,
|
|
+ TX_CORE_DATA_CAPTURE_2_INTERNAL_PACKET_ENABLE);
|
|
+ regmap_write(priv->regmap, TX_CORE_DATA_MONITOR_1,
|
|
+ TX_CORE_DATA_MONITOR_1_LANE0 |
|
|
+ FIELD_PREP(TX_CORE_DATA_MONITOR_1_SELECT_LANE0, 0x7));
|
|
+ regmap_write(priv->regmap, TX_CORE_DATA_MONITOR_2,
|
|
+ FIELD_PREP(TX_CORE_DATA_MONITOR_2_MONITOR_SELECT, 0x2));
|
|
+
|
|
+ if (connector->display_info.is_hdmi)
|
|
+ regmap_write(priv->regmap, TX_TMDS_MODE,
|
|
+ TX_TMDS_MODE_FORCED_HDMI |
|
|
+ TX_TMDS_MODE_HDMI_CONFIG);
|
|
+ else
|
|
+ regmap_write(priv->regmap, TX_TMDS_MODE,
|
|
+ TX_TMDS_MODE_FORCED_HDMI);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS4_CONNECT_SEL_1, 0x0);
|
|
+
|
|
+ /*
|
|
+ * Set tmds_clk pattern to be "0000011111" before being sent to AFE
|
|
+ * clock channel.
|
|
+ */
|
|
+ regmap_write(priv->regmap, TX_SYS4_CK_INV_VIDEO,
|
|
+ TX_SYS4_CK_INV_VIDEO_TMDS_CLK_PATTERN);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS5_FIFO_CONFIG,
|
|
+ TX_SYS5_FIFO_CONFIG_CLK_CHANNEL3_OUTPUT_ENABLE |
|
|
+ TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL2_ENABLE |
|
|
+ TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL1_ENABLE |
|
|
+ TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL0_ENABLE);
|
|
+
|
|
+ meson_txc_hdmi_config_color_space(priv,
|
|
+ bridge_state->input_bus_cfg.format,
|
|
+ bridge_state->output_bus_cfg.format,
|
|
+ quant_range, colorimetry);
|
|
+
|
|
+ meson_txc_hdmi_sys5_reset_deassert(priv);
|
|
+
|
|
+ meson_txc_hdmi_config_serializer_clock(priv, colorimetry);
|
|
+ meson_txc_hdmi_reconfig_packet_setting(priv, cea_mode);
|
|
+
|
|
+ /* all resets need to be applied twice */
|
|
+ for (i = 0; i < 2; i++) {
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1,
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_PIXEL_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_I2S_RESET_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH2 |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH1 |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH0);
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2,
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH3_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH0_RST_IN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_HDMI_SR_RST |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_TX_DDC_HDCP_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_TX_DDC_EDID_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_2_TX_DIG_RESET_N_CH3);
|
|
+ usleep_range(5000, 10000);
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, 0x00);
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2, 0x00);
|
|
+ usleep_range(5000, 10000);
|
|
+ }
|
|
+
|
|
+ if (!priv->phy_is_on) {
|
|
+ int ret;
|
|
+
|
|
+ ret = phy_power_on(priv->phy);
|
|
+ if (ret)
|
|
+ drm_err(bridge->dev, "Failed to turn on PHY\n");
|
|
+ else
|
|
+ priv->phy_is_on = true;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_bridge_atomic_disable(struct drm_bridge *bridge,
|
|
+ struct drm_bridge_state *old_bridge_state)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge);
|
|
+
|
|
+ priv->current_connector = NULL;
|
|
+
|
|
+ if (priv->phy_is_on) {
|
|
+ int ret;
|
|
+
|
|
+ ret = phy_power_off(priv->phy);
|
|
+ if (ret)
|
|
+ drm_err(bridge->dev, "Failed to turn off PHY\n");
|
|
+ else
|
|
+ priv->phy_is_on = false;
|
|
+ }
|
|
+
|
|
+ meson_txc_hdmi_disable_infoframe(priv, TX_PKT_REG_AUDIO_INFO_BASE_ADDR);
|
|
+ meson_txc_hdmi_disable_infoframe(priv, TX_PKT_REG_AVI_INFO_BASE_ADDR);
|
|
+ meson_txc_hdmi_disable_infoframe(priv, TX_PKT_REG_EXCEPT0_BASE_ADDR);
|
|
+ meson_txc_hdmi_disable_infoframe(priv, TX_PKT_REG_VEND_INFO_BASE_ADDR);
|
|
+}
|
|
+
|
|
+static enum drm_mode_status
|
|
+meson_txc_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
|
|
+ const struct drm_display_info *info,
|
|
+ const struct drm_display_mode *mode)
|
|
+{
|
|
+ return MODE_OK;
|
|
+}
|
|
+
|
|
+static enum drm_connector_status meson_txc_hdmi_bridge_detect(struct drm_bridge *bridge)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge);
|
|
+ enum drm_connector_status status;
|
|
+ unsigned int val;
|
|
+
|
|
+ regmap_read(priv->regmap, TX_HDCP_ST_EDID_STATUS, &val);
|
|
+ if (val & TX_HDCP_ST_EDID_STATUS_HPD_STATUS)
|
|
+ status = connector_status_connected;
|
|
+ else
|
|
+ status = connector_status_disconnected;
|
|
+
|
|
+ mutex_lock(&priv->codec_mutex);
|
|
+ if (priv->last_connector_status != status) {
|
|
+ priv->last_connector_status = status;
|
|
+ meson_txc_hdmi_handle_plugged_change(priv);
|
|
+ }
|
|
+ mutex_unlock(&priv->codec_mutex);
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_get_edid_block(void *data, u8 *buf, unsigned int block,
|
|
+ size_t len)
|
|
+{
|
|
+ unsigned int i, regval, start = block * EDID_LENGTH;
|
|
+ struct meson_txc_hdmi *priv = data;
|
|
+ int ret;
|
|
+
|
|
+ /* Start the DDC transaction */
|
|
+ regmap_update_bits(priv->regmap, TX_HDCP_EDID_CONFIG,
|
|
+ TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG, 0);
|
|
+ regmap_update_bits(priv->regmap, TX_HDCP_EDID_CONFIG,
|
|
+ TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG,
|
|
+ TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG);
|
|
+
|
|
+ ret = regmap_read_poll_timeout(priv->regmap,
|
|
+ TX_HDCP_ST_EDID_STATUS,
|
|
+ regval,
|
|
+ (regval & TX_HDCP_ST_EDID_STATUS_EDID_DATA_READY),
|
|
+ 1000, 200000);
|
|
+
|
|
+ regmap_update_bits(priv->regmap, TX_HDCP_EDID_CONFIG,
|
|
+ TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG, 0);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ for (i = 0; i < len; i++) {
|
|
+ regmap_read(priv->regmap, TX_RX_EDID_OFFSET + start + i,
|
|
+ ®val);
|
|
+ buf[i] = regval;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct drm_edid *meson_txc_hdmi_bridge_edid_read(struct drm_bridge *bridge,
|
|
+ struct drm_connector *connector)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge);
|
|
+ const struct drm_edid *drm_edid;
|
|
+
|
|
+ drm_edid = drm_edid_read_custom(connector,
|
|
+ meson_txc_hdmi_get_edid_block, priv);
|
|
+ if (!drm_edid) {
|
|
+ drm_dbg(priv->bridge.dev, "Failed to get EDID\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return drm_edid;
|
|
+}
|
|
+
|
|
+static const struct drm_bridge_funcs meson_txc_hdmi_bridge_funcs = {
|
|
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
|
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
|
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
|
+ .attach = meson_txc_hdmi_bridge_attach,
|
|
+ .atomic_get_output_bus_fmts = meson_txc_hdmi_bridge_atomic_get_output_bus_fmts,
|
|
+ .atomic_get_input_bus_fmts = meson_txc_hdmi_bridge_atomic_get_input_bus_fmts,
|
|
+ .atomic_enable = meson_txc_hdmi_bridge_atomic_enable,
|
|
+ .atomic_disable = meson_txc_hdmi_bridge_atomic_disable,
|
|
+ .mode_valid = meson_txc_hdmi_bridge_mode_valid,
|
|
+ .detect = meson_txc_hdmi_bridge_detect,
|
|
+ .edid_read = meson_txc_hdmi_bridge_edid_read,
|
|
+};
|
|
+
|
|
+static int meson_txc_hdmi_hw_init(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ unsigned long ddc_i2c_bus_clk_hz = 500 * 1000;
|
|
+ unsigned long sys_clk_hz = 24 * 1000 * 1000;
|
|
+ int ret;
|
|
+
|
|
+ ret = phy_init(priv->phy);
|
|
+ if (ret) {
|
|
+ dev_err(priv->dev, "Failed to initialize the PHY: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = clk_set_rate(priv->sys_clk, sys_clk_hz);
|
|
+ if (ret) {
|
|
+ dev_err(priv->dev, "Failed to set HDMI system clock to 24MHz\n");
|
|
+ goto err_phy_exit;
|
|
+ }
|
|
+
|
|
+ ret = clk_prepare_enable(priv->sys_clk);
|
|
+ if (ret) {
|
|
+ dev_err(priv->dev, "Failed to enable the sys clk\n");
|
|
+ goto err_phy_exit;
|
|
+ }
|
|
+
|
|
+ regmap_update_bits(priv->regmap, HDMI_OTHER_CTRL1,
|
|
+ HDMI_OTHER_CTRL1_POWER_ON,
|
|
+ HDMI_OTHER_CTRL1_POWER_ON);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_HDMI_PHY_CONFIG0,
|
|
+ TX_HDMI_PHY_CONFIG0_HDMI_COMMON_B7_B0);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_HDCP_MODE, 0x40);
|
|
+
|
|
+ /*
|
|
+ * The vendor driver comments that this is a setting for "Band-gap and
|
|
+ * main-bias". 0x1d = power-up, 0x00 = power-down.
|
|
+ */
|
|
+ regmap_write(priv->regmap, TX_SYS1_AFE_TEST, 0x1d);
|
|
+
|
|
+ meson_txc_hdmi_config_serializer_clock(priv, HDMI_COLORIMETRY_NONE);
|
|
+
|
|
+ /*
|
|
+ * The vendor driver has a comment with the following information for
|
|
+ * the magic value:
|
|
+ * bit[2:0]=011: CK channel output TMDS CLOCK
|
|
+ * bit[2:0]=101, ck channel output PHYCLCK
|
|
+ */
|
|
+ regmap_write(priv->regmap, TX_SYS1_AFE_CONNECT, 0xfb);
|
|
+
|
|
+ /* Termination resistor calib value */
|
|
+ regmap_write(priv->regmap, TX_CORE_CALIB_VALUE, 0x0f);
|
|
+
|
|
+ /* HPD glitch filter */
|
|
+ regmap_write(priv->regmap, TX_HDCP_HPD_FILTER_L, 0xa0);
|
|
+ regmap_write(priv->regmap, TX_HDCP_HPD_FILTER_H, 0xa0);
|
|
+
|
|
+ /* Disable MEM power-down */
|
|
+ regmap_write(priv->regmap, TX_MEM_PD_REG0, 0x0);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_HDCP_CONFIG3,
|
|
+ FIELD_PREP(TX_HDCP_CONFIG3_DDC_I2C_BUS_CLOCK_TIME_DIVIDER,
|
|
+ (sys_clk_hz / ddc_i2c_bus_clk_hz) - 1));
|
|
+
|
|
+ /* Enable software controlled DDC transaction */
|
|
+ regmap_write(priv->regmap, TX_HDCP_EDID_CONFIG,
|
|
+ TX_HDCP_EDID_CONFIG_FORCED_MEM_COPY_DONE |
|
|
+ TX_HDCP_EDID_CONFIG_MEM_COPY_DONE_CONFIG);
|
|
+ regmap_write(priv->regmap, TX_CORE_EDID_CONFIG_MORE,
|
|
+ TX_CORE_EDID_CONFIG_MORE_SYS_TRIGGER_CONFIG_SEMI_MANU);
|
|
+
|
|
+ /* mask (= disable) all interrupts */
|
|
+ regmap_write(priv->regmap, HDMI_OTHER_INTR_MASKN, 0x0);
|
|
+
|
|
+ /* clear any pending interrupt */
|
|
+ regmap_write(priv->regmap, HDMI_OTHER_INTR_STAT_CLR,
|
|
+ HDMI_OTHER_INTR_STAT_CLR_EDID_RISING |
|
|
+ HDMI_OTHER_INTR_STAT_CLR_HPD_FALLING |
|
|
+ HDMI_OTHER_INTR_STAT_CLR_HPD_RISING);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_phy_exit:
|
|
+ phy_exit(priv->phy);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_hw_exit(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ /* mask (= disable) all interrupts */
|
|
+ regmap_write(priv->regmap, HDMI_OTHER_INTR_MASKN,
|
|
+ HDMI_OTHER_INTR_MASKN_TX_EDID_INT_RISE |
|
|
+ HDMI_OTHER_INTR_MASKN_TX_HPD_INT_FALL |
|
|
+ HDMI_OTHER_INTR_MASKN_TX_HPD_INT_RISE);
|
|
+
|
|
+ regmap_update_bits(priv->regmap, HDMI_OTHER_CTRL1,
|
|
+ HDMI_OTHER_CTRL1_POWER_ON, 0);
|
|
+
|
|
+ clk_disable_unprepare(priv->sys_clk);
|
|
+
|
|
+ ret = phy_exit(priv->phy);
|
|
+ if (ret)
|
|
+ dev_err(priv->dev, "Failed to exit the PHY: %d\n", ret);
|
|
+}
|
|
+
|
|
+static u32 meson_txc_hdmi_hdmi_codec_calc_audio_n(struct hdmi_codec_params *hparms)
|
|
+{
|
|
+ u32 audio_n;
|
|
+
|
|
+ if ((hparms->sample_rate % 44100) == 0)
|
|
+ audio_n = (128 * hparms->sample_rate) / 900;
|
|
+ else
|
|
+ audio_n = (128 * hparms->sample_rate) / 1000;
|
|
+
|
|
+ if (hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_EAC3 ||
|
|
+ hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_DTS_HD)
|
|
+ audio_n *= 4;
|
|
+
|
|
+ return audio_n;
|
|
+}
|
|
+
|
|
+static u8 meson_txc_hdmi_hdmi_codec_coding_type(struct hdmi_codec_params *hparms)
|
|
+{
|
|
+ switch (hparms->cea.coding_type) {
|
|
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
|
+ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_HBR_AUDIO_PACKET;
|
|
+ case HDMI_AUDIO_CODING_TYPE_DSD:
|
|
+ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_ONE_BIT_AUDIO;
|
|
+ case HDMI_AUDIO_CODING_TYPE_DST:
|
|
+ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_DST_AUDIO_PACKET;
|
|
+ default:
|
|
+ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_AUDIO_SAMPLE_PACKET;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_hdmi_codec_hw_params(struct device *dev, void *data,
|
|
+ struct hdmi_codec_daifmt *fmt,
|
|
+ struct hdmi_codec_params *hparms)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = dev_get_drvdata(dev);
|
|
+ u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)];
|
|
+ u16 audio_tx_format;
|
|
+ u32 audio_n;
|
|
+ int len, i;
|
|
+
|
|
+ if (hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_MLP) {
|
|
+ /*
|
|
+ * TODO: fixed CTS is not supported yet, it needs special
|
|
+ * TX_SYS1_ACR_N_* settings
|
|
+ */
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ switch (hparms->sample_width) {
|
|
+ case 16:
|
|
+ audio_tx_format = FIELD_PREP(TX_AUDIO_FORMAT_BIT_WIDTH_MASK,
|
|
+ TX_AUDIO_FORMAT_BIT_WIDTH_16);
|
|
+ break;
|
|
+
|
|
+ case 20:
|
|
+ audio_tx_format = FIELD_PREP(TX_AUDIO_FORMAT_BIT_WIDTH_MASK,
|
|
+ TX_AUDIO_FORMAT_BIT_WIDTH_20);
|
|
+ break;
|
|
+
|
|
+ case 24:
|
|
+ audio_tx_format = FIELD_PREP(TX_AUDIO_FORMAT_BIT_WIDTH_MASK,
|
|
+ TX_AUDIO_FORMAT_BIT_WIDTH_24);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ switch (fmt->fmt) {
|
|
+ case HDMI_I2S:
|
|
+ regmap_update_bits(priv->regmap, HDMI_OTHER_CTRL1,
|
|
+ HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON,
|
|
+ HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON);
|
|
+
|
|
+ audio_tx_format |= TX_AUDIO_FORMAT_SPDIF_OR_I2S |
|
|
+ TX_AUDIO_FORMAT_I2S_ONE_BIT_OR_I2S |
|
|
+ FIELD_PREP(TX_AUDIO_FORMAT_I2S_FORMAT, 0x2);
|
|
+
|
|
+ if (hparms->channels > 2)
|
|
+ audio_tx_format |= TX_AUDIO_FORMAT_I2S_2_OR_8_CH;
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_FORMAT, audio_tx_format);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_I2S, TX_AUDIO_I2S_ENABLE);
|
|
+ regmap_write(priv->regmap, TX_AUDIO_SPDIF, 0x0);
|
|
+ break;
|
|
+
|
|
+ case HDMI_SPDIF:
|
|
+ regmap_update_bits(priv->regmap, HDMI_OTHER_CTRL1,
|
|
+ HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON, 0x0);
|
|
+
|
|
+ if (hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_STREAM)
|
|
+ audio_tx_format |= TX_AUDIO_FORMAT_SPDIF_CHANNEL_STATUS_FROM_DATA_OR_REG;
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_FORMAT, audio_tx_format);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_I2S, 0x0);
|
|
+ regmap_write(priv->regmap, TX_AUDIO_SPDIF, TX_AUDIO_SPDIF_ENABLE);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (hparms->channels > 2)
|
|
+ regmap_write(priv->regmap, TX_AUDIO_HEADER,
|
|
+ TX_AUDIO_HEADER_AUDIO_SAMPLE_PACKET_HEADER_LAYOUT1);
|
|
+ else
|
|
+ regmap_write(priv->regmap, TX_AUDIO_HEADER, 0x0);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_SAMPLE,
|
|
+ FIELD_PREP(TX_AUDIO_SAMPLE_CHANNEL_VALID,
|
|
+ BIT(hparms->channels) - 1));
|
|
+
|
|
+ audio_n = meson_txc_hdmi_hdmi_codec_calc_audio_n(hparms);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS1_ACR_N_0,
|
|
+ FIELD_PREP(TX_SYS1_ACR_N_0_N_BYTE0,
|
|
+ (audio_n >> 0) & 0xff));
|
|
+ regmap_write(priv->regmap, TX_SYS1_ACR_N_1,
|
|
+ FIELD_PREP(TX_SYS1_ACR_N_1_N_BYTE1,
|
|
+ (audio_n >> 8) & 0xff));
|
|
+ regmap_update_bits(priv->regmap, TX_SYS1_ACR_N_2,
|
|
+ TX_SYS1_ACR_N_2_N_UPPER_NIBBLE,
|
|
+ FIELD_PREP(TX_SYS1_ACR_N_2_N_UPPER_NIBBLE,
|
|
+ (audio_n >> 16) & 0xf));
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS0_ACR_CTS_0, 0x0);
|
|
+ regmap_write(priv->regmap, TX_SYS0_ACR_CTS_1, 0x0);
|
|
+ regmap_write(priv->regmap, TX_SYS0_ACR_CTS_2,
|
|
+ TX_SYS0_ACR_CTS_2_FORCE_ARC_STABLE);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_CONTROL,
|
|
+ TX_AUDIO_CONTROL_AUTO_AUDIO_FIFO_CLEAR |
|
|
+ FIELD_PREP(TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_MASK,
|
|
+ meson_txc_hdmi_hdmi_codec_coding_type(hparms)) |
|
|
+ TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_FLAT);
|
|
+
|
|
+ len = hdmi_audio_infoframe_pack(&hparms->cea, buf, sizeof(buf));
|
|
+ if (len < 0)
|
|
+ return len;
|
|
+
|
|
+ meson_txc_hdmi_write_infoframe(priv->regmap,
|
|
+ TX_PKT_REG_AUDIO_INFO_BASE_ADDR,
|
|
+ buf, len, true);
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(hparms->iec.status); i++) {
|
|
+ unsigned char sub1, sub2;
|
|
+
|
|
+ sub1 = sub2 = hparms->iec.status[i];
|
|
+
|
|
+ if (i == 2) {
|
|
+ sub1 |= FIELD_PREP(IEC958_AES2_CON_CHANNEL, 1);
|
|
+ sub2 |= FIELD_PREP(IEC958_AES2_CON_CHANNEL, 2);
|
|
+ }
|
|
+
|
|
+ regmap_write(priv->regmap, TX_IEC60958_SUB1_OFFSET + i, sub1);
|
|
+ regmap_write(priv->regmap, TX_IEC60958_SUB2_OFFSET + i, sub2);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_hdmi_codec_audio_startup(struct device *dev,
|
|
+ void *data)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = dev_get_drvdata(dev);
|
|
+
|
|
+ regmap_update_bits(priv->regmap, TX_PACKET_CONTROL_2,
|
|
+ TX_PACKET_CONTROL_2_AUDIO_REQUEST_DISABLE, 0x0);
|
|
+
|
|
+ /* reset audio master and sample */
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1,
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN |
|
|
+ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN);
|
|
+ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, 0x0);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_CONTROL_MORE,
|
|
+ TX_AUDIO_CONTROL_MORE_ENABLE);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_FIFO,
|
|
+ FIELD_PREP(TX_AUDIO_FIFO_FIFO_DEPTH_MASK,
|
|
+ TX_AUDIO_FIFO_FIFO_DEPTH_512) |
|
|
+ FIELD_PREP(TX_AUDIO_FIFO_CRITICAL_THRESHOLD_MASK,
|
|
+ TX_AUDIO_FIFO_CRITICAL_THRESHOLD_DEPTH_DIV16) |
|
|
+ FIELD_PREP(TX_AUDIO_FIFO_NORMAL_THRESHOLD_MASK,
|
|
+ TX_AUDIO_FIFO_NORMAL_THRESHOLD_DEPTH_DIV8));
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_LIPSYNC, 0x0);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_SYS1_ACR_N_2,
|
|
+ FIELD_PREP(TX_SYS1_ACR_N_2_N_MEAS_TOLERANCE, 0x3));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_hdmi_codec_audio_shutdown(struct device *dev,
|
|
+ void *data)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = dev_get_drvdata(dev);
|
|
+
|
|
+ meson_txc_hdmi_disable_infoframe(priv, TX_PKT_REG_AUDIO_INFO_BASE_ADDR);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_CONTROL_MORE, 0x0);
|
|
+ regmap_update_bits(priv->regmap, HDMI_OTHER_CTRL1,
|
|
+ HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON, 0x0);
|
|
+
|
|
+ regmap_update_bits(priv->regmap, TX_PACKET_CONTROL_2,
|
|
+ TX_PACKET_CONTROL_2_AUDIO_REQUEST_DISABLE,
|
|
+ TX_PACKET_CONTROL_2_AUDIO_REQUEST_DISABLE);
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_hdmi_codec_mute_stream(struct device *dev,
|
|
+ void *data, bool enable,
|
|
+ int direction)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = dev_get_drvdata(dev);
|
|
+
|
|
+ regmap_write(priv->regmap, TX_AUDIO_PACK,
|
|
+ enable ? 0 : TX_AUDIO_PACK_AUDIO_SAMPLE_PACKETS_ENABLE);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_hdmi_codec_get_eld(struct device *dev, void *data,
|
|
+ uint8_t *buf, size_t len)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = dev_get_drvdata(dev);
|
|
+
|
|
+ if (priv->current_connector)
|
|
+ memcpy(buf, priv->current_connector->eld,
|
|
+ min_t(size_t, MAX_ELD_BYTES, len));
|
|
+ else
|
|
+ memset(buf, 0, len);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_hdmi_codec_get_dai_id(struct snd_soc_component *component,
|
|
+ struct device_node *endpoint)
|
|
+{
|
|
+ struct of_endpoint of_ep;
|
|
+ int ret;
|
|
+
|
|
+ ret = of_graph_parse_endpoint(endpoint, &of_ep);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ /*
|
|
+ * HDMI sound should be located as reg = <2>
|
|
+ * Then, it is sound port 0
|
|
+ */
|
|
+ if (of_ep.port == 2)
|
|
+ return 0;
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_hdmi_codec_hook_plugged_cb(struct device *dev,
|
|
+ void *data,
|
|
+ hdmi_codec_plugged_cb fn,
|
|
+ struct device *codec_dev)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = dev_get_drvdata(dev);
|
|
+
|
|
+ mutex_lock(&priv->codec_mutex);
|
|
+ priv->codec_plugged_cb = fn;
|
|
+ priv->codec_dev = codec_dev;
|
|
+ meson_txc_hdmi_handle_plugged_change(priv);
|
|
+ mutex_unlock(&priv->codec_mutex);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct hdmi_codec_ops meson_txc_hdmi_hdmi_codec_ops = {
|
|
+ .hw_params = meson_txc_hdmi_hdmi_codec_hw_params,
|
|
+ .audio_startup = meson_txc_hdmi_hdmi_codec_audio_startup,
|
|
+ .audio_shutdown = meson_txc_hdmi_hdmi_codec_audio_shutdown,
|
|
+ .mute_stream = meson_txc_hdmi_hdmi_codec_mute_stream,
|
|
+ .get_eld = meson_txc_hdmi_hdmi_codec_get_eld,
|
|
+ .get_dai_id = meson_txc_hdmi_hdmi_codec_get_dai_id,
|
|
+ .hook_plugged_cb = meson_txc_hdmi_hdmi_codec_hook_plugged_cb,
|
|
+};
|
|
+
|
|
+static const struct hdmi_codec_pdata meson_txc_hdmi_codec_pdata = {
|
|
+ .ops = &meson_txc_hdmi_hdmi_codec_ops,
|
|
+ .i2s = 1,
|
|
+ .spdif = 1,
|
|
+ .max_i2s_channels = 8,
|
|
+};
|
|
+
|
|
+static int meson_txc_hdmi_codec_init(struct meson_txc_hdmi *priv)
|
|
+{
|
|
+ priv->hdmi_codec_pdev = platform_device_register_data(priv->dev,
|
|
+ HDMI_CODEC_DRV_NAME,
|
|
+ PLATFORM_DEVID_AUTO,
|
|
+ &meson_txc_hdmi_codec_pdata,
|
|
+ sizeof(meson_txc_hdmi_codec_pdata));
|
|
+ return PTR_ERR_OR_ZERO(priv->hdmi_codec_pdev);
|
|
+}
|
|
+
|
|
+static int meson_txc_hdmi_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device_node *endpoint, *remote;
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct meson_txc_hdmi *priv;
|
|
+ void __iomem *base;
|
|
+ u32 regval;
|
|
+ int ret;
|
|
+
|
|
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ priv->dev = dev;
|
|
+
|
|
+ mutex_init(&priv->codec_mutex);
|
|
+
|
|
+ platform_set_drvdata(pdev, priv);
|
|
+
|
|
+ base = devm_platform_ioremap_resource(pdev, 0);
|
|
+ if (IS_ERR(base))
|
|
+ return PTR_ERR(base);
|
|
+
|
|
+ priv->regmap = devm_regmap_init(dev, NULL, base,
|
|
+ &meson_txc_hdmi_regmap_config);
|
|
+ if (IS_ERR(priv->regmap))
|
|
+ return PTR_ERR(priv->regmap);
|
|
+
|
|
+ priv->pclk = devm_clk_get(dev, "pclk");
|
|
+ if (IS_ERR(priv->pclk))
|
|
+ return dev_err_probe(dev, PTR_ERR(priv->pclk),
|
|
+ "Failed to get the pclk\n");
|
|
+
|
|
+ priv->sys_clk = devm_clk_get(dev, "sys");
|
|
+ if (IS_ERR(priv->sys_clk))
|
|
+ return dev_err_probe(dev, PTR_ERR(priv->sys_clk),
|
|
+ "Failed to get the sys clock\n");
|
|
+
|
|
+ priv->phy = devm_phy_get(dev, "hdmi");
|
|
+ if (IS_ERR(priv->phy))
|
|
+ return dev_err_probe(dev, PTR_ERR(priv->phy),
|
|
+ "Failed to get the HDMI PHY\n");
|
|
+
|
|
+ endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
|
|
+ if (!endpoint)
|
|
+ return dev_err_probe(dev, -ENODEV,
|
|
+ "Missing endpoint in port@1\n");
|
|
+
|
|
+ remote = of_graph_get_remote_port_parent(endpoint);
|
|
+ of_node_put(endpoint);
|
|
+ if (!remote)
|
|
+ return dev_err_probe(dev, -ENODEV,
|
|
+ "Endpoint in port@1 unconnected\n");
|
|
+
|
|
+ if (!of_device_is_available(remote)) {
|
|
+ of_node_put(remote);
|
|
+ return dev_err_probe(dev, -ENODEV,
|
|
+ "port@1 remote device is disabled\n");
|
|
+ }
|
|
+
|
|
+ priv->next_bridge = of_drm_find_bridge(remote);
|
|
+ of_node_put(remote);
|
|
+ if (!priv->next_bridge)
|
|
+ return -EPROBE_DEFER;
|
|
+
|
|
+ ret = clk_prepare_enable(priv->pclk);
|
|
+ if (ret)
|
|
+ return dev_err_probe(dev, ret, "Failed to enable the pclk\n");
|
|
+
|
|
+ regval = readl(base + HDMI_CTRL_PORT);
|
|
+ regval |= HDMI_CTRL_PORT_APB3_ERR_EN;
|
|
+ writel(regval, base + HDMI_CTRL_PORT);
|
|
+
|
|
+ ret = meson_txc_hdmi_hw_init(priv);
|
|
+ if (ret)
|
|
+ goto err_disable_clk;
|
|
+
|
|
+ ret = meson_txc_hdmi_codec_init(priv);
|
|
+ if (ret)
|
|
+ goto err_hw_exit;
|
|
+
|
|
+ priv->bridge.driver_private = priv;
|
|
+ priv->bridge.funcs = &meson_txc_hdmi_bridge_funcs;
|
|
+ priv->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
|
|
+ priv->bridge.of_node = dev->of_node;
|
|
+ priv->bridge.interlace_allowed = true;
|
|
+
|
|
+ drm_bridge_add(&priv->bridge);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_hw_exit:
|
|
+ meson_txc_hdmi_hw_exit(priv);
|
|
+err_disable_clk:
|
|
+ clk_disable_unprepare(priv->pclk);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void meson_txc_hdmi_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct meson_txc_hdmi *priv = platform_get_drvdata(pdev);
|
|
+
|
|
+ platform_device_unregister(priv->hdmi_codec_pdev);
|
|
+
|
|
+ drm_bridge_remove(&priv->bridge);
|
|
+
|
|
+ meson_txc_hdmi_hw_exit(priv);
|
|
+
|
|
+ clk_disable_unprepare(priv->pclk);
|
|
+}
|
|
+
|
|
+static const struct of_device_id meson_txc_hdmi_of_table[] = {
|
|
+ { .compatible = "amlogic,meson8-hdmi-tx" },
|
|
+ { .compatible = "amlogic,meson8b-hdmi-tx" },
|
|
+ { /* sentinel */ }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, meson_txc_hdmi_of_table);
|
|
+
|
|
+static struct platform_driver meson_txc_hdmi_platform_driver = {
|
|
+ .probe = meson_txc_hdmi_probe,
|
|
+ .remove_new = meson_txc_hdmi_remove,
|
|
+ .driver = {
|
|
+ .name = "meson-transwitch-hdmi",
|
|
+ .of_match_table = meson_txc_hdmi_of_table,
|
|
+ },
|
|
+};
|
|
+module_platform_driver(meson_txc_hdmi_platform_driver);
|
|
+
|
|
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
|
|
+MODULE_DESCRIPTION("Amlogic Meson8 and Meson8b TranSwitch HDMI 1.4 TX driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/gpu/drm/meson/meson_transwitch_hdmi.h b/drivers/gpu/drm/meson/meson_transwitch_hdmi.h
|
|
new file mode 100644
|
|
index 000000000000..111111111111
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/meson/meson_transwitch_hdmi.h
|
|
@@ -0,0 +1,536 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
|
+ *
|
|
+ * All registers and magic values are taken from Amlogic's GPL kernel sources:
|
|
+ * Copyright (C) 2010 Amlogic, Inc.
|
|
+ */
|
|
+
|
|
+#include <linux/bitfield.h>
|
|
+#include <linux/bits.h>
|
|
+
|
|
+#ifndef __MESON_TRANSWITCH_HDMI_H__
|
|
+#define __MESON_TRANSWITCH_HDMI_H__
|
|
+
|
|
+/* HDMI TX register */
|
|
+
|
|
+// System config 0
|
|
+#define TX_SYS0_AFE_SIGNAL 0x0000
|
|
+#define TX_SYS0_AFE_LOOP 0x0001
|
|
+#define TX_SYS0_ACR_CTS_0 0x0002
|
|
+ #define TX_SYS0_ACR_CTS_0_AUDIO_CTS_BYTE0 GENMASK(7, 0)
|
|
+#define TX_SYS0_ACR_CTS_1 0x0003
|
|
+ #define TX_SYS0_ACR_CTS_1_AUDIO_CTS_BYTE1 GENMASK(7, 0)
|
|
+#define TX_SYS0_ACR_CTS_2 0x0004
|
|
+ #define TX_SYS0_ACR_CTS_2_FORCE_ARC_STABLE BIT(5)
|
|
+#define TX_SYS0_BIST_CONTROL 0x0005
|
|
+ #define TX_SYS0_BIST_CONTROL_AFE_BIST_ENABLE BIT(7)
|
|
+ #define TX_SYS0_BIST_CONTROL_TMDS_SHIFT_PATTERN_SELECT BIT(6)
|
|
+ #define TX_SYS0_BIST_CONTROL_TMDS_PRBS_PATTERN_SELECT GENMASK(5, 4)
|
|
+ #define TX_SYS0_BIST_CONTROL_TMDS_REPEAT_BIST_PATTERN GENMASK(2, 0)
|
|
+
|
|
+#define TX_SYS0_BIST_DATA_0 0x0006
|
|
+#define TX_SYS0_BIST_DATA_1 0x0007
|
|
+#define TX_SYS0_BIST_DATA_2 0x0008
|
|
+#define TX_SYS0_BIST_DATA_3 0x0009
|
|
+#define TX_SYS0_BIST_DATA_4 0x000A
|
|
+#define TX_SYS0_BIST_DATA_5 0x000B
|
|
+#define TX_SYS0_BIST_DATA_6 0x000C
|
|
+#define TX_SYS0_BIST_DATA_7 0x000D
|
|
+#define TX_SYS0_BIST_DATA_8 0x000E
|
|
+#define TX_SYS0_BIST_DATA_9 0x000F
|
|
+
|
|
+// system config 1
|
|
+#define TX_HDMI_PHY_CONFIG0 0x0010
|
|
+ #define TX_HDMI_PHY_CONFIG0_HDMI_COMMON_B7_B0 GENMASK(7, 0)
|
|
+#define TX_HDMI_PHY_CONFIG1 0x0010
|
|
+ #define TX_HDMI_PHY_CONFIG1_HDMI_COMMON_B11_B8 GENMASK(3, 0)
|
|
+ #define TX_HDMI_PHY_CONFIG1_HDMI_CTL_REG_B3_B0 GENMASK(7, 4)
|
|
+#define TX_HDMI_PHY_CONFIG2 0x0012
|
|
+ #define TX_HDMI_PHY_CONFIG_HDMI_CTL_REG_B11_B4 GENMASK(7, 0)
|
|
+#define TX_HDMI_PHY_CONFIG3 0x0013
|
|
+ #define TX_HDMI_PHY_CONFIG3_HDMI_L2H_CTL GENMASK(3, 0)
|
|
+ #define TX_HDMI_PHY_CONFIG3_HDMI_MDR_PU GENMASK(7, 4)
|
|
+#define TX_HDMI_PHY_CONFIG4 0x0014
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_LF_PD BIT(0)
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_PHY_CLK_EN BIT(1)
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE GENMASK(3, 2)
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_NORMAL 0x0
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_CLK_CH3_EQUAL_CH0 0x1
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_ALTERNATE_HIGH_LOW 0x2
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_ALTERNATE_LOW_HIGH 0x3
|
|
+ #define TX_HDMI_PHY_CONFIG4_HDMI_PREM_CTL GENMASK(7, 4)
|
|
+#define TX_HDMI_PHY_CONFIG5 0x0015
|
|
+ #define TX_HDMI_PHY_CONFIG5_HDMI_VCM_CTL GENMASK(7, 5)
|
|
+ #define TX_HDMI_PHY_CONFIG5_HDMI_PREFCTL GENMASK(2, 0)
|
|
+#define TX_HDMI_PHY_CONFIG6 0x0016
|
|
+ #define TX_HDMI_PHY_CONFIG6_HDMI_RTERM_CTL GENMASK(3, 0)
|
|
+ #define TX_HDMI_PHY_CONFIG6_HDMI_SWING_CTL GENMASK(7, 4)
|
|
+#define TX_SYS1_AFE_TEST 0x0017
|
|
+#define TX_SYS1_PLL 0x0018
|
|
+#define TX_SYS1_TUNE 0x0019
|
|
+#define TX_SYS1_AFE_CONNECT 0x001A
|
|
+
|
|
+#define TX_SYS1_ACR_N_0 0x001C
|
|
+ #define TX_SYS1_ACR_N_0_N_BYTE0 GENMASK(7, 0)
|
|
+#define TX_SYS1_ACR_N_1 0x001D
|
|
+ #define TX_SYS1_ACR_N_1_N_BYTE1 GENMASK(7, 0)
|
|
+#define TX_SYS1_ACR_N_2 0x001E
|
|
+ #define TX_SYS1_ACR_N_2_N_MEAS_TOLERANCE GENMASK(7, 4)
|
|
+ #define TX_SYS1_ACR_N_2_N_UPPER_NIBBLE GENMASK(3, 0)
|
|
+#define TX_SYS1_PRBS_DATA 0x001F
|
|
+ #define TX_SYS1_PRBS_DATA_PRBS_MODE GENMASK(1, 0)
|
|
+ #define TX_SYS1_PRBS_DATA_PRBS_MODE_11 0x0
|
|
+ #define TX_SYS1_PRBS_DATA_PRBS_MODE_15 0x1
|
|
+ #define TX_SYS1_PRBS_DATA_PRBS_MODE_7 0x2
|
|
+ #define TX_SYS1_PRBS_DATA_PRBS_MODE_31 0x3
|
|
+
|
|
+// HDCP CONFIG
|
|
+#define TX_HDCP_ECC_CONFIG 0x0024
|
|
+#define TX_HDCP_CRC_CONFIG 0x0025
|
|
+#define TX_HDCP_EDID_CONFIG 0x0026
|
|
+ #define TX_HDCP_EDID_CONFIG_FORCED_SYS_TRIGGER BIT(7)
|
|
+ #define TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG BIT(6)
|
|
+ #define TX_HDCP_EDID_CONFIG_MEM_ACC_SEQ_MODE BIT(5)
|
|
+ #define TX_HDCP_EDID_CONFIG_MEM_ACC_SEQ_START BIT(4)
|
|
+ #define TX_HDCP_EDID_CONFIG_FORCED_MEM_COPY_DONE BIT(3)
|
|
+ #define TX_HDCP_EDID_CONFIG_MEM_COPY_DONE_CONFIG BIT(2)
|
|
+ #define TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG_SEMI_MANU BIT(1)
|
|
+
|
|
+#define TX_HDCP_MEM_CONFIG 0x0027
|
|
+ #define TX_HDCP_MEM_CONFIG_READ_DECRYPT BIT(3)
|
|
+
|
|
+#define TX_HDCP_HPD_FILTER_L 0x0028
|
|
+#define TX_HDCP_HPD_FILTER_H 0x0029
|
|
+#define TX_HDCP_ENCRYPT_BYTE 0x002A
|
|
+#define TX_HDCP_CONFIG0 0x002B
|
|
+ #define TX_HDCP_CONFIG0_ROM_ENCRYPT_OFF GENMASK(4, 3)
|
|
+
|
|
+#define TX_HDCP_CONFIG1 0x002C
|
|
+#define TX_HDCP_CONFIG2 0x002D
|
|
+#define TX_HDCP_CONFIG3 0x002E
|
|
+ #define TX_HDCP_CONFIG3_DDC_I2C_BUS_CLOCK_TIME_DIVIDER GENMASK(7, 0)
|
|
+
|
|
+#define TX_HDCP_MODE 0x002F
|
|
+ #define TX_HDCP_MODE_CP_DESIRED BIT(7)
|
|
+ #define TX_HDCP_MODE_ESS_CONFIG BIT(6)
|
|
+ #define TX_HDCP_MODE_SET_AVMUTE BIT(5)
|
|
+ #define TX_HDCP_MODE_CLEAR_AVMUTE BIT(4)
|
|
+ #define TX_HDCP_MODE_HDCP_1_1 BIT(3)
|
|
+ #define TX_HDCP_MODE_VSYNC_HSYNC_FORCED_POLARITY_SELECT BIT(2)
|
|
+ #define TX_HDCP_MODE_FORCED_VSYNC_POLARITY BIT(1)
|
|
+ #define TX_HDCP_MODE_FORCED_HSYNC_POLARITY BIT(0)
|
|
+
|
|
+// Video config, part 1
|
|
+#define TX_VIDEO_ACTIVE_PIXELS_0 0x0030
|
|
+#define TX_VIDEO_ACTIVE_PIXELS_1 0x0031
|
|
+#define TX_VIDEO_FRONT_PIXELS 0x0032
|
|
+#define TX_VIDEO_HSYNC_PIXELS 0x0033
|
|
+#define TX_VIDEO_BACK_PIXELS 0x0034
|
|
+#define TX_VIDEO_ACTIVE_LINES_0 0x0035
|
|
+#define TX_VIDEO_ACTIVE_LINES_1 0x0036
|
|
+#define TX_VIDEO_EOF_LINES 0x0037
|
|
+#define TX_VIDEO_VSYNC_LINES 0x0038
|
|
+#define TX_VIDEO_SOF_LINES 0x0039
|
|
+#define TX_VIDEO_DTV_TIMING 0x003A
|
|
+ #define TX_VIDEO_DTV_TIMING_FORCE_DTV_TIMING_AUTO BIT(7)
|
|
+ #define TX_VIDEO_DTV_TIMING_FORCE_VIDEO_SCAN BIT(6)
|
|
+ #define TX_VIDEO_DTV_TIMING_FORCE_VIDEO_FIELD BIT(5)
|
|
+ #define TX_VIDEO_DTV_TIMING_DISABLE_VIC39_CORRECTION BIT(4)
|
|
+
|
|
+#define TX_VIDEO_DTV_MODE 0x003B
|
|
+ #define TX_VIDEO_DTV_MODE_FORCED_DEFAULT_PHASE BIT(7)
|
|
+ #define TX_VIDEO_DTV_MODE_COLOR_DEPTH GENMASK(1, 0)
|
|
+
|
|
+#define TX_VIDEO_DTV_FORMAT0 0x003C
|
|
+#define TX_VIDEO_DTV_FORMAT1 0x003D
|
|
+#define TX_VIDEO_PIXEL_PACK 0x003F
|
|
+// video config, part 2
|
|
+#define TX_VIDEO_CSC_COEFF_B0 0x0040
|
|
+#define TX_VIDEO_CSC_COEFF_B1 0x0041
|
|
+#define TX_VIDEO_CSC_COEFF_R0 0x0042
|
|
+#define TX_VIDEO_CSC_COEFF_R1 0x0043
|
|
+#define TX_VIDEO_CSC_COEFF_CB0 0x0044
|
|
+#define TX_VIDEO_CSC_COEFF_CB1 0x0045
|
|
+#define TX_VIDEO_CSC_COEFF_CR0 0x0046
|
|
+#define TX_VIDEO_CSC_COEFF_CR1 0x0047
|
|
+#define TX_VIDEO_DTV_OPTION_L 0x0048
|
|
+ #define TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_FORMAT GENMASK(7, 6)
|
|
+ #define TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_FORMAT GENMASK(5, 4)
|
|
+ #define TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_DEPTH GENMASK(3, 2)
|
|
+ #define TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_DEPTH GENMASK(1, 0)
|
|
+
|
|
+#define TX_VIDEO_DTV_OPTION_H 0x0049
|
|
+ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_16_235 0x0
|
|
+ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_16_240 0x1
|
|
+ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_1_254 0x2
|
|
+ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_0_255 0x3
|
|
+ #define TX_VIDEO_DTV_OPTION_H_OUTPUT_COLOR_RANGE GENMASK(3, 2)
|
|
+ #define TX_VIDEO_DTV_OPTION_H_INPUT_COLOR_RANGE GENMASK(1, 0)
|
|
+
|
|
+#define TX_VIDEO_DTV_FILTER 0x004A
|
|
+#define TX_VIDEO_DTV_DITHER 0x004B
|
|
+#define TX_VIDEO_DTV_DEDITHER 0x004C
|
|
+#define TX_VIDEO_PROC_CONFIG0 0x004E
|
|
+#define TX_VIDEO_PROC_CONFIG1 0x004F
|
|
+
|
|
+// Audio config
|
|
+#define TX_AUDIO_FORMAT 0x0058
|
|
+ #define TX_AUDIO_FORMAT_SPDIF_OR_I2S BIT(7)
|
|
+ #define TX_AUDIO_FORMAT_I2S_2_OR_8_CH BIT(6)
|
|
+ #define TX_AUDIO_FORMAT_I2S_FORMAT GENMASK(5, 4)
|
|
+ #define TX_AUDIO_FORMAT_BIT_WIDTH_MASK GENMASK(3, 2)
|
|
+ #define TX_AUDIO_FORMAT_BIT_WIDTH_16 0x1
|
|
+ #define TX_AUDIO_FORMAT_BIT_WIDTH_20 0x2
|
|
+ #define TX_AUDIO_FORMAT_BIT_WIDTH_24 0x3
|
|
+ #define TX_AUDIO_FORMAT_WS_POLARITY BIT(1)
|
|
+ #define TX_AUDIO_FORMAT_I2S_ONE_BIT_OR_I2S BIT(0)
|
|
+ #define TX_AUDIO_FORMAT_SPDIF_CHANNEL_STATUS_FROM_DATA_OR_REG BIT(0)
|
|
+
|
|
+#define TX_AUDIO_SPDIF 0x0059
|
|
+ #define TX_AUDIO_SPDIF_ENABLE BIT(0)
|
|
+#define TX_AUDIO_I2S 0x005A
|
|
+ #define TX_AUDIO_I2S_ENABLE BIT(0)
|
|
+#define TX_AUDIO_FIFO 0x005B
|
|
+ #define TX_AUDIO_FIFO_FIFO_DEPTH_MASK GENMASK(7, 4)
|
|
+ #define TX_AUDIO_FIFO_FIFO_DEPTH_512 0x4
|
|
+ #define TX_AUDIO_FIFO_CRITICAL_THRESHOLD_MASK GENMASK(3, 2)
|
|
+ #define TX_AUDIO_FIFO_CRITICAL_THRESHOLD_DEPTH_DIV16 0x2
|
|
+ #define TX_AUDIO_FIFO_NORMAL_THRESHOLD_MASK GENMASK(1, 0)
|
|
+ #define TX_AUDIO_FIFO_NORMAL_THRESHOLD_DEPTH_DIV8 0x1
|
|
+#define TX_AUDIO_LIPSYNC 0x005C
|
|
+ #define TX_AUDIO_LIPSYNC_NORMALIZED_LIPSYNC_PARAM GENMASK(7, 0)
|
|
+#define TX_AUDIO_CONTROL 0x005D
|
|
+ #define TX_AUDIO_CONTROL_FORCED_AUDIO_FIFO_CLEAR BIT(7)
|
|
+ #define TX_AUDIO_CONTROL_AUTO_AUDIO_FIFO_CLEAR BIT(6)
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_MASK GENMASK(5, 4)
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_AUDIO_SAMPLE_PACKET 0x0
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_ONE_BIT_AUDIO 0x1
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_HBR_AUDIO_PACKET 0x2
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_DST_AUDIO_PACKET 0x3
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_VALID BIT(2)
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_USER BIT(1)
|
|
+ #define TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_FLAT BIT(0)
|
|
+#define TX_AUDIO_HEADER 0x005E
|
|
+ #define TX_AUDIO_HEADER_AUDIO_SAMPLE_PACKET_HEADER_LAYOUT1 BIT(7)
|
|
+ #define TX_AUDIO_HEADER_SET_NORMAL_DOUBLE_IN_DST_PACKET_HEADER BIT(6)
|
|
+#define TX_AUDIO_SAMPLE 0x005F
|
|
+ #define TX_AUDIO_SAMPLE_CHANNEL_VALID GENMASK(7, 0)
|
|
+#define TX_AUDIO_VALID 0x0060
|
|
+#define TX_AUDIO_USER 0x0061
|
|
+#define TX_AUDIO_PACK 0x0062
|
|
+ #define TX_AUDIO_PACK_AUDIO_SAMPLE_PACKETS_ENABLE BIT(0)
|
|
+#define TX_AUDIO_CONTROL_MORE 0x0064
|
|
+ #define TX_AUDIO_CONTROL_MORE_ENABLE BIT(0)
|
|
+
|
|
+// tmds config
|
|
+#define TX_TMDS_MODE 0x0068
|
|
+ #define TX_TMDS_MODE_FORCED_HDMI BIT(7)
|
|
+ #define TX_TMDS_MODE_HDMI_CONFIG BIT(6)
|
|
+ #define TX_TMDS_MODE_BIT_SWAP BIT(3)
|
|
+ #define TX_TMDS_MODE_CHANNEL_SWAP GENMASK(2, 0)
|
|
+
|
|
+#define TX_TMDS_CONFIG0 0x006C
|
|
+#define TX_TMDS_CONFIG1 0x006D
|
|
+
|
|
+// packet config
|
|
+#define TX_PACKET_ALLOC_ACTIVE_1 0x0078
|
|
+#define TX_PACKET_ALLOC_ACTIVE_2 0x0079
|
|
+#define TX_PACKET_ALLOC_EOF_1 0x007A
|
|
+#define TX_PACKET_ALLOC_EOF_2 0x007B
|
|
+#define TX_PACKET_ALLOC_SOF_1 0x007C
|
|
+#define TX_PACKET_ALLOC_SOF_2 0x007D
|
|
+#define TX_PACKET_CONTROL_1 0x007E
|
|
+ #define TX_PACKET_CONTROL_1_FORCE_PACKET_TIMING BIT(7)
|
|
+ #define TX_PACKET_CONTROL_1_PACKET_ALLOC_MODE BIT(6)
|
|
+ #define TX_PACKET_CONTROL_1_PACKET_START_LATENCY GENMASK(5, 0)
|
|
+
|
|
+#define TX_PACKET_CONTROL_2 0x007F
|
|
+ #define TX_PACKET_CONTROL_2_AUDIO_REQUEST_DISABLE BIT(3)
|
|
+ #define TX_PACKET_CONTROL_2_HORIZONTAL_GC_PACKET_TRANSPORT_EN BIT(1)
|
|
+
|
|
+#define TX_CORE_EDID_CONFIG_MORE 0x0080
|
|
+ #define TX_CORE_EDID_CONFIG_MORE_KEEP_EDID_ERROR BIT(1)
|
|
+ #define TX_CORE_EDID_CONFIG_MORE_SYS_TRIGGER_CONFIG_SEMI_MANU BIT(0)
|
|
+
|
|
+#define TX_CORE_ALLOC_VSYNC_0 0x0081
|
|
+#define TX_CORE_ALLOC_VSYNC_1 0x0082
|
|
+#define TX_CORE_ALLOC_VSYNC_2 0x0083
|
|
+#define TX_MEM_PD_REG0 0x0084
|
|
+
|
|
+// core config
|
|
+#define TX_CORE_DATA_CAPTURE_1 0x00F0
|
|
+#define TX_CORE_DATA_CAPTURE_2 0x00F1
|
|
+ #define TX_CORE_DATA_CAPTURE_2_AUDIO_SOURCE_SELECT GENMASK(7, 6)
|
|
+ #define TX_CORE_DATA_CAPTURE_2_EXTERNAL_PACKET_ENABLE BIT(5)
|
|
+ #define TX_CORE_DATA_CAPTURE_2_INTERNAL_PACKET_ENABLE BIT(4)
|
|
+ #define TX_CORE_DATA_CAPTURE_2_AFE_FIFO_SRC_LANE1 GENMASK(3, 2)
|
|
+ #define TX_CORE_DATA_CAPTURE_2_AFE_FIFO_SRC_LANE0 GENMASK(1, 0)
|
|
+
|
|
+#define TX_CORE_DATA_MONITOR_1 0x00F2
|
|
+ #define TX_CORE_DATA_MONITOR_1_LANE1 BIT(7)
|
|
+ #define TX_CORE_DATA_MONITOR_1_SELECT_LANE1 GENMASK(6, 4)
|
|
+ #define TX_CORE_DATA_MONITOR_1_LANE0 BIT(3)
|
|
+ #define TX_CORE_DATA_MONITOR_1_SELECT_LANE0 GENMASK(2, 0)
|
|
+
|
|
+#define TX_CORE_DATA_MONITOR_2 0x00F3
|
|
+ #define TX_CORE_DATA_MONITOR_2_MONITOR_SELECT GENMASK(2, 0)
|
|
+
|
|
+#define TX_CORE_CALIB_MODE 0x00F4
|
|
+#define TX_CORE_CALIB_SAMPLE_DELAY 0x00F5
|
|
+#define TX_CORE_CALIB_VALUE_AUTO 0x00F6
|
|
+#define TX_CORE_CALIB_VALUE 0x00F7
|
|
+
|
|
+// system config 4
|
|
+#define TX_SYS4_TX_CKI_DDR 0x00A0
|
|
+#define TX_SYS4_TX_CKO_DDR 0x00A1
|
|
+#define TX_SYS4_RX_CKI_DDR 0x00A2
|
|
+#define TX_SYS4_RX_CKO_DDR 0x00A3
|
|
+#define TX_SYS4_CONNECT_SEL_0 0x00A4
|
|
+#define TX_SYS4_CONNECT_SEL_1 0x00A5
|
|
+ #define TX_SYS4_CONNECT_SEL_1_TX_CONNECT_SEL_UPPER_CHANNEL_DATA BIT(6)
|
|
+
|
|
+#define TX_SYS4_CONNECT_SEL_2 0x00A6
|
|
+#define TX_SYS4_CONNECT_SEL_3 0x00A7
|
|
+#define TX_SYS4_CK_INV_VIDEO 0x00A8
|
|
+ #define TX_SYS4_CK_INV_VIDEO_TMDS_CLK_PATTERN BIT(4)
|
|
+#define TX_SYS4_CK_INV_AUDIO 0x00A9
|
|
+#define TX_SYS4_CK_INV_AFE 0x00AA
|
|
+#define TX_SYS4_CK_INV_CH01 0x00AB
|
|
+#define TX_SYS4_CK_INV_CH2 0x00AC
|
|
+#define TX_SYS4_CK_CEC 0x00AD
|
|
+#define TX_SYS4_CK_SOURCE_1 0x00AE
|
|
+#define TX_SYS4_CK_SOURCE_2 0x00AF
|
|
+
|
|
+#define TX_IEC60958_SUB1_OFFSET 0x00B0
|
|
+#define TX_IEC60958_SUB2_OFFSET 0x00C8
|
|
+
|
|
+// system config 5
|
|
+#define TX_SYS5_TX_SOFT_RESET_1 0x00E0
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_PIXEL_RSTN BIT(7)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN BIT(6)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN BIT(5)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN BIT(4)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_I2S_RESET_RSTN BIT(3)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH2 BIT(2)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH1 BIT(1)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH0 BIT(0)
|
|
+
|
|
+#define TX_SYS5_TX_SOFT_RESET_2 0x00E1
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH3_RST_IN BIT(7)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN BIT(6)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN BIT(5)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH0_RST_IN BIT(4)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_SR_RST BIT(3)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_TX_DDC_HDCP_RSTN BIT(2)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_TX_DDC_EDID_RSTN BIT(1)
|
|
+ #define TX_SYS5_TX_SOFT_RESET_2_TX_DIG_RESET_N_CH3 BIT(0)
|
|
+
|
|
+#define TX_SYS5_RX_SOFT_RESET_1 0x00E2
|
|
+#define TX_SYS5_RX_SOFT_RESET_2 0x00E3
|
|
+#define TX_SYS5_RX_SOFT_RESET_3 0x00E4
|
|
+#define TX_SYS5_SSTL_BIDIR_IN 0x00E5
|
|
+#define TX_SYS5_SSTL_IN 0x00E6
|
|
+#define TX_SYS5_SSTL_DIFF_IN 0x00E7
|
|
+#define TX_SYS5_FIFO_CONFIG 0x00E8
|
|
+ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL2_BYPASS BIT(6)
|
|
+ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL1_BYPASS BIT(5)
|
|
+ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL0_BYPASS BIT(4)
|
|
+ #define TX_SYS5_FIFO_CONFIG_CLK_CHANNEL3_OUTPUT_ENABLE BIT(3)
|
|
+ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL2_ENABLE BIT(2)
|
|
+ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL1_ENABLE BIT(1)
|
|
+ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL0_ENABLE BIT(0)
|
|
+
|
|
+#define TX_SYS5_FIFO_SAMP01_CFG 0x00E9
|
|
+#define TX_SYS5_FIFO_SAMP23_CFG 0x00EA
|
|
+#define TX_SYS5_CONNECT_FIFO_CFG 0x00EB
|
|
+#define TX_SYS5_IO_CALIB_CONTROL 0x00EC
|
|
+#define TX_SYS5_SSTL_BIDIR_OUT 0x00ED
|
|
+#define TX_SYS5_SSTL_OUT 0x00EE
|
|
+#define TX_SYS5_SSTL_DIFF_OUT 0x00EF
|
|
+
|
|
+// HDCP shadow register
|
|
+#define TX_HDCP_SHW_BKSV_0 0x0100
|
|
+#define TX_HDCP_SHW_BKSV_1 0x0101
|
|
+#define TX_HDCP_SHW_BKSV_2 0x0102
|
|
+#define TX_HDCP_SHW_BKSV_3 0x0103
|
|
+#define TX_HDCP_SHW_BKSV_4 0x0104
|
|
+#define TX_HDCP_SHW_RI1_0 0x0108
|
|
+#define TX_HDCP_SHW_RI1_1 0x0109
|
|
+#define TX_HDCP_SHW_PJ1 0x010A
|
|
+#define TX_HDCP_SHW_AKSV_0 0x0110
|
|
+#define TX_HDCP_SHW_AKSV_1 0x0111
|
|
+#define TX_HDCP_SHW_AKSV_2 0x0112
|
|
+#define TX_HDCP_SHW_AKSV_3 0x0113
|
|
+#define TX_HDCP_SHW_AKSV_4 0x0114
|
|
+#define TX_HDCP_SHW_AINFO 0x0115
|
|
+#define TX_HDCP_SHW_AN_0 0x0118
|
|
+#define TX_HDCP_SHW_AN_1 0x0119
|
|
+#define TX_HDCP_SHW_AN_2 0x011A
|
|
+#define TX_HDCP_SHW_AN_3 0x011B
|
|
+#define TX_HDCP_SHW_AN_4 0x011C
|
|
+#define TX_HDCP_SHW_AN_5 0x011D
|
|
+#define TX_HDCP_SHW_AN_6 0x011E
|
|
+#define TX_HDCP_SHW_AN_7 0x011F
|
|
+#define TX_HDCP_SHW_V1_H0_0 0x0120
|
|
+#define TX_HDCP_SHW_V1_H0_1 0x0121
|
|
+#define TX_HDCP_SHW_V1_H0_2 0x0122
|
|
+#define TX_HDCP_SHW_V1_H0_3 0x0123
|
|
+#define TX_HDCP_SHW_V1_H1_0 0x0124
|
|
+#define TX_HDCP_SHW_V1_H1_1 0x0125
|
|
+#define TX_HDCP_SHW_V1_H1_2 0x0126
|
|
+#define TX_HDCP_SHW_V1_H1_3 0x0127
|
|
+#define TX_HDCP_SHW_V1_H2_0 0x0128
|
|
+#define TX_HDCP_SHW_V1_H2_1 0x0129
|
|
+#define TX_HDCP_SHW_V1_H2_2 0x012A
|
|
+#define TX_HDCP_SHW_V1_H2_3 0x012B
|
|
+#define TX_HDCP_SHW_V1_H3_0 0x012C
|
|
+#define TX_HDCP_SHW_V1_H3_1 0x012D
|
|
+#define TX_HDCP_SHW_V1_H3_2 0x012E
|
|
+#define TX_HDCP_SHW_V1_H3_3 0x012F
|
|
+#define TX_HDCP_SHW_V1_H4_0 0x0130
|
|
+#define TX_HDCP_SHW_V1_H4_1 0x0131
|
|
+#define TX_HDCP_SHW_V1_H4_2 0x0132
|
|
+#define TX_HDCP_SHW_V1_H4_3 0x0133
|
|
+#define TX_HDCP_SHW_BCAPS 0x0140
|
|
+#define TX_HDCP_SHW_BSTATUS_0 0x0141
|
|
+#define TX_HDCP_SHW_BSTATUS_1 0x0142
|
|
+#define TX_HDCP_SHW_KSV_FIFO 0x0143
|
|
+
|
|
+// system status 0
|
|
+#define TX_SYSST0_CONNECT_FIFO 0x0180
|
|
+#define TX_SYSST0_PLL_MONITOR 0x0181
|
|
+#define TX_SYSST0_AFE_FIFO 0x0182
|
|
+#define TX_SYSST0_ROM_STATUS 0x018F
|
|
+
|
|
+// hdcp status
|
|
+#define TX_HDCP_ST_AUTHENTICATION 0x0190
|
|
+#define TX_HDCP_ST_FRAME_COUNT 0x0191
|
|
+#define TX_HDCP_ST_STATUS_0 0x0192
|
|
+#define TX_HDCP_ST_STATUS_1 0x0193
|
|
+#define TX_HDCP_ST_STATUS_2 0x0194
|
|
+#define TX_HDCP_ST_STATUS_3 0x0195
|
|
+#define TX_HDCP_ST_EDID_STATUS 0x0196
|
|
+ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS GENMASK(7, 6)
|
|
+ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_NO_SINK_ATTACHED 0x0
|
|
+ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_READING_EDID 0x1
|
|
+ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_DVI_MODE 0x2
|
|
+ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_HDMI_MODE 0x3
|
|
+ #define TX_HDCP_ST_EDID_STATUS_EDID_DATA_READY BIT(4)
|
|
+ #define TX_HDCP_ST_EDID_STATUS_HPD_STATUS BIT(1)
|
|
+
|
|
+#define TX_HDCP_ST_MEM_STATUS 0x0197
|
|
+#define TX_HDCP_ST_ST_MODE 0x019F
|
|
+
|
|
+// video status
|
|
+#define TX_VIDEO_ST_ACTIVE_PIXELS_1 0x01A0
|
|
+#define TX_VIDEO_ST_ACTIVE_PIXELS_2 0x01A1
|
|
+#define TX_VIDEO_ST_FRONT_PIXELS 0x01A2
|
|
+#define TX_VIDEO_ST_HSYNC_PIXELS 0x01A3
|
|
+#define TX_VIDEO_ST_BACK_PIXELS 0x01A4
|
|
+#define TX_VIDEO_ST_ACTIVE_LINES_1 0x01A5
|
|
+#define TX_VIDEO_ST_ACTIVE_LINES_2 0x01A6
|
|
+#define TX_VIDEO_ST_EOF_LINES 0x01A7
|
|
+#define TX_VIDEO_ST_VSYNC_LINES 0x01A8
|
|
+#define TX_VIDEO_ST_SOF_LINES 0x01A9
|
|
+#define TX_VIDEO_ST_DTV_TIMING 0x01AA
|
|
+#define TX_VIDEO_ST_DTV_MODE 0x01AB
|
|
+// audio status
|
|
+#define TX_VIDEO_ST_AUDIO_STATUS 0x01AC
|
|
+#define TX_AFE_STATUS_0 0x01AE
|
|
+#define TX_AFE_STATUS_1 0x01AF
|
|
+
|
|
+#define TX_IEC60958_ST_SUB1_OFFSET 0x01B0
|
|
+#define TX_IEC60958_ST_SUB2_OFFSET 0x01C8
|
|
+
|
|
+// system status 1
|
|
+#define TX_SYSST1_CALIB_BIT_RESULT_0 0x01E0
|
|
+#define TX_SYSST1_CALIB_BIT_RESULT_1 0x01E1
|
|
+//HDMI_STATUS_OUT[7:0]
|
|
+#define TX_HDMI_PHY_READBACK_0 0x01E2
|
|
+//HDMI_COMP_OUT[4]
|
|
+//HDMI_STATUS_OUT[11:8]
|
|
+#define TX_HDMI_PHY_READBACK_1 0x01E3
|
|
+#define TX_SYSST1_CALIB_BIT_RESULT_4 0x01E4
|
|
+#define TX_SYSST1_CALIB_BIT_RESULT_5 0x01E5
|
|
+#define TX_SYSST1_CALIB_BIT_RESULT_6 0x01E6
|
|
+#define TX_SYSST1_CALIB_BIT_RESULT_7 0x01E7
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_0 0x01E8
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_1 0x01E9
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_2 0x01EA
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_3 0x01EB
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_4 0x01EC
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_5 0x01ED
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_6 0x01EE
|
|
+#define TX_SYSST1_CALIB_BUS_RESULT_7 0x01EF
|
|
+
|
|
+// Packet status
|
|
+#define TX_PACKET_ST_REQUEST_STATUS_1 0x01F0
|
|
+#define TX_PACKET_ST_REQUEST_STATUS_2 0x01F1
|
|
+#define TX_PACKET_ST_REQUEST_MISSED_1 0x01F2
|
|
+#define TX_PACKET_ST_REQUEST_MISSED_2 0x01F3
|
|
+#define TX_PACKET_ST_ENCODE_STATUS_0 0x01F4
|
|
+#define TX_PACKET_ST_ENCODE_STATUS_1 0x01F5
|
|
+#define TX_PACKET_ST_ENCODE_STATUS_2 0x01F6
|
|
+#define TX_PACKET_ST_TIMER_STATUS 0x01F7
|
|
+
|
|
+// tmds status
|
|
+#define TX_TMDS_ST_CLOCK_METER_1 0x01F8
|
|
+#define TX_TMDS_ST_CLOCK_METER_2 0x01F9
|
|
+#define TX_TMDS_ST_CLOCK_METER_3 0x01FA
|
|
+#define TX_TMDS_ST_TMDS_STATUS_1 0x01FC
|
|
+#define TX_TMDS_ST_TMDS_STATUS_2 0x01FD
|
|
+#define TX_TMDS_ST_TMDS_STATUS_3 0x01FE
|
|
+#define TX_TMDS_ST_TMDS_STATUS_4 0x01FF
|
|
+
|
|
+// Packet register
|
|
+#define TX_PKT_REG_SPD_INFO_BASE_ADDR 0x0200
|
|
+#define TX_PKT_REG_VEND_INFO_BASE_ADDR 0x0220
|
|
+#define TX_PKT_REG_MPEG_INFO_BASE_ADDR 0x0240
|
|
+#define TX_PKT_REG_AVI_INFO_BASE_ADDR 0x0260
|
|
+#define TX_PKT_REG_AUDIO_INFO_BASE_ADDR 0x0280
|
|
+#define TX_PKT_REG_ACP_INFO_BASE_ADDR 0x02A0
|
|
+#define TX_PKT_REG_ISRC1_BASE_ADDR 0x02C0
|
|
+#define TX_PKT_REG_ISRC2_BASE_ADDR 0x02E0
|
|
+#define TX_PKT_REG_EXCEPT0_BASE_ADDR 0x0300
|
|
+#define TX_PKT_REG_EXCEPT1_BASE_ADDR 0x0320
|
|
+#define TX_PKT_REG_EXCEPT2_BASE_ADDR 0x0340
|
|
+#define TX_PKT_REG_EXCEPT3_BASE_ADDR 0x0360
|
|
+#define TX_PKT_REG_EXCEPT4_BASE_ADDR 0x0380
|
|
+#define TX_PKT_REG_GAMUT_P0_BASE_ADDR 0x03A0
|
|
+#define TX_PKT_REG_GAMUT_P1_1_BASE_ADDR 0x03C0
|
|
+#define TX_PKT_REG_GAMUT_P1_2_BASE_ADDR 0x03E0
|
|
+
|
|
+#define TX_RX_EDID_OFFSET 0x0600
|
|
+
|
|
+/* HDMI OTHER registers */
|
|
+
|
|
+#define HDMI_OTHER_CTRL0 0x8000
|
|
+#define HDMI_OTHER_CTRL1 0x8001
|
|
+ #define HDMI_OTHER_CTRL1_POWER_ON BIT(15)
|
|
+ #define HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON BIT(13)
|
|
+
|
|
+#define HDMI_OTHER_STATUS0 0x8002
|
|
+#define HDMI_OTHER_CTRL2 0x8003
|
|
+#define HDMI_OTHER_INTR_MASKN 0x8004
|
|
+ #define HDMI_OTHER_INTR_MASKN_TX_EDID_INT_RISE BIT(2)
|
|
+ #define HDMI_OTHER_INTR_MASKN_TX_HPD_INT_FALL BIT(1)
|
|
+ #define HDMI_OTHER_INTR_MASKN_TX_HPD_INT_RISE BIT(0)
|
|
+
|
|
+#define HDMI_OTHER_INTR_STAT 0x8005
|
|
+ #define HDMI_OTHER_INTR_STAT_EDID_RISING BIT(2)
|
|
+ #define HDMI_OTHER_INTR_STAT_HPD_FALLING BIT(1)
|
|
+ #define HDMI_OTHER_INTR_STAT_HPD_RISING BIT(0)
|
|
+
|
|
+#define HDMI_OTHER_INTR_STAT_CLR 0x8006
|
|
+ #define HDMI_OTHER_INTR_STAT_CLR_EDID_RISING BIT(2)
|
|
+ #define HDMI_OTHER_INTR_STAT_CLR_HPD_FALLING BIT(1)
|
|
+ #define HDMI_OTHER_INTR_STAT_CLR_HPD_RISING BIT(0)
|
|
+
|
|
+#define HDMI_OTHER_AVI_INTR_MASKN0 0x8008
|
|
+#define HDMI_OTHER_AVI_INTR_MASKN1 0x8009
|
|
+#define HDMI_OTHER_RX_AINFO_INTR_MASKN0 0x800a
|
|
+#define HDMI_OTHER_RX_AINFO_INTR_MASKN1 0x800b
|
|
+#define HDMI_OTHER_RX_PACKET_INTR_CLR 0x800c
|
|
+
|
|
+#endif /* __MESON_TRANSWITCH_HDMI_H__ */
|
|
--
|
|
Armbian
|
|
|