// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) Rockchip Electronics Co., Ltd.
* Zheng Yang <zhengyang@rock-chips.com>
* Yakir Yang <ykk@rock-chips.com>
* Andy Yan <andyshrk@163.com>
*/
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/hdmi.h>
#include <linux/mfd/syscon.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <drm/bridge/inno_hdmi.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
#define DDC_SEGMENT_ADDR 0x30
#define HDMI_SCL_RATE (100 * 1000)
#define DDC_BUS_FREQ_L 0x4b
#define DDC_BUS_FREQ_H 0x4c
#define HDMI_SYS_CTRL 0x00
#define m_RST_ANALOG BIT(6)
#define v_RST_ANALOG (0 << 6)
#define v_NOT_RST_ANALOG BIT(6)
#define m_RST_DIGITAL BIT(5)
#define v_RST_DIGITAL (0 << 5)
#define v_NOT_RST_DIGITAL BIT(5)
#define m_REG_CLK_INV BIT(4)
#define v_REG_CLK_NOT_INV (0 << 4)
#define v_REG_CLK_INV BIT(4)
#define m_VCLK_INV BIT(3)
#define v_VCLK_NOT_INV (0 << 3)
#define v_VCLK_INV BIT(3)
#define m_REG_CLK_SOURCE BIT(2)
#define v_REG_CLK_SOURCE_TMDS (0 << 2)
#define v_REG_CLK_SOURCE_SYS BIT(2)
#define m_POWER BIT(1)
#define v_PWR_ON (0 << 1)
#define v_PWR_OFF BIT(1)
#define m_INT_POL BIT(0)
#define v_INT_POL_HIGH 1
#define v_INT_POL_LOW 0
#define HDMI_VIDEO_CONTRL1 0x01
#define m_VIDEO_INPUT_FORMAT (7 << 1)
#define m_DE_SOURCE BIT(0)
#define v_VIDEO_INPUT_FORMAT(n) ((n) << 1)
#define v_DE_EXTERNAL 1
#define v_DE_INTERNAL 0
enum {
VIDEO_INPUT_SDR_RGB444 = 0,
VIDEO_INPUT_DDR_RGB444 = 5,
VIDEO_INPUT_DDR_YCBCR422 = 6
};
#define HDMI_VIDEO_CONTRL2 0x02
#define m_VIDEO_OUTPUT_COLOR (3 << 6)
#define m_VIDEO_INPUT_BITS (3 << 4)
#define m_VIDEO_INPUT_CSP BIT(0)
#define v_VIDEO_OUTPUT_COLOR(n) (((n) & 0x3) << 6)
#define v_VIDEO_INPUT_BITS(n) ((n) << 4)
#define v_VIDEO_INPUT_CSP(n) ((n) << 0)
enum {
VIDEO_INPUT_12BITS = 0,
VIDEO_INPUT_10BITS = 1,
VIDEO_INPUT_REVERT = 2,
VIDEO_INPUT_8BITS = 3,
};
#define HDMI_VIDEO_CONTRL 0x03
#define m_VIDEO_AUTO_CSC BIT(7)
#define v_VIDEO_AUTO_CSC(n) ((n) << 7)
#define m_VIDEO_C0_C2_SWAP BIT(0)
#define v_VIDEO_C0_C2_SWAP(n) ((n) << 0)
enum {
C0_C2_CHANGE_ENABLE = 0,
C0_C2_CHANGE_DISABLE = 1,
AUTO_CSC_DISABLE = 0,
AUTO_CSC_ENABLE = 1,
};
#define HDMI_VIDEO_CONTRL3 0x04
#define m_COLOR_DEPTH_NOT_INDICATED BIT(4)
#define m_SOF BIT(3)
#define m_COLOR_RANGE BIT(2)
#define m_CSC BIT(0)
#define v_COLOR_DEPTH_NOT_INDICATED(n) ((n) << 4)
#define v_SOF_ENABLE (0 << 3)
#define v_SOF_DISABLE BIT(3)
#define v_COLOR_RANGE_FULL BIT(2)
#define v_COLOR_RANGE_LIMITED (0 << 2)
#define v_CSC_ENABLE 1
#define v_CSC_DISABLE 0
#define HDMI_AV_MUTE 0x05
#define m_AVMUTE_CLEAR BIT(7)
#define m_AVMUTE_ENABLE BIT(6)
#define m_AUDIO_MUTE BIT(1)
#define m_VIDEO_BLACK BIT(0)
#define v_AVMUTE_CLEAR(n) ((n) << 7)
#define v_AVMUTE_ENABLE(n) ((n) << 6)
#define v_AUDIO_MUTE(n) ((n) << 1)
#define v_VIDEO_MUTE(n) ((n) << 0)
#define HDMI_VIDEO_TIMING_CTL 0x08
#define v_HSYNC_POLARITY(n) ((n) << 3)
#define v_VSYNC_POLARITY(n) ((n) << 2)
#define v_INETLACE(n) ((n) << 1)
#define v_EXTERANL_VIDEO(n) ((n) << 0)
#define HDMI_VIDEO_EXT_HTOTAL_L 0x09
#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a
#define HDMI_VIDEO_EXT_HBLANK_L 0x0b
#define HDMI_VIDEO_EXT_HBLANK_H 0x0c
#define HDMI_VIDEO_EXT_HDELAY_L 0x0d
#define HDMI_VIDEO_EXT_HDELAY_H 0x0e
#define HDMI_VIDEO_EXT_HDURATION_L 0x0f
#define HDMI_VIDEO_EXT_HDURATION_H 0x10
#define HDMI_VIDEO_EXT_VTOTAL_L 0x11
#define HDMI_VIDEO_EXT_VTOTAL_H 0x12
#define HDMI_VIDEO_EXT_VBLANK 0x13
#define HDMI_VIDEO_EXT_VDELAY 0x14
#define HDMI_VIDEO_EXT_VDURATION 0x15
#define HDMI_VIDEO_CSC_COEF 0x18
#define HDMI_AUDIO_CTRL1 0x35
enum {
CTS_SOURCE_INTERNAL = 0,
CTS_SOURCE_EXTERNAL = 1,
};
#define v_CTS_SOURCE(n) ((n) << 7)
enum {
DOWNSAMPLE_DISABLE = 0,
DOWNSAMPLE_1_2 = 1,
DOWNSAMPLE_1_4 = 2,
};
#define v_DOWN_SAMPLE(n) ((n) << 5)
enum {
AUDIO_SOURCE_IIS = 0,
AUDIO_SOURCE_SPDIF = 1,
};
#define v_AUDIO_SOURCE(n) ((n) << 3)
#define v_MCLK_ENABLE(n) ((n) << 2)
enum {
MCLK_128FS = 0,
MCLK_256FS = 1,
MCLK_384FS = 2,
MCLK_512FS = 3,
};
#define v_MCLK_RATIO(n) (n)
#define AUDIO_SAMPLE_RATE 0x37
enum {
AUDIO_32K = 0x3,
AUDIO_441K = 0x0,
AUDIO_48K = 0x2,
AUDIO_882K = 0x8,
AUDIO_96K = 0xa,
AUDIO_1764K = 0xc,
AUDIO_192K = 0xe,
};
#define AUDIO_I2S_MODE 0x38
enum {
I2S_CHANNEL_1_2 = 1,
I2S_CHANNEL_3_4 = 3,
I2S_CHANNEL_5_6 = 7,
I2S_CHANNEL_7_8 = 0xf
};
#define v_I2S_CHANNEL(n) ((n) << 2)
enum {
I2S_STANDARD = 0,
I2S_LEFT_JUSTIFIED = 1,
I2S_RIGHT_JUSTIFIED = 2,
};
#define v_I2S_MODE(n) (n)
#define AUDIO_I2S_MAP 0x39
#define AUDIO_I2S_SWAPS_SPDIF 0x3a
#define v_SPIDF_FREQ(n) (n)
#define N_32K 0x1000
#define N_441K 0x1880
#define N_882K 0x3100
#define N_1764K 0x6200
#define N_48K 0x1800
#define N_96K 0x3000
#define N_192K 0x6000
#define HDMI_AUDIO_CHANNEL_STATUS 0x3e
#define m_AUDIO_STATUS_NLPCM BIT(7)
#define m_AUDIO_STATUS_USE BIT(6)
#define m_AUDIO_STATUS_COPYRIGHT BIT(5)
#define m_AUDIO_STATUS_ADDITION (3 << 2)
#define m_AUDIO_STATUS_CLK_ACCURACY (2 << 0)