linux/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * DesignWare High-Definition Multimedia Interface (HDMI) driver
 *
 * Copyright (C) 2013-2015 Mentor Graphics Inc.
 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
 * Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
 */
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>

#include <media/cec-notifier.h>

#include <uapi/linux/media-bus-format.h>
#include <uapi/linux/videodev2.h>

#include <drm/bridge/dw_hdmi.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>

#include "dw-hdmi-audio.h"
#include "dw-hdmi-cec.h"
#include "dw-hdmi.h"

#define DDC_CI_ADDR
#define DDC_SEGMENT_ADDR

#define HDMI_EDID_LEN

/* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */
#define SCDC_MIN_SOURCE_VERSION

#define HDMI14_MAX_TMDSCLK

static const u16 csc_coeff_default[3][4] =;

static const u16 csc_coeff_rgb_out_eitu601[3][4] =;

static const u16 csc_coeff_rgb_out_eitu709[3][4] =;

static const u16 csc_coeff_rgb_in_eitu601[3][4] =;

static const u16 csc_coeff_rgb_in_eitu709[3][4] =;

static const u16 csc_coeff_rgb_full_to_rgb_limited[3][4] =;

struct hdmi_vmode {};

struct hdmi_data_info {};

struct dw_hdmi_i2c {};

struct dw_hdmi_phy_data {};

struct dw_hdmi {};

#define HDMI_IH_PHY_STAT0_RX_SENSE

#define HDMI_PHY_RX_SENSE

static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{}

static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{}

static void handle_plugged_change(struct dw_hdmi *hdmi, bool plugged)
{}

int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn,
			   struct device *codec_dev)
{}
EXPORT_SYMBOL_GPL();

static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{}

static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
			     u8 shift, u8 mask)
{}

static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
{}

static bool dw_hdmi_i2c_unwedge(struct dw_hdmi *hdmi)
{}

static int dw_hdmi_i2c_wait(struct dw_hdmi *hdmi)
{}

static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi,
			    unsigned char *buf, unsigned int length)
{}

static int dw_hdmi_i2c_write(struct dw_hdmi *hdmi,
			     unsigned char *buf, unsigned int length)
{}

static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap,
			    struct i2c_msg *msgs, int num)
{}

static u32 dw_hdmi_i2c_func(struct i2c_adapter *adapter)
{}

static const struct i2c_algorithm dw_hdmi_algorithm =;

static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi)
{}

static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
			   unsigned int n)
{}

static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk)
{}

/*
 * When transmitting IEC60958 linear PCM audio, these registers allow to
 * configure the channel status information of all the channel status
 * bits in the IEC60958 frame. For the moment this configuration is only
 * used when the I2S audio interface, General Purpose Audio (GPA),
 * or AHB audio DMA (AHBAUDDMA) interface is active
 * (for S/PDIF interface this information comes from the stream).
 */
void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi,
				u8 *channel_status)
{}
EXPORT_SYMBOL_GPL();

static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
	unsigned long pixel_clk, unsigned int sample_rate)
{}

static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
{}

static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{}

void dw_hdmi_set_sample_width(struct dw_hdmi *hdmi, unsigned int width)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_set_sample_non_pcm(struct dw_hdmi *hdmi, unsigned int non_pcm)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca)
{}
EXPORT_SYMBOL_GPL();

static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable)
{}

static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_ahb_audio_disable(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_i2s_audio_enable(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_i2s_audio_disable(struct dw_hdmi *hdmi)
{}

void dw_hdmi_audio_enable(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_audio_disable(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
{}

static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
{}

static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
{}

static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
{}

static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
{}

/*
 * this submodule is responsible for the video data synchronization.
 * for example, for RGB 4:4:4 input, the data map is defined as
 *			pin{47~40} <==> R[7:0]
 *			pin{31~24} <==> G[7:0]
 *			pin{15~8}  <==> B[7:0]
 */
static void hdmi_video_sample(struct dw_hdmi *hdmi)
{}

static int is_color_space_conversion(struct dw_hdmi *hdmi)
{}

static int is_color_space_decimation(struct dw_hdmi *hdmi)
{}

static int is_color_space_interpolation(struct dw_hdmi *hdmi)
{}

static bool is_csc_needed(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
{}

static void hdmi_video_csc(struct dw_hdmi *hdmi)
{}

/*
 * HDMI video packetizer is used to packetize the data.
 * for example, if input is YCC422 mode or repeater is used,
 * data should be repacked this module can be bypassed.
 */
static void hdmi_video_packetize(struct dw_hdmi *hdmi)
{}

/* -----------------------------------------------------------------------------
 * Synopsys PHY Handling
 */

static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
				       unsigned char bit)
{}

static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{}

void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
			   unsigned char addr)
{}
EXPORT_SYMBOL_GPL();

/* Filter out invalid setups to avoid configuring SCDC and scrambling */
static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi,
				 const struct drm_display_info *display)
{}

/*
 * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
 * - The Source shall suspend transmission of the TMDS clock and data
 * - The Source shall write to the TMDS_Bit_Clock_Ratio bit to change it
 * from a 0 to a 1 or from a 1 to a 0
 * - The Source shall allow a minimum of 1 ms and a maximum of 100 ms from
 * the time the TMDS_Bit_Clock_Ratio bit is written until resuming
 * transmission of TMDS clock and data
 *
 * To respect the 100ms maximum delay, the dw_hdmi_set_high_tmds_clock_ratio()
 * helper should called right before enabling the TMDS Clock and Data in
 * the PHY configuration callback.
 */
void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi,
				       const struct drm_display_info *display)
{}
EXPORT_SYMBOL_GPL();

static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{}

static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
{}

static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
{}

void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
{}
EXPORT_SYMBOL_GPL();

static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
{}

static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
{}

void dw_hdmi_phy_gen1_reset(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_phy_gen2_reset(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address)
{}
EXPORT_SYMBOL_GPL();

static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
{}

static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
{}

/*
 * PHY configuration function for the DWC HDMI 3D TX PHY. Based on the available
 * information the DWC MHL PHY has the same register layout and is thus also
 * supported by this function.
 */
static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
		const struct dw_hdmi_plat_data *pdata,
		unsigned long mpixelclock)
{}

static int hdmi_phy_configure(struct dw_hdmi *hdmi,
			      const struct drm_display_info *display)
{}

static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
			    const struct drm_display_info *display,
			    const struct drm_display_mode *mode)
{}

static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
{}

enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
					       void *data)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
			    bool force, bool disabled, bool rxsense)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
{}
EXPORT_SYMBOL_GPL();

static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops =;

/* -----------------------------------------------------------------------------
 * HDMI TX Setup
 */

static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{}

static void hdmi_config_AVI(struct dw_hdmi *hdmi,
			    const struct drm_connector *connector,
			    const struct drm_display_mode *mode)
{}

static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
						  const struct drm_connector *connector,
						  const struct drm_display_mode *mode)
{}

static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi,
				      const struct drm_connector *connector)
{}

static void hdmi_av_composer(struct dw_hdmi *hdmi,
			     const struct drm_display_info *display,
			     const struct drm_display_mode *mode)
{}

/* HDMI Initialization Step B.4 */
static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{}

/* Workaround to clear the overflow condition */
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{}

static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
{}

static int dw_hdmi_setup(struct dw_hdmi *hdmi,
			 const struct drm_connector *connector,
			 const struct drm_display_mode *mode)
{}

static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_update_power(struct dw_hdmi *hdmi)
{}

/*
 * Adjust the detection of RXSENSE according to whether we have a forced
 * connection mode enabled, or whether we have been disabled.  There is
 * no point processing RXSENSE interrupts if we have a forced connection
 * state, or DRM has us disabled.
 *
 * We also disable rxsense interrupts when we think we're disconnected
 * to avoid floating TDMS signals giving false rxsense interrupts.
 *
 * Note: we still need to listen for HPD interrupts even when DRM has us
 * disabled so that we can detect a connect event.
 */
static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
{}

static enum drm_connector_status dw_hdmi_detect(struct dw_hdmi *hdmi)
{}

static const struct drm_edid *dw_hdmi_edid_read(struct dw_hdmi *hdmi,
						struct drm_connector *connector)
{}

/* -----------------------------------------------------------------------------
 * DRM Connector Operations
 */

static enum drm_connector_status
dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
{}

static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{}

static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
					  struct drm_atomic_state *state)
{}

static void dw_hdmi_connector_force(struct drm_connector *connector)
{}

static const struct drm_connector_funcs dw_hdmi_connector_funcs =;

static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =;

static int dw_hdmi_connector_create(struct dw_hdmi *hdmi)
{}

/* -----------------------------------------------------------------------------
 * DRM Bridge Operations
 */

/*
 * Possible output formats :
 * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
 * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
 * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
 * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
 * - MEDIA_BUS_FMT_YUV16_1X48,
 * - MEDIA_BUS_FMT_RGB161616_1X48,
 * - MEDIA_BUS_FMT_UYVY12_1X24,
 * - MEDIA_BUS_FMT_YUV12_1X36,
 * - MEDIA_BUS_FMT_RGB121212_1X36,
 * - MEDIA_BUS_FMT_UYVY10_1X20,
 * - MEDIA_BUS_FMT_YUV10_1X30,
 * - MEDIA_BUS_FMT_RGB101010_1X30,
 * - MEDIA_BUS_FMT_UYVY8_1X16,
 * - MEDIA_BUS_FMT_YUV8_1X24,
 * - MEDIA_BUS_FMT_RGB888_1X24,
 */

/* Can return a maximum of 11 possible output formats for a mode/connector */
#define MAX_OUTPUT_SEL_FORMATS

static u32 *dw_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)
{}

/*
 * Possible input formats :
 * - MEDIA_BUS_FMT_RGB888_1X24
 * - MEDIA_BUS_FMT_YUV8_1X24
 * - MEDIA_BUS_FMT_UYVY8_1X16
 * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
 * - MEDIA_BUS_FMT_RGB101010_1X30
 * - MEDIA_BUS_FMT_YUV10_1X30
 * - MEDIA_BUS_FMT_UYVY10_1X20
 * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
 * - MEDIA_BUS_FMT_RGB121212_1X36
 * - MEDIA_BUS_FMT_YUV12_1X36
 * - MEDIA_BUS_FMT_UYVY12_1X24
 * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
 * - MEDIA_BUS_FMT_RGB161616_1X48
 * - MEDIA_BUS_FMT_YUV16_1X48
 * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
 */

/* Can return a maximum of 3 possible input formats for an output format */
#define MAX_INPUT_SEL_FORMATS

static u32 *dw_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)
{}

static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
				       struct drm_bridge_state *bridge_state,
				       struct drm_crtc_state *crtc_state,
				       struct drm_connector_state *conn_state)
{}

static int dw_hdmi_bridge_attach(struct drm_bridge *bridge,
				 enum drm_bridge_attach_flags flags)
{}

static void dw_hdmi_bridge_detach(struct drm_bridge *bridge)
{}

static enum drm_mode_status
dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
			  const struct drm_display_info *info,
			  const struct drm_display_mode *mode)
{}

static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
				    const struct drm_display_mode *orig_mode,
				    const struct drm_display_mode *mode)
{}

static void dw_hdmi_bridge_atomic_disable(struct drm_bridge *bridge,
					  struct drm_bridge_state *old_state)
{}

static void dw_hdmi_bridge_atomic_enable(struct drm_bridge *bridge,
					 struct drm_bridge_state *old_state)
{}

static enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge)
{}

static const struct drm_edid *dw_hdmi_bridge_edid_read(struct drm_bridge *bridge,
						       struct drm_connector *connector)
{}

static const struct drm_bridge_funcs dw_hdmi_bridge_funcs =;

/* -----------------------------------------------------------------------------
 * IRQ Handling
 */

static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi)
{}

static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{}

void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
{}
EXPORT_SYMBOL_GPL();

static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{}

static const struct dw_hdmi_phy_data dw_hdmi_phys[] =;

static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_cec_enable(struct dw_hdmi *hdmi)
{}

static void dw_hdmi_cec_disable(struct dw_hdmi *hdmi)
{}

static const struct dw_hdmi_cec_ops dw_hdmi_cec_ops =;

static const struct regmap_config hdmi_regmap_8bit_config =;

static const struct regmap_config hdmi_regmap_32bit_config =;

static void dw_hdmi_init_hw(struct dw_hdmi *hdmi)
{}

/* -----------------------------------------------------------------------------
 * Probe/remove API, used from platforms based on the DRM bridge API.
 */

static int dw_hdmi_parse_dt(struct dw_hdmi *hdmi)
{}

bool dw_hdmi_bus_fmt_is_420(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
			      const struct dw_hdmi_plat_data *plat_data)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_remove(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

/* -----------------------------------------------------------------------------
 * Bind/unbind API, used from platforms based on the component framework.
 */
struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
			     struct drm_encoder *encoder,
			     const struct dw_hdmi_plat_data *plat_data)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_unbind(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

void dw_hdmi_resume(struct dw_hdmi *hdmi)
{}
EXPORT_SYMBOL_GPL();

MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_ALIAS();