summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-01-30 19:04:01 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2020-01-30 19:04:01 +0300
commit9f68e3655aae6d49d6ba05dd263f99f33c2567af (patch)
tree42c2c4579c4acbbb456695326af4f4ad8f402813 /drivers/gpu/drm/bridge
parent4cadc60d6bcfee9c626d4b55e9dc1475d21ad3bb (diff)
parentd47c7f06268082bc0082a15297a07c0da59b0fc4 (diff)
downloadlinux-9f68e3655aae6d49d6ba05dd263f99f33c2567af.tar.xz
Merge tag 'drm-next-2020-01-30' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Davbe Airlie: "This is the main pull request for graphics for 5.6. Usual selection of changes all over. I've got one outstanding vmwgfx pull that touches mm so kept it separate until after all of this lands. I'll try and get it to you soon after this, but it might be early next week (nothing wrong with code, just my schedule is messy) This also hits a lot of fbdev drivers with some cleanups. Other notables: - vulkan timeline semaphore support added to syncobjs - nouveau turing secureboot/graphics support - Displayport MST display stream compression support Detailed summary: uapi: - dma-buf heaps added (and fixed) - command line add support for panel oreientation - command line allow overriding penguin count drm: - mipi dsi definition updates - lockdep annotations for dma_resv - remove dma-buf kmap/kunmap support - constify fb_ops in all fbdev drivers - MST fix for daisy chained hotplug- - CTA-861-G modes with VIC >= 193 added - fix drm_panel_of_backlight export - LVDS decoder support - more device based logging support - scanline alighment for dumb buffers - MST DSC helpers scheduler: - documentation fixes - job distribution improvements panel: - Logic PD type 28 panel support - Jimax8729d MIPI-DSI - igenic JZ4770 - generic DSI devicetree bindings - sony acx424AKP panel - Leadtek LTK500HD1829 - xinpeng XPP055C272 - AUO B116XAK01 - GiantPlus GPM940B0 - BOE NV140FHM-N49 - Satoz SAT050AT40H12R2 - Sharp LS020B1DD01D panels. ttm: - use blocking WW lock i915: - hw/uapi state separation - Lock annotation improvements - selftest improvements - ICL/TGL DSI VDSC support - VBT parsing improvments - Display refactoring - DSI updates + fixes - HDCP 2.2 for CFL - CML PCI ID fixes - GLK+ fbc fix - PSR fixes - GEN/GT refactor improvments - DP MST fixes - switch context id alloc to xarray - workaround updates - LMEM debugfs support - tiled monitor fixes - ICL+ clock gating programming removed - DP MST disable sequence fixed - LMEM discontiguous object maps - prefaulting for discontiguous objects - use LMEM for dumb buffers if possible - add LMEM mmap support amdgpu: - enable sync object timelines for vulkan - MST atomic routines - enable MST DSC support - add DMCUB display microengine support - DC OEM i2c support - Renoir DC fixes - Initial HDCP 2.x support - BACO support for Arcturus - Use BACO for runtime PM power save - gfxoff on navi10 - gfx10 golden updates and fixes - DCN support on POWER - GFXOFF for raven1 refresh - MM engine idle handlers cleanup - 10bpc EDP panel fixes - renoir watermark fixes - SR-IOV fixes - Arcturus VCN fixes - GDDR6 training fixes - freesync fixes - Pollock support amdkfd: - unify more codepath with amdgpu - use KIQ to setup HIQ rather than MMIO radeon: - fix vma fault handler race - PPC DMA fix - register check fixes for r100/r200 nouveau: - mmap_sem vs dma_resv fix - rewrite the ACR secure boot code for Turing - TU10x graphics engine support (TU11x pending) - Page kind mapping for turing - 10-bit LUT support - GP10B Tegra fixes - HD audio regression fix hisilicon/hibmc: - use generic fbdev code and helpers rockchip: - dsi/px30 support virtio: - fb damage support - static some functions vc4: - use dma_resv lock wrappers msm: - use dma_resv lock wrappers - sc7180 display + DSI support - a618 support - UBWC support improvements vmwgfx: - updates + new logging uapi exynos: - enable/disable callback cleanups etnaviv: - use dma_resv lock wrappers atmel-hlcdc: - clock fixes mediatek: - cmdq support - non-smooth cursor fixes - ctm property support sun4i: - suspend support - A64 mipi dsi support rcar-du: - Color management module support - LVDS encoder dual-link support - R8A77980 support analogic: - add support for an6345 ast: - atomic modeset support - primary plane garbage fix arcgpu: - fixes for fourcc handling tegra: - minor fixes and improvments mcde: - vblank support meson: - OSD1 plane AFBC commit gma500: - add pageflip support - reomve global drm_dev komeda: - tweak debugfs output - d32 support - runtime PM suppotr udl: - use generic shmem helpers - cleanup and fixes" * tag 'drm-next-2020-01-30' of git://anongit.freedesktop.org/drm/drm: (1998 commits) drm/nouveau/fb/gp102-: allow module to load even when scrubber binary is missing drm/nouveau/acr: return error when registering LSF if ACR not supported drm/nouveau/disp/gv100-: not all channel types support reporting error codes drm/nouveau/disp/nv50-: prevent oops when no channel method map provided drm/nouveau: support synchronous pushbuf submission drm/nouveau: signal pending fences when channel has been killed drm/nouveau: reject attempts to submit to dead channels drm/nouveau: zero vma pointer even if we only unreference it rather than free drm/nouveau: Add HD-audio component notifier support drm/nouveau: fix build error without CONFIG_IOMMU_API drm/nouveau/kms/nv04: remove set but not used variable 'width' drm/nouveau/kms/nv50: remove set but not unused variable 'nv_connector' drm/nouveau/mmu: fix comptag memory leak drm/nouveau/gr/gp10b: Use gp100_grctx and gp100_gr_zbc drm/nouveau/pmu/gm20b,gp10b: Fix Falcon bootstrapping drm/exynos: Rename Exynos to lowercase drm/exynos: change callback names drm/mst: Don't do atomic checks over disabled managers drm/amdgpu: add the lost mutex_init back drm/amd/display: skip opp blank or unblank if test pattern enabled ...
Diffstat (limited to 'drivers/gpu/drm/bridge')
-rw-r--r--drivers/gpu/drm/bridge/Kconfig26
-rw-r--r--drivers/gpu/drm/bridge/Makefile6
-rw-r--r--drivers/gpu/drm/bridge/analogix-anx78xx.h703
-rw-r--r--drivers/gpu/drm/bridge/analogix/Kconfig23
-rw-r--r--drivers/gpu/drm/bridge/analogix/Makefile4
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx6345.c817
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c (renamed from drivers/gpu/drm/bridge/analogix-anx78xx.c)146
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx78xx.h249
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c165
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h256
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-i2c-txcommon.h234
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c2
-rw-r--r--drivers/gpu/drm/bridge/cdns-dsi.c6
-rw-r--r--drivers/gpu/drm/bridge/lvds-codec.c151
-rw-r--r--drivers/gpu/drm/bridge/lvds-encoder.c155
-rw-r--r--drivers/gpu/drm/bridge/panel.c20
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8622.c2
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c2
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c40
-rw-r--r--drivers/gpu/drm/bridge/tc358764.c2
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c2
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c2
22 files changed, 1963 insertions, 1050 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 34362976cd6f..0b9ca5862455 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -16,16 +16,6 @@ config DRM_PANEL_BRIDGE
menu "Display Interface Bridges"
depends on DRM && DRM_BRIDGE
-config DRM_ANALOGIX_ANX78XX
- tristate "Analogix ANX78XX bridge"
- select DRM_KMS_HELPER
- select REGMAP_I2C
- ---help---
- ANX78XX is an ultra-low power Full-HD SlimPort transmitter
- designed for portable devices. The ANX78XX transforms
- the HDMI output of an application processor to MyDP
- or DisplayPort.
-
config DRM_CDNS_DSI
tristate "Cadence DPI/DSI bridge"
select DRM_KMS_HELPER
@@ -45,14 +35,14 @@ config DRM_DUMB_VGA_DAC
Support for non-programmable RGB to VGA DAC bridges, such as ADI
ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs.
-config DRM_LVDS_ENCODER
- tristate "Transparent parallel to LVDS encoder support"
+config DRM_LVDS_CODEC
+ tristate "Transparent LVDS encoders and decoders support"
depends on OF
select DRM_KMS_HELPER
select DRM_PANEL_BRIDGE
help
- Support for transparent parallel to LVDS encoders that don't require
- any configuration.
+ Support for transparent LVDS encoders and decoders that don't
+ require any configuration.
config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw"
@@ -60,10 +50,10 @@ config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
select DRM_KMS_HELPER
select DRM_PANEL
---help---
- This is a driver for the display bridges of
- GE B850v3 that convert dual channel LVDS
- to DP++. This is used with the i.MX6 imx-ldb
- driver. You are likely to say N here.
+ This is a driver for the display bridges of
+ GE B850v3 that convert dual channel LVDS
+ to DP++. This is used with the i.MX6 imx-ldb
+ driver. You are likely to say N here.
config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge"
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 4934fcf5a6f8..cd16ce830270 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,8 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
-obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
+obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
@@ -12,8 +11,9 @@ obj-$(CONFIG_DRM_SII9234) += sii9234.o
obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o
obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
-obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
+
+obj-y += analogix/
obj-y += synopsys/
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.h b/drivers/gpu/drm/bridge/analogix-anx78xx.h
deleted file mode 100644
index 55d6c2109740..000000000000
--- a/drivers/gpu/drm/bridge/analogix-anx78xx.h
+++ /dev/null
@@ -1,703 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright(c) 2016, Analogix Semiconductor. All rights reserved.
- */
-
-#ifndef __ANX78xx_H
-#define __ANX78xx_H
-
-/***************************************************************/
-/* Register definitions for RX_PO */
-/***************************************************************/
-
-/*
- * System Control and Status
- */
-
-/* Software Reset Register 1 */
-#define SP_SOFTWARE_RESET1_REG 0x11
-#define SP_VIDEO_RST BIT(4)
-#define SP_HDCP_MAN_RST BIT(2)
-#define SP_TMDS_RST BIT(1)
-#define SP_SW_MAN_RST BIT(0)
-
-/* System Status Register */
-#define SP_SYSTEM_STATUS_REG 0x14
-#define SP_TMDS_CLOCK_DET BIT(1)
-#define SP_TMDS_DE_DET BIT(0)
-
-/* HDMI Status Register */
-#define SP_HDMI_STATUS_REG 0x15
-#define SP_HDMI_AUD_LAYOUT BIT(3)
-#define SP_HDMI_DET BIT(0)
-# define SP_DVI_MODE 0
-# define SP_HDMI_MODE 1
-
-/* HDMI Mute Control Register */
-#define SP_HDMI_MUTE_CTRL_REG 0x16
-#define SP_AUD_MUTE BIT(1)
-#define SP_VID_MUTE BIT(0)
-
-/* System Power Down Register 1 */
-#define SP_SYSTEM_POWER_DOWN1_REG 0x18
-#define SP_PWDN_CTRL BIT(0)
-
-/*
- * Audio and Video Auto Control
- */
-
-/* Auto Audio and Video Control register */
-#define SP_AUDVID_CTRL_REG 0x20
-#define SP_AVC_OE BIT(7)
-#define SP_AAC_OE BIT(6)
-#define SP_AVC_EN BIT(1)
-#define SP_AAC_EN BIT(0)
-
-/* Audio Exception Enable Registers */
-#define SP_AUD_EXCEPTION_ENABLE_BASE (0x24 - 1)
-/* Bits for Audio Exception Enable Register 3 */
-#define SP_AEC_EN21 BIT(5)
-
-/*
- * Interrupt
- */
-
-/* Interrupt Status Register 1 */
-#define SP_INT_STATUS1_REG 0x31
-/* Bits for Interrupt Status Register 1 */
-#define SP_HDMI_DVI BIT(7)
-#define SP_CKDT_CHG BIT(6)
-#define SP_SCDT_CHG BIT(5)
-#define SP_PCLK_CHG BIT(4)
-#define SP_PLL_UNLOCK BIT(3)
-#define SP_CABLE_PLUG_CHG BIT(2)
-#define SP_SET_MUTE BIT(1)
-#define SP_SW_INTR BIT(0)
-/* Bits for Interrupt Status Register 2 */
-#define SP_HDCP_ERR BIT(5)
-#define SP_AUDIO_SAMPLE_CHG BIT(0) /* undocumented */
-/* Bits for Interrupt Status Register 3 */
-#define SP_AUD_MODE_CHG BIT(0)
-/* Bits for Interrupt Status Register 5 */
-#define SP_AUDIO_RCV BIT(0)
-/* Bits for Interrupt Status Register 6 */
-#define SP_INT_STATUS6_REG 0x36
-#define SP_CTS_RCV BIT(7)
-#define SP_NEW_AUD_PKT BIT(4)
-#define SP_NEW_AVI_PKT BIT(1)
-#define SP_NEW_CP_PKT BIT(0)
-/* Bits for Interrupt Status Register 7 */
-#define SP_NO_VSI BIT(7)
-#define SP_NEW_VS BIT(4)
-
-/* Interrupt Mask 1 Status Registers */
-#define SP_INT_MASK1_REG 0x41
-
-/* HDMI US TIMER Control Register */
-#define SP_HDMI_US_TIMER_CTRL_REG 0x49
-#define SP_MS_TIMER_MARGIN_10_8_MASK 0x07
-
-/*
- * TMDS Control
- */
-
-/* TMDS Control Registers */
-#define SP_TMDS_CTRL_BASE (0x50 - 1)
-/* Bits for TMDS Control Register 7 */
-#define SP_PD_RT BIT(0)
-
-/*
- * Video Control
- */
-
-/* Video Status Register */
-#define SP_VIDEO_STATUS_REG 0x70
-#define SP_COLOR_DEPTH_MASK 0xf0
-#define SP_COLOR_DEPTH_SHIFT 4
-# define SP_COLOR_DEPTH_MODE_LEGACY 0x00
-# define SP_COLOR_DEPTH_MODE_24BIT 0x04
-# define SP_COLOR_DEPTH_MODE_30BIT 0x05
-# define SP_COLOR_DEPTH_MODE_36BIT 0x06
-# define SP_COLOR_DEPTH_MODE_48BIT 0x07
-
-/* Video Data Range Control Register */
-#define SP_VID_DATA_RANGE_CTRL_REG 0x83
-#define SP_R2Y_INPUT_LIMIT BIT(1)
-
-/* Pixel Clock High Resolution Counter Registers */
-#define SP_PCLK_HIGHRES_CNT_BASE (0x8c - 1)
-
-/*
- * Audio Control
- */
-
-/* Number of Audio Channels Status Registers */
-#define SP_AUD_CH_STATUS_REG_NUM 6
-
-/* Audio IN S/PDIF Channel Status Registers */
-#define SP_AUD_SPDIF_CH_STATUS_BASE 0xc7
-
-/* Audio IN S/PDIF Channel Status Register 4 */
-#define SP_FS_FREQ_MASK 0x0f
-# define SP_FS_FREQ_44100HZ 0x00
-# define SP_FS_FREQ_48000HZ 0x02
-# define SP_FS_FREQ_32000HZ 0x03
-# define SP_FS_FREQ_88200HZ 0x08
-# define SP_FS_FREQ_96000HZ 0x0a
-# define SP_FS_FREQ_176400HZ 0x0c
-# define SP_FS_FREQ_192000HZ 0x0e
-
-/*
- * Micellaneous Control Block
- */
-
-/* CHIP Control Register */
-#define SP_CHIP_CTRL_REG 0xe3
-#define SP_MAN_HDMI5V_DET BIT(3)
-#define SP_PLLLOCK_CKDT_EN BIT(2)
-#define SP_ANALOG_CKDT_EN BIT(1)
-#define SP_DIGITAL_CKDT_EN BIT(0)
-
-/* Packet Receiving Status Register */
-#define SP_PACKET_RECEIVING_STATUS_REG 0xf3
-#define SP_AVI_RCVD BIT(5)
-#define SP_VSI_RCVD BIT(1)
-
-/***************************************************************/
-/* Register definitions for RX_P1 */
-/***************************************************************/
-
-/* HDCP BCAPS Shadow Register */
-#define SP_HDCP_BCAPS_SHADOW_REG 0x2a
-#define SP_BCAPS_REPEATER BIT(5)
-
-/* HDCP Status Register */
-#define SP_RX_HDCP_STATUS_REG 0x3f
-#define SP_AUTH_EN BIT(4)
-
-/*
- * InfoFrame and Control Packet Registers
- */
-
-/* AVI InfoFrame packet checksum */
-#define SP_AVI_INFOFRAME_CHECKSUM 0xa3
-
-/* AVI InfoFrame Registers */
-#define SP_AVI_INFOFRAME_DATA_BASE 0xa4
-
-#define SP_AVI_COLOR_F_MASK 0x60
-#define SP_AVI_COLOR_F_SHIFT 5
-
-/* Audio InfoFrame Registers */
-#define SP_AUD_INFOFRAME_DATA_BASE 0xc4
-#define SP_AUD_INFOFRAME_LAYOUT_MASK 0x0f
-
-/* MPEG/HDMI Vendor Specific InfoFrame Packet type code */
-#define SP_MPEG_VS_INFOFRAME_TYPE_REG 0xe0
-
-/* MPEG/HDMI Vendor Specific InfoFrame Packet length */
-#define SP_MPEG_VS_INFOFRAME_LEN_REG 0xe2
-
-/* MPEG/HDMI Vendor Specific InfoFrame Packet version number */
-#define SP_MPEG_VS_INFOFRAME_VER_REG 0xe1
-
-/* MPEG/HDMI Vendor Specific InfoFrame Packet content */
-#define SP_MPEG_VS_INFOFRAME_DATA_BASE 0xe4
-
-/* General Control Packet Register */
-#define SP_GENERAL_CTRL_PACKET_REG 0x9f
-#define SP_CLEAR_AVMUTE BIT(4)
-#define SP_SET_AVMUTE BIT(0)
-
-/***************************************************************/
-/* Register definitions for TX_P0 */
-/***************************************************************/
-
-/* HDCP Status Register */
-#define SP_TX_HDCP_STATUS_REG 0x00
-#define SP_AUTH_FAIL BIT(5)
-#define SP_AUTHEN_PASS BIT(1)
-
-/* HDCP Control Register 0 */
-#define SP_HDCP_CTRL0_REG 0x01
-#define SP_RX_REPEATER BIT(6)
-#define SP_RE_AUTH BIT(5)
-#define SP_SW_AUTH_OK BIT(4)
-#define SP_HARD_AUTH_EN BIT(3)
-#define SP_HDCP_ENC_EN BIT(2)
-#define SP_BKSV_SRM_PASS BIT(1)
-#define SP_KSVLIST_VLD BIT(0)
-/* HDCP Function Enabled */
-#define SP_HDCP_FUNCTION_ENABLED (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-
-/* HDCP Receiver BSTATUS Register 0 */
-#define SP_HDCP_RX_BSTATUS0_REG 0x1b
-/* HDCP Receiver BSTATUS Register 1 */
-#define SP_HDCP_RX_BSTATUS1_REG 0x1c
-
-/* HDCP Embedded "Blue Screen" Content Registers */
-#define SP_HDCP_VID0_BLUE_SCREEN_REG 0x2c
-#define SP_HDCP_VID1_BLUE_SCREEN_REG 0x2d
-#define SP_HDCP_VID2_BLUE_SCREEN_REG 0x2e
-
-/* HDCP Wait R0 Timing Register */
-#define SP_HDCP_WAIT_R0_TIME_REG 0x40
-
-/* HDCP Link Integrity Check Timer Register */
-#define SP_HDCP_LINK_CHECK_TIMER_REG 0x41
-
-/* HDCP Repeater Ready Wait Timer Register */
-#define SP_HDCP_RPTR_RDY_WAIT_TIME_REG 0x42
-
-/* HDCP Auto Timer Register */
-#define SP_HDCP_AUTO_TIMER_REG 0x51
-
-/* HDCP Key Status Register */
-#define SP_HDCP_KEY_STATUS_REG 0x5e
-
-/* HDCP Key Command Register */
-#define SP_HDCP_KEY_COMMAND_REG 0x5f
-#define SP_DISABLE_SYNC_HDCP BIT(2)
-
-/* OTP Memory Key Protection Registers */
-#define SP_OTP_KEY_PROTECT1_REG 0x60
-#define SP_OTP_KEY_PROTECT2_REG 0x61
-#define SP_OTP_KEY_PROTECT3_REG 0x62
-#define SP_OTP_PSW1 0xa2
-#define SP_OTP_PSW2 0x7e
-#define SP_OTP_PSW3 0xc6
-
-/* DP System Control Registers */
-#define SP_DP_SYSTEM_CTRL_BASE (0x80 - 1)
-/* Bits for DP System Control Register 2 */
-#define SP_CHA_STA BIT(2)
-/* Bits for DP System Control Register 3 */
-#define SP_HPD_STATUS BIT(6)
-#define SP_STRM_VALID BIT(2)
-/* Bits for DP System Control Register 4 */
-#define SP_ENHANCED_MODE BIT(3)
-
-/* DP Video Control Register */
-#define SP_DP_VIDEO_CTRL_REG 0x84
-#define SP_COLOR_F_MASK 0x06
-#define SP_COLOR_F_SHIFT 1
-#define SP_BPC_MASK 0xe0
-#define SP_BPC_SHIFT 5
-# define SP_BPC_6BITS 0x00
-# define SP_BPC_8BITS 0x01
-# define SP_BPC_10BITS 0x02
-# define SP_BPC_12BITS 0x03
-
-/* DP Audio Control Register */
-#define SP_DP_AUDIO_CTRL_REG 0x87
-#define SP_AUD_EN BIT(0)
-
-/* 10us Pulse Generate Timer Registers */
-#define SP_I2C_GEN_10US_TIMER0_REG 0x88
-#define SP_I2C_GEN_10US_TIMER1_REG 0x89
-
-/* Packet Send Control Register */
-#define SP_PACKET_SEND_CTRL_REG 0x90
-#define SP_AUD_IF_UP BIT(7)
-#define SP_AVI_IF_UD BIT(6)
-#define SP_MPEG_IF_UD BIT(5)
-#define SP_SPD_IF_UD BIT(4)
-#define SP_AUD_IF_EN BIT(3)
-#define SP_AVI_IF_EN BIT(2)
-#define SP_MPEG_IF_EN BIT(1)
-#define SP_SPD_IF_EN BIT(0)
-
-/* DP HDCP Control Register */
-#define SP_DP_HDCP_CTRL_REG 0x92
-#define SP_AUTO_EN BIT(7)
-#define SP_AUTO_START BIT(5)
-#define SP_LINK_POLLING BIT(1)
-
-/* DP Main Link Bandwidth Setting Register */
-#define SP_DP_MAIN_LINK_BW_SET_REG 0xa0
-#define SP_LINK_BW_SET_MASK 0x1f
-#define SP_INITIAL_SLIM_M_AUD_SEL BIT(5)
-
-/* DP Training Pattern Set Register */
-#define SP_DP_TRAINING_PATTERN_SET_REG 0xa2
-
-/* DP Lane 0 Link Training Control Register */
-#define SP_DP_LANE0_LT_CTRL_REG 0xa3
-#define SP_TX_SW_SET_MASK 0x1b
-#define SP_MAX_PRE_REACH BIT(5)
-#define SP_MAX_DRIVE_REACH BIT(4)
-#define SP_PRE_EMP_LEVEL1 BIT(3)
-#define SP_DRVIE_CURRENT_LEVEL1 BIT(0)
-
-/* DP Link Training Control Register */
-#define SP_DP_LT_CTRL_REG 0xa8
-#define SP_LT_ERROR_TYPE_MASK 0x70
-# define SP_LT_NO_ERROR 0x00
-# define SP_LT_AUX_WRITE_ERROR 0x01
-# define SP_LT_MAX_DRIVE_REACHED 0x02
-# define SP_LT_WRONG_LANE_COUNT_SET 0x03
-# define SP_LT_LOOP_SAME_5_TIME 0x04
-# define SP_LT_CR_FAIL_IN_EQ 0x05
-# define SP_LT_EQ_LOOP_5_TIME 0x06
-#define SP_LT_EN BIT(0)
-
-/* DP CEP Training Control Registers */
-#define SP_DP_CEP_TRAINING_CTRL0_REG 0xa9
-#define SP_DP_CEP_TRAINING_CTRL1_REG 0xaa
-
-/* DP Debug Register 1 */
-#define SP_DP_DEBUG1_REG 0xb0
-#define SP_DEBUG_PLL_LOCK BIT(4)
-#define SP_POLLING_EN BIT(1)
-
-/* DP Polling Control Register */
-#define SP_DP_POLLING_CTRL_REG 0xb4
-#define SP_AUTO_POLLING_DISABLE BIT(0)
-
-/* DP Link Debug Control Register */
-#define SP_DP_LINK_DEBUG_CTRL_REG 0xb8
-#define SP_M_VID_DEBUG BIT(5)
-#define SP_NEW_PRBS7 BIT(4)
-#define SP_INSERT_ER BIT(1)
-#define SP_PRBS31_EN BIT(0)
-
-/* AUX Misc control Register */
-#define SP_AUX_MISC_CTRL_REG 0xbf
-
-/* DP PLL control Register */
-#define SP_DP_PLL_CTRL_REG 0xc7
-#define SP_PLL_RST BIT(6)
-
-/* DP Analog Power Down Register */
-#define SP_DP_ANALOG_POWER_DOWN_REG 0xc8
-#define SP_CH0_PD BIT(0)
-
-/* DP Misc Control Register */
-#define SP_DP_MISC_CTRL_REG 0xcd
-#define SP_EQ_TRAINING_LOOP BIT(6)
-
-/* DP Extra I2C Device Address Register */
-#define SP_DP_EXTRA_I2C_DEV_ADDR_REG 0xce
-#define SP_I2C_STRETCH_DISABLE BIT(7)
-
-#define SP_I2C_EXTRA_ADDR 0x50
-
-/* DP Downspread Control Register 1 */
-#define SP_DP_DOWNSPREAD_CTRL1_REG 0xd0
-
-/* DP M Value Calculation Control Register */
-#define SP_DP_M_CALCULATION_CTRL_REG 0xd9
-#define SP_M_GEN_CLK_SEL BIT(0)
-
-/* AUX Channel Access Status Register */
-#define SP_AUX_CH_STATUS_REG 0xe0
-#define SP_AUX_STATUS 0x0f
-
-/* AUX Channel DEFER Control Register */
-#define SP_AUX_DEFER_CTRL_REG 0xe2
-#define SP_DEFER_CTRL_EN BIT(7)
-
-/* DP Buffer Data Count Register */
-#define SP_BUF_DATA_COUNT_REG 0xe4
-#define SP_BUF_DATA_COUNT_MASK 0x1f
-#define SP_BUF_CLR BIT(7)
-
-/* DP AUX Channel Control Register 1 */
-#define SP_DP_AUX_CH_CTRL1_REG 0xe5
-#define SP_AUX_TX_COMM_MASK 0x0f
-#define SP_AUX_LENGTH_MASK 0xf0
-#define SP_AUX_LENGTH_SHIFT 4
-
-/* DP AUX CH Address Register 0 */
-#define SP_AUX_ADDR_7_0_REG 0xe6
-
-/* DP AUX CH Address Register 1 */
-#define SP_AUX_ADDR_15_8_REG 0xe7
-
-/* DP AUX CH Address Register 2 */
-#define SP_AUX_ADDR_19_16_REG 0xe8
-#define SP_AUX_ADDR_19_16_MASK 0x0f
-
-/* DP AUX Channel Control Register 2 */
-#define SP_DP_AUX_CH_CTRL2_REG 0xe9
-#define SP_AUX_SEL_RXCM BIT(6)
-#define SP_AUX_CHSEL BIT(3)
-#define SP_AUX_PN_INV BIT(2)
-#define SP_ADDR_ONLY BIT(1)
-#define SP_AUX_EN BIT(0)
-
-/* DP Video Stream Control InfoFrame Register */
-#define SP_DP_3D_VSC_CTRL_REG 0xea
-#define SP_INFO_FRAME_VSC_EN BIT(0)
-
-/* DP Video Stream Data Byte 1 Register */
-#define SP_DP_VSC_DB1_REG 0xeb
-
-/* DP AUX Channel Control Register 3 */
-#define SP_DP_AUX_CH_CTRL3_REG 0xec
-#define SP_WAIT_COUNTER_7_0_MASK 0xff
-
-/* DP AUX Channel Control Register 4 */
-#define SP_DP_AUX_CH_CTRL4_REG 0xed
-
-/* DP AUX Buffer Data Registers */
-#define SP_DP_BUF_DATA0_REG 0xf0
-
-/***************************************************************/
-/* Register definitions for TX_P2 */
-/***************************************************************/
-
-/*
- * Core Register Definitions
- */
-
-/* Device ID Low Byte Register */
-#define SP_DEVICE_IDL_REG 0x02
-
-/* Device ID High Byte Register */
-#define SP_DEVICE_IDH_REG 0x03
-
-/* Device version register */
-#define SP_DEVICE_VERSION_REG 0x04
-
-/* Power Down Control Register */
-#define SP_POWERDOWN_CTRL_REG 0x05
-#define SP_REGISTER_PD BIT(7)
-#define SP_HDCP_PD BIT(5)
-#define SP_AUDIO_PD BIT(4)
-#define SP_VIDEO_PD BIT(3)
-#define SP_LINK_PD BIT(2)
-#define SP_TOTAL_PD BIT(1)
-
-/* Reset Control Register 1 */
-#define SP_RESET_CTRL1_REG 0x06
-#define SP_MISC_RST BIT(7)
-#define SP_VIDCAP_RST BIT(6)
-#define SP_VIDFIF_RST BIT(5)
-#define SP_AUDFIF_RST BIT(4)
-#define SP_AUDCAP_RST BIT(3)
-#define SP_HDCP_RST BIT(2)
-#define SP_SW_RST BIT(1)
-#define SP_HW_RST BIT(0)
-
-/* Reset Control Register 2 */
-#define SP_RESET_CTRL2_REG 0x07
-#define SP_AUX_RST BIT(2)
-#define SP_SERDES_FIFO_RST BIT(1)
-#define SP_I2C_REG_RST BIT(0)
-
-/* Video Control Register 1 */
-#define SP_VID_CTRL1_REG 0x08
-#define SP_VIDEO_EN BIT(7)
-#define SP_VIDEO_MUTE BIT(2)
-#define SP_DE_GEN BIT(1)
-#define SP_DEMUX BIT(0)
-
-/* Video Control Register 2 */
-#define SP_VID_CTRL2_REG 0x09
-#define SP_IN_COLOR_F_MASK 0x03
-#define SP_IN_YC_BIT_SEL BIT(2)
-#define SP_IN_BPC_MASK 0x70
-#define SP_IN_BPC_SHIFT 4
-# define SP_IN_BPC_12BIT 0x03
-# define SP_IN_BPC_10BIT 0x02
-# define SP_IN_BPC_8BIT 0x01
-# define SP_IN_BPC_6BIT 0x00
-#define SP_IN_D_RANGE BIT(7)
-
-/* Video Control Register 3 */
-#define SP_VID_CTRL3_REG 0x0a
-#define SP_HPD_OUT BIT(6)
-
-/* Video Control Register 5 */
-#define SP_VID_CTRL5_REG 0x0c
-#define SP_CSC_STD_SEL BIT(7)
-#define SP_XVYCC_RNG_LMT BIT(6)
-#define SP_RANGE_Y2R BIT(5)
-#define SP_CSPACE_Y2R BIT(4)
-#define SP_RGB_RNG_LMT BIT(3)
-#define SP_Y_RNG_LMT BIT(2)
-#define SP_RANGE_R2Y BIT(1)
-#define SP_CSPACE_R2Y BIT(0)
-
-/* Video Control Register 6 */
-#define SP_VID_CTRL6_REG 0x0d
-#define SP_TEST_PATTERN_EN BIT(7)
-#define SP_VIDEO_PROCESS_EN BIT(6)
-#define SP_VID_US_MODE BIT(3)
-#define SP_VID_DS_MODE BIT(2)
-#define SP_UP_SAMPLE BIT(1)
-#define SP_DOWN_SAMPLE BIT(0)
-
-/* Video Control Register 8 */
-#define SP_VID_CTRL8_REG 0x0f
-#define SP_VID_VRES_TH BIT(0)
-
-/* Total Line Status Low Byte Register */
-#define SP_TOTAL_LINE_STAL_REG 0x24
-
-/* Total Line Status High Byte Register */
-#define SP_TOTAL_LINE_STAH_REG 0x25
-
-/* Active Line Status Low Byte Register */
-#define SP_ACT_LINE_STAL_REG 0x26
-
-/* Active Line Status High Byte Register */
-#define SP_ACT_LINE_STAH_REG 0x27
-
-/* Vertical Front Porch Status Register */
-#define SP_V_F_PORCH_STA_REG 0x28
-
-/* Vertical SYNC Width Status Register */
-#define SP_V_SYNC_STA_REG 0x29
-
-/* Vertical Back Porch Status Register */
-#define SP_V_B_PORCH_STA_REG 0x2a
-
-/* Total Pixel Status Low Byte Register */
-#define SP_TOTAL_PIXEL_STAL_REG 0x2b
-
-/* Total Pixel Status High Byte Register */
-#define SP_TOTAL_PIXEL_STAH_REG 0x2c
-
-/* Active Pixel Status Low Byte Register */
-#define SP_ACT_PIXEL_STAL_REG 0x2d
-
-/* Active Pixel Status High Byte Register */
-#define SP_ACT_PIXEL_STAH_REG 0x2e
-
-/* Horizontal Front Porch Status Low Byte Register */
-#define SP_H_F_PORCH_STAL_REG 0x2f
-
-/* Horizontal Front Porch Statys High Byte Register */
-#define SP_H_F_PORCH_STAH_REG 0x30
-
-/* Horizontal SYNC Width Status Low Byte Register */
-#define SP_H_SYNC_STAL_REG 0x31
-
-/* Horizontal SYNC Width Status High Byte Register */
-#define SP_H_SYNC_STAH_REG 0x32
-
-/* Horizontal Back Porch Status Low Byte Register */
-#define SP_H_B_PORCH_STAL_REG 0x33
-
-/* Horizontal Back Porch Status High Byte Register */
-#define SP_H_B_PORCH_STAH_REG 0x34
-
-/* InfoFrame AVI Packet DB1 Register */
-#define SP_INFOFRAME_AVI_DB1_REG 0x70
-
-/* Bit Control Specific Register */
-#define SP_BIT_CTRL_SPECIFIC_REG 0x80
-#define SP_BIT_CTRL_SELECT_SHIFT 1
-#define SP_ENABLE_BIT_CTRL BIT(0)
-
-/* InfoFrame Audio Packet DB1 Register */
-#define SP_INFOFRAME_AUD_DB1_REG 0x83
-
-/* InfoFrame MPEG Packet DB1 Register */
-#define SP_INFOFRAME_MPEG_DB1_REG 0xb0
-
-/* Audio Channel Status Registers */
-#define SP_AUD_CH_STATUS_BASE 0xd0
-
-/* Audio Channel Num Register 5 */
-#define SP_I2S_CHANNEL_NUM_MASK 0xe0
-# define SP_I2S_CH_NUM_1 (0x00 << 5)
-# define SP_I2S_CH_NUM_2 (0x01 << 5)
-# define SP_I2S_CH_NUM_3 (0x02 << 5)
-# define SP_I2S_CH_NUM_4 (0x03 << 5)
-# define SP_I2S_CH_NUM_5 (0x04 << 5)
-# define SP_I2S_CH_NUM_6 (0x05 << 5)
-# define SP_I2S_CH_NUM_7 (0x06 << 5)
-# define SP_I2S_CH_NUM_8 (0x07 << 5)
-#define SP_EXT_VUCP BIT(2)
-#define SP_VBIT BIT(1)
-#define SP_AUDIO_LAYOUT BIT(0)
-
-/* Analog Debug Register 2 */
-#define SP_ANALOG_DEBUG2_REG 0xdd
-#define SP_FORCE_SW_OFF_BYPASS 0x20
-#define SP_XTAL_FRQ 0x1c
-# define SP_XTAL_FRQ_19M2 (0x00 << 2)
-# define SP_XTAL_FRQ_24M (0x01 << 2)
-# define SP_XTAL_FRQ_25M (0x02 << 2)
-# define SP_XTAL_FRQ_26M (0x03 << 2)
-# define SP_XTAL_FRQ_27M (0x04 << 2)
-# define SP_XTAL_FRQ_38M4 (0x05 << 2)
-# define SP_XTAL_FRQ_52M (0x06 << 2)
-#define SP_POWERON_TIME_1P5MS 0x03
-
-/* Analog Control 0 Register */
-#define SP_ANALOG_CTRL0_REG 0xe1
-
-/* Common Interrupt Status Register 1 */
-#define SP_COMMON_INT_STATUS_BASE (0xf1 - 1)
-#define SP_PLL_LOCK_CHG 0x40
-
-/* Common Interrupt Status Register 2 */
-#define SP_COMMON_INT_STATUS2 0xf2
-#define SP_HDCP_AUTH_CHG BIT(1)
-#define SP_HDCP_AUTH_DONE BIT(0)
-
-#define SP_HDCP_LINK_CHECK_FAIL BIT(0)
-
-/* Common Interrupt Status Register 4 */
-#define SP_COMMON_INT_STATUS4_REG 0xf4
-#define SP_HPD_IRQ BIT(6)
-#define SP_HPD_ESYNC_ERR BIT(4)
-#define SP_HPD_CHG BIT(2)
-#define SP_HPD_LOST BIT(1)
-#define SP_HPD_PLUG BIT(0)
-
-/* DP Interrupt Status Register */
-#define SP_DP_INT_STATUS1_REG 0xf7
-#define SP_TRAINING_FINISH BIT(5)
-#define SP_POLLING_ERR BIT(4)
-
-/* Common Interrupt Mask Register */
-#define SP_COMMON_INT_MASK_BASE (0xf8 - 1)
-
-#define SP_COMMON_INT_MASK4_REG 0xfb
-
-/* DP Interrupts Mask Register */
-#define SP_DP_INT_MASK1_REG 0xfe
-
-/* Interrupt Control Register */
-#define SP_INT_CTRL_REG 0xff
-
-/***************************************************************/
-/* Register definitions for TX_P1 */
-/***************************************************************/
-
-/* DP TX Link Training Control Register */
-#define SP_DP_TX_LT_CTRL0_REG 0x30
-
-/* PD 1.2 Lint Training 80bit Pattern Register */
-#define SP_DP_LT_80BIT_PATTERN0_REG 0x80
-#define SP_DP_LT_80BIT_PATTERN_REG_NUM 10
-
-/* Audio Interface Control Register 0 */
-#define SP_AUD_INTERFACE_CTRL0_REG 0x5f
-#define SP_AUD_INTERFACE_DISABLE 0x80
-
-/* Audio Interface Control Register 2 */
-#define SP_AUD_INTERFACE_CTRL2_REG 0x60
-#define SP_M_AUD_ADJUST_ST 0x04
-
-/* Audio Interface Control Register 3 */
-#define SP_AUD_INTERFACE_CTRL3_REG 0x62
-
-/* Audio Interface Control Register 4 */
-#define SP_AUD_INTERFACE_CTRL4_REG 0x67
-
-/* Audio Interface Control Register 5 */
-#define SP_AUD_INTERFACE_CTRL5_REG 0x68
-
-/* Audio Interface Control Register 6 */
-#define SP_AUD_INTERFACE_CTRL6_REG 0x69
-
-/* Firmware Version Register */
-#define SP_FW_VER_REG 0xb7
-
-#endif
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index e930ff9b5cd4..e1fa7d820373 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -1,4 +1,27 @@
# SPDX-License-Identifier: GPL-2.0-only
+config DRM_ANALOGIX_ANX6345
+ tristate "Analogix ANX6345 bridge"
+ depends on OF
+ select DRM_ANALOGIX_DP
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ help
+ ANX6345 is an ultra-low Full-HD DisplayPort/eDP
+ transmitter designed for portable devices. The
+ ANX6345 transforms the LVTTL RGB output of an
+ application processor to eDP or DisplayPort.
+
+config DRM_ANALOGIX_ANX78XX
+ tristate "Analogix ANX78XX bridge"
+ select DRM_ANALOGIX_DP
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ help
+ ANX78XX is an ultra-low power Full-HD SlimPort transmitter
+ designed for portable devices. The ANX78XX transforms
+ the HDMI output of an application processor to MyDP
+ or DisplayPort.
+
config DRM_ANALOGIX_DP
tristate
depends on DRM
diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile
index fdbf3fd2f087..97669b374098 100644
--- a/drivers/gpu/drm/bridge/analogix/Makefile
+++ b/drivers/gpu/drm/bridge/analogix/Makefile
@@ -1,3 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o
+analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
+obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
+obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
new file mode 100644
index 000000000000..56f55c53abfd
--- /dev/null
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
@@ -0,0 +1,817 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2016, Analogix Semiconductor.
+ * Copyright(c) 2017, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on anx7808 driver obtained from chromeos with copyright:
+ * Copyright(c) 2013, Google Inc.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+#include "analogix-i2c-dptx.h"
+#include "analogix-i2c-txcommon.h"
+
+#define POLL_DELAY 50000 /* us */
+#define POLL_TIMEOUT 5000000 /* us */
+
+#define I2C_IDX_DPTX 0
+#define I2C_IDX_TXCOM 1
+
+static const u8 anx6345_i2c_addresses[] = {
+ [I2C_IDX_DPTX] = 0x70,
+ [I2C_IDX_TXCOM] = 0x72,
+};
+#define I2C_NUM_ADDRESSES ARRAY_SIZE(anx6345_i2c_addresses)
+
+struct anx6345 {
+ struct drm_dp_aux aux;
+ struct drm_bridge bridge;
+ struct i2c_client *client;
+ struct edid *edid;
+ struct drm_connector connector;
+ struct drm_panel *panel;
+ struct regulator *dvdd12;
+ struct regulator *dvdd25;
+ struct gpio_desc *gpiod_reset;
+ struct mutex lock; /* protect EDID access */
+
+ /* I2C Slave addresses of ANX6345 are mapped as DPTX and SYS */
+ struct i2c_client *i2c_clients[I2C_NUM_ADDRESSES];
+ struct regmap *map[I2C_NUM_ADDRESSES];
+
+ u16 chipid;
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+
+ bool powered;
+};
+
+static inline struct anx6345 *connector_to_anx6345(struct drm_connector *c)
+{
+ return container_of(c, struct anx6345, connector);
+}
+
+static inline struct anx6345 *bridge_to_anx6345(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct anx6345, bridge);
+}
+
+static int anx6345_set_bits(struct regmap *map, u8 reg, u8 mask)
+{
+ return regmap_update_bits(map, reg, mask, mask);
+}
+
+static int anx6345_clear_bits(struct regmap *map, u8 reg, u8 mask)
+{
+ return regmap_update_bits(map, reg, mask, 0);
+}
+
+static ssize_t anx6345_aux_transfer(struct drm_dp_aux *aux,
+ struct drm_dp_aux_msg *msg)
+{
+ struct anx6345 *anx6345 = container_of(aux, struct anx6345, aux);
+
+ return anx_dp_aux_transfer(anx6345->map[I2C_IDX_DPTX], msg);
+}
+
+static int anx6345_dp_link_training(struct anx6345 *anx6345)
+{
+ unsigned int value;
+ u8 dp_bw, dpcd[2];
+ int err;
+
+ err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
+ SP_POWERDOWN_CTRL_REG,
+ SP_TOTAL_PD);
+ if (err)
+ return err;
+
+ err = drm_dp_dpcd_readb(&anx6345->aux, DP_MAX_LINK_RATE, &dp_bw);
+ if (err < 0)
+ return err;
+
+ switch (dp_bw) {
+ case DP_LINK_BW_1_62:
+ case DP_LINK_BW_2_7:
+ break;
+
+ default:
+ DRM_DEBUG_KMS("DP bandwidth (%#02x) not supported\n", dp_bw);
+ return -EINVAL;
+ }
+
+ err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
+ SP_VIDEO_MUTE);
+ if (err)
+ return err;
+
+ err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
+ SP_VID_CTRL1_REG, SP_VIDEO_EN);
+ if (err)
+ return err;
+
+ /* Get DPCD info */
+ err = drm_dp_dpcd_read(&anx6345->aux, DP_DPCD_REV,
+ &anx6345->dpcd, DP_RECEIVER_CAP_SIZE);
+ if (err < 0) {
+ DRM_ERROR("Failed to read DPCD: %d\n", err);
+ return err;
+ }
+
+ /* Clear channel x SERDES power down */
+ err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_ANALOG_POWER_DOWN_REG, SP_CH0_PD);
+ if (err)
+ return err;
+
+ /*
+ * Power up the sink (DP_SET_POWER register is only available on DPCD
+ * v1.1 and later).
+ */
+ if (anx6345->dpcd[DP_DPCD_REV] >= 0x11) {
+ err = drm_dp_dpcd_readb(&anx6345->aux, DP_SET_POWER, &dpcd[0]);
+ if (err < 0) {
+ DRM_ERROR("Failed to read DP_SET_POWER register: %d\n",
+ err);
+ return err;
+ }
+
+ dpcd[0] &= ~DP_SET_POWER_MASK;
+ dpcd[0] |= DP_SET_POWER_D0;
+
+ err = drm_dp_dpcd_writeb(&anx6345->aux, DP_SET_POWER, dpcd[0]);
+ if (err < 0) {
+ DRM_ERROR("Failed to power up DisplayPort link: %d\n",
+ err);
+ return err;
+ }
+
+ /*
+ * According to the DP 1.1 specification, a "Sink Device must
+ * exit the power saving state within 1 ms" (Section 2.5.3.1,
+ * Table 5-52, "Sink Control Field" (register 0x600).
+ */
+ usleep_range(1000, 2000);
+ }
+
+ /* Possibly enable downspread on the sink */
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_DOWNSPREAD_CTRL1_REG, 0);
+ if (err)
+ return err;
+
+ if (anx6345->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) {
+ DRM_DEBUG("Enable downspread on the sink\n");
+ /* 4000PPM */
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_DOWNSPREAD_CTRL1_REG, 8);
+ if (err)
+ return err;
+
+ err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL,
+ DP_SPREAD_AMP_0_5);
+ if (err < 0)
+ return err;
+ } else {
+ err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL, 0);
+ if (err < 0)
+ return err;
+ }
+
+ /* Set the lane count and the link rate on the sink */
+ if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
+ err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_SYSTEM_CTRL_BASE + 4,
+ SP_ENHANCED_MODE);
+ else
+ err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_SYSTEM_CTRL_BASE + 4,
+ SP_ENHANCED_MODE);
+ if (err)
+ return err;
+
+ dpcd[0] = drm_dp_max_link_rate(anx6345->dpcd);
+ dpcd[0] = drm_dp_link_rate_to_bw_code(dpcd[0]);
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_MAIN_LINK_BW_SET_REG, dpcd[0]);
+ if (err)
+ return err;
+
+ dpcd[1] = drm_dp_max_lane_count(anx6345->dpcd);
+
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_LANE_COUNT_SET_REG, dpcd[1]);
+ if (err)
+ return err;
+
+ if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
+ dpcd[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+
+ err = drm_dp_dpcd_write(&anx6345->aux, DP_LINK_BW_SET, dpcd,
+ sizeof(dpcd));
+
+ if (err < 0) {
+ DRM_ERROR("Failed to configure link: %d\n", err);
+ return err;
+ }
+
+ /* Start training on the source */
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_LT_CTRL_REG,
+ SP_LT_EN);
+ if (err)
+ return err;
+
+ return regmap_read_poll_timeout(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_LT_CTRL_REG,
+ value, !(value & SP_DP_LT_INPROGRESS),
+ POLL_DELAY, POLL_TIMEOUT);
+}
+
+static int anx6345_tx_initialization(struct anx6345 *anx6345)
+{
+ int err, i;
+
+ /* FIXME: colordepth is hardcoded for now */
+ err = regmap_write(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL2_REG,
+ SP_IN_BPC_6BIT << SP_IN_BPC_SHIFT);
+ if (err)
+ return err;
+
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_PLL_CTRL_REG, 0);
+ if (err)
+ return err;
+
+ err = regmap_write(anx6345->map[I2C_IDX_TXCOM],
+ SP_ANALOG_DEBUG1_REG, 0);
+ if (err)
+ return err;
+
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_LINK_DEBUG_CTRL_REG,
+ SP_NEW_PRBS7 | SP_M_VID_DEBUG);
+ if (err)
+ return err;
+
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_ANALOG_POWER_DOWN_REG, 0);
+ if (err)
+ return err;
+
+ /* Force HPD */
+ err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_SYSTEM_CTRL_BASE + 3,
+ SP_HPD_FORCE | SP_HPD_CTRL);
+ if (err)
+ return err;
+
+ for (i = 0; i < 4; i++) {
+ /* 4 lanes */
+ err = regmap_write(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_LANE0_LT_CTRL_REG + i, 0);
+ if (err)
+ return err;
+ }
+
+ /* Reset AUX */
+ err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM],
+ SP_RESET_CTRL2_REG, SP_AUX_RST);
+ if (err)
+ return err;
+
+ return anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
+ SP_RESET_CTRL2_REG, SP_AUX_RST);
+}
+
+static void anx6345_poweron(struct anx6345 *anx6345)
+{
+ int err;
+
+ /* Ensure reset is asserted before starting power on sequence */
+ gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
+ usleep_range(1000, 2000);
+
+ err = regulator_enable(anx6345->dvdd12);
+ if (err) {
+ DRM_ERROR("Failed to enable dvdd12 regulator: %d\n",
+ err);
+ return;
+ }
+
+ /* T1 - delay between VDD12 and VDD25 should be 0-2ms */
+ usleep_range(1000, 2000);
+
+ err = regulator_enable(anx6345->dvdd25);
+ if (err) {
+ DRM_ERROR("Failed to enable dvdd25 regulator: %d\n",
+ err);
+ return;
+ }
+
+ /* T2 - delay between RESETN and all power rail stable,
+ * should be 2-5ms
+ */
+ usleep_range(2000, 5000);
+
+ gpiod_set_value_cansleep(anx6345->gpiod_reset, 0);
+
+ /* Power on registers module */
+ anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
+ SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
+ anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
+ SP_REGISTER_PD | SP_TOTAL_PD);
+
+ if (anx6345->panel)
+ drm_panel_prepare(anx6345->panel);
+
+ anx6345->powered = true;
+}
+
+static void anx6345_poweroff(struct anx6345 *anx6345)
+{
+ int err;
+
+ gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
+ usleep_range(1000, 2000);
+
+ if (anx6345->panel)
+ drm_panel_unprepare(anx6345->panel);
+
+ err = regulator_disable(anx6345->dvdd25);
+ if (err) {
+ DRM_ERROR("Failed to disable dvdd25 regulator: %d\n",
+ err);
+ return;
+ }
+
+ usleep_range(5000, 10000);
+
+ err = regulator_disable(anx6345->dvdd12);
+ if (err) {
+ DRM_ERROR("Failed to disable dvdd12 regulator: %d\n",
+ err);
+ return;
+ }
+
+ usleep_range(1000, 2000);
+
+ anx6345->powered = false;
+}
+
+static int anx6345_start(struct anx6345 *anx6345)
+{
+ int err;
+
+ if (!anx6345->powered)
+ anx6345_poweron(anx6345);
+
+ /* Power on needed modules */
+ err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
+ SP_POWERDOWN_CTRL_REG,
+ SP_VIDEO_PD | SP_LINK_PD);
+
+ err = anx6345_tx_initialization(anx6345);
+ if (err) {
+ DRM_ERROR("Failed eDP transmitter initialization: %d\n", err);
+ anx6345_poweroff(anx6345);
+ return err;
+ }
+
+ err = anx6345_dp_link_training(anx6345);
+ if (err) {
+ DRM_ERROR("Failed link training: %d\n", err);
+ anx6345_poweroff(anx6345);
+ return err;
+ }
+
+ /*
+ * This delay seems to help keep the hardware in a good state. Without
+ * it, there are times where it fails silently.
+ */
+ usleep_range(10000, 15000);
+
+ return 0;
+}
+
+static int anx6345_config_dp_output(struct anx6345 *anx6345)
+{
+ int err;
+
+ err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
+ SP_VIDEO_MUTE);
+ if (err)
+ return err;
+
+ /* Enable DP output */
+ err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
+ SP_VIDEO_EN);
+ if (err)
+ return err;
+
+ /* Force stream valid */
+ return anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
+ SP_DP_SYSTEM_CTRL_BASE + 3,
+ SP_STRM_FORCE | SP_STRM_CTRL);
+}
+
+static int anx6345_get_downstream_info(struct anx6345 *anx6345)
+{
+ u8 value;
+ int err;
+
+ err = drm_dp_dpcd_readb(&anx6345->aux, DP_SINK_COUNT, &value);
+ if (err < 0) {
+ DRM_ERROR("Get sink count failed %d\n", err);
+ return err;
+ }
+
+ if (!DP_GET_SINK_COUNT(value)) {
+ DRM_ERROR("Downstream disconnected\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int anx6345_get_modes(struct drm_connector *connector)
+{
+ struct anx6345 *anx6345 = connector_to_anx6345(connector);
+ int err, num_modes = 0;
+ bool power_off = false;
+
+ mutex_lock(&anx6345->lock);
+
+ if (!anx6345->edid) {
+ if (!anx6345->powered) {
+ anx6345_poweron(anx6345);
+ power_off = true;
+ }
+
+ err = anx6345_get_downstream_info(anx6345);
+ if (err) {
+ DRM_ERROR("Failed to get downstream info: %d\n", err);
+ goto unlock;
+ }
+
+ anx6345->edid = drm_get_edid(connector, &anx6345->aux.ddc);
+ if (!anx6345->edid)
+ DRM_ERROR("Failed to read EDID from panel\n");
+
+ err = drm_connector_update_edid_property(connector,
+ anx6345->edid);
+ if (err) {
+ DRM_ERROR("Failed to update EDID property: %d\n", err);
+ goto unlock;
+ }
+ }
+
+ num_modes += drm_add_edid_modes(connector, anx6345->edid);
+
+unlock:
+ if (power_off)
+ anx6345_poweroff(anx6345);
+
+ mutex_unlock(&anx6345->lock);
+
+ if (!num_modes && anx6345->panel)
+ num_modes += drm_panel_get_modes(anx6345->panel, connector);
+
+ return num_modes;
+}
+
+static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs = {
+ .get_modes = anx6345_get_modes,
+};
+
+static void
+anx6345_connector_destroy(struct drm_connector *connector)
+{
+ struct anx6345 *anx6345 = connector_to_anx6345(connector);
+
+ if (anx6345->panel)
+ drm_panel_detach(anx6345->panel);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs anx6345_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = anx6345_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int anx6345_bridge_attach(struct drm_bridge *bridge)
+{
+ struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
+ int err;
+
+ if (!bridge->encoder) {
+ DRM_ERROR("Parent encoder object not found");
+ return -ENODEV;
+ }
+
+ /* Register aux channel */
+ anx6345->aux.name = "DP-AUX";
+ anx6345->aux.dev = &anx6345->client->dev;
+ anx6345->aux.transfer = anx6345_aux_transfer;
+
+ err = drm_dp_aux_register(&anx6345->aux);
+ if (err < 0) {
+ DRM_ERROR("Failed to register aux channel: %d\n", err);
+ return err;
+ }
+
+ err = drm_connector_init(bridge->dev, &anx6345->connector,
+ &anx6345_connector_funcs,
+ DRM_MODE_CONNECTOR_eDP);
+ if (err) {
+ DRM_ERROR("Failed to initialize connector: %d\n", err);
+ return err;
+ }
+
+ drm_connector_helper_add(&anx6345->connector,
+ &anx6345_connector_helper_funcs);
+
+ err = drm_connector_register(&anx6345->connector);
+ if (err) {
+ DRM_ERROR("Failed to register connector: %d\n", err);
+ return err;
+ }
+
+ anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ err = drm_connector_attach_encoder(&anx6345->connector,
+ bridge->encoder);
+ if (err) {
+ DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
+ return err;
+ }
+
+ if (anx6345->panel) {
+ err = drm_panel_attach(anx6345->panel, &anx6345->connector);
+ if (err) {
+ DRM_ERROR("Failed to attach panel: %d\n", err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+anx6345_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode)
+{
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ return MODE_NO_INTERLACE;
+
+ /* Max 1200p at 5.4 Ghz, one lane */
+ if (mode->clock > 154000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static void anx6345_bridge_disable(struct drm_bridge *bridge)
+{
+ struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
+
+ /* Power off all modules except configuration registers access */
+ anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
+ SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
+ if (anx6345->panel)
+ drm_panel_disable(anx6345->panel);
+
+ if (anx6345->powered)
+ anx6345_poweroff(anx6345);
+}
+
+static void anx6345_bridge_enable(struct drm_bridge *bridge)
+{
+ struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
+ int err;
+
+ if (anx6345->panel)
+ drm_panel_enable(anx6345->panel);
+
+ err = anx6345_start(anx6345);
+ if (err) {
+ DRM_ERROR("Failed to initialize: %d\n", err);
+ return;
+ }
+
+ err = anx6345_config_dp_output(anx6345);
+ if (err)
+ DRM_ERROR("Failed to enable DP output: %d\n", err);
+}
+
+static const struct drm_bridge_funcs anx6345_bridge_funcs = {
+ .attach = anx6345_bridge_attach,
+ .mode_valid = anx6345_bridge_mode_valid,
+ .disable = anx6345_bridge_disable,
+ .enable = anx6345_bridge_enable,
+};
+
+static void unregister_i2c_dummy_clients(struct anx6345 *anx6345)
+{
+ unsigned int i;
+
+ for (i = 1; i < ARRAY_SIZE(anx6345->i2c_clients); i++)
+ if (anx6345->i2c_clients[i] &&
+ anx6345->i2c_clients[i]->addr != anx6345->client->addr)
+ i2c_unregister_device(anx6345->i2c_clients[i]);
+}
+
+static const struct regmap_config anx6345_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .cache_type = REGCACHE_NONE,
+};
+
+static const u16 anx6345_chipid_list[] = {
+ 0x6345,
+};
+
+static bool anx6345_get_chip_id(struct anx6345 *anx6345)
+{
+ unsigned int i, idl, idh, version;
+
+ if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDL_REG, &idl))
+ return false;
+
+ if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDH_REG, &idh))
+ return false;
+
+ anx6345->chipid = (u8)idl | ((u8)idh << 8);
+
+ if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_VERSION_REG,
+ &version))
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(anx6345_chipid_list); i++) {
+ if (anx6345->chipid == anx6345_chipid_list[i]) {
+ DRM_INFO("Found ANX%x (ver. %d) eDP Transmitter\n",
+ anx6345->chipid, version);
+ return true;
+ }
+ }
+
+ DRM_ERROR("ANX%x (ver. %d) not supported by this driver\n",
+ anx6345->chipid, version);
+
+ return false;
+}
+
+static int anx6345_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct anx6345 *anx6345;
+ struct device *dev;
+ int i, err;
+
+ anx6345 = devm_kzalloc(&client->dev, sizeof(*anx6345), GFP_KERNEL);
+ if (!anx6345)
+ return -ENOMEM;
+
+ mutex_init(&anx6345->lock);
+
+ anx6345->bridge.of_node = client->dev.of_node;
+
+ anx6345->client = client;
+ i2c_set_clientdata(client, anx6345);
+
+ dev = &anx6345->client->dev;
+
+ err = drm_of_find_panel_or_bridge(client->dev.of_node, 1, 0,
+ &anx6345->panel, NULL);
+ if (err == -EPROBE_DEFER)
+ return err;
+
+ if (err)
+ DRM_DEBUG("No panel found\n");
+
+ /* 1.2V digital core power regulator */
+ anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12-supply");
+ if (IS_ERR(anx6345->dvdd12)) {
+ DRM_ERROR("dvdd12-supply not found\n");
+ return PTR_ERR(anx6345->dvdd12);
+ }
+
+ /* 2.5V digital core power regulator */
+ anx6345->dvdd25 = devm_regulator_get(dev, "dvdd25-supply");
+ if (IS_ERR(anx6345->dvdd25)) {
+ DRM_ERROR("dvdd25-supply not found\n");
+ return PTR_ERR(anx6345->dvdd25);
+ }
+
+ /* GPIO for chip reset */
+ anx6345->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(anx6345->gpiod_reset)) {
+ DRM_ERROR("Reset gpio not found\n");
+ return PTR_ERR(anx6345->gpiod_reset);
+ }
+
+ /* Map slave addresses of ANX6345 */
+ for (i = 0; i < I2C_NUM_ADDRESSES; i++) {
+ if (anx6345_i2c_addresses[i] >> 1 != client->addr)
+ anx6345->i2c_clients[i] = i2c_new_dummy_device(client->adapter,
+ anx6345_i2c_addresses[i] >> 1);
+ else
+ anx6345->i2c_clients[i] = client;
+
+ if (IS_ERR(anx6345->i2c_clients[i])) {
+ err = PTR_ERR(anx6345->i2c_clients[i]);
+ DRM_ERROR("Failed to reserve I2C bus %02x\n",
+ anx6345_i2c_addresses[i]);
+ goto err_unregister_i2c;
+ }
+
+ anx6345->map[i] = devm_regmap_init_i2c(anx6345->i2c_clients[i],
+ &anx6345_regmap_config);
+ if (IS_ERR(anx6345->map[i])) {
+ err = PTR_ERR(anx6345->map[i]);
+ DRM_ERROR("Failed regmap initialization %02x\n",
+ anx6345_i2c_addresses[i]);
+ goto err_unregister_i2c;
+ }
+ }
+
+ /* Look for supported chip ID */
+ anx6345_poweron(anx6345);
+ if (anx6345_get_chip_id(anx6345)) {
+ anx6345->bridge.funcs = &anx6345_bridge_funcs;
+ drm_bridge_add(&anx6345->bridge);
+
+ return 0;
+ } else {
+ anx6345_poweroff(anx6345);
+ err = -ENODEV;
+ }
+
+err_unregister_i2c:
+ unregister_i2c_dummy_clients(anx6345);
+ return err;
+}
+
+static int anx6345_i2c_remove(struct i2c_client *client)
+{
+ struct anx6345 *anx6345 = i2c_get_clientdata(client);
+
+ drm_bridge_remove(&anx6345->bridge);
+
+ unregister_i2c_dummy_clients(anx6345);
+
+ kfree(anx6345->edid);
+
+ mutex_destroy(&anx6345->lock);
+
+ return 0;
+}
+
+static const struct i2c_device_id anx6345_id[] = {
+ { "anx6345", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, anx6345_id);
+
+static const struct of_device_id anx6345_match_table[] = {
+ { .compatible = "analogix,anx6345", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, anx6345_match_table);
+
+static struct i2c_driver anx6345_driver = {
+ .driver = {
+ .name = "anx6345",
+ .of_match_table = of_match_ptr(anx6345_match_table),
+ },
+ .probe = anx6345_i2c_probe,
+ .remove = anx6345_i2c_remove,
+ .id_table = anx6345_id,
+};
+module_i2c_driver(anx6345_driver);
+
+MODULE_DESCRIPTION("ANX6345 eDP Transmitter driver");
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
index 274989f96a91..41867be03751 100644
--- a/drivers/gpu/drm/bridge/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
@@ -36,8 +36,6 @@
#define I2C_IDX_RX_P1 4
#define XTAL_CLK 270 /* 27M */
-#define AUX_CH_BUFFER_SIZE 16
-#define AUX_WAIT_TIMEOUT_MS 15
static const u8 anx7808_i2c_addresses[] = {
[I2C_IDX_TX_P0] = 0x78,
@@ -107,153 +105,11 @@ static int anx78xx_clear_bits(struct regmap *map, u8 reg, u8 mask)
return regmap_update_bits(map, reg, mask, 0);
}
-static bool anx78xx_aux_op_finished(struct anx78xx *anx78xx)
-{
- unsigned int value;
- int err;
-
- err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL2_REG,
- &value);
- if (err < 0)
- return false;
-
- return (value & SP_AUX_EN) == 0;
-}
-
-static int anx78xx_aux_wait(struct anx78xx *anx78xx)
-{
- unsigned long timeout;
- unsigned int status;
- int err;
-
- timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
-
- while (!anx78xx_aux_op_finished(anx78xx)) {
- if (time_after(jiffies, timeout)) {
- if (!anx78xx_aux_op_finished(anx78xx)) {
- DRM_ERROR("Timed out waiting AUX to finish\n");
- return -ETIMEDOUT;
- }
-
- break;
- }
-
- usleep_range(1000, 2000);
- }
-
- /* Read the AUX channel access status */
- err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_CH_STATUS_REG,
- &status);
- if (err < 0) {
- DRM_ERROR("Failed to read from AUX channel: %d\n", err);
- return err;
- }
-
- if (status & SP_AUX_STATUS) {
- DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n",
- status);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int anx78xx_aux_address(struct anx78xx *anx78xx, unsigned int addr)
-{
- int err;
-
- err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_7_0_REG,
- addr & 0xff);
- if (err)
- return err;
-
- err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_15_8_REG,
- (addr & 0xff00) >> 8);
- if (err)
- return err;
-
- /*
- * DP AUX CH Address Register #2, only update bits[3:0]
- * [7:4] RESERVED
- * [3:0] AUX_ADDR[19:16], Register control AUX CH address.
- */
- err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0],
- SP_AUX_ADDR_19_16_REG,
- SP_AUX_ADDR_19_16_MASK,
- (addr & 0xf0000) >> 16);
-
- if (err)
- return err;
-
- return 0;
-}
-
static ssize_t anx78xx_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
struct anx78xx *anx78xx = container_of(aux, struct anx78xx, aux);
- u8 ctrl1 = msg->request;
- u8 ctrl2 = SP_AUX_EN;
- u8 *buffer = msg->buffer;
- int err;
-
- /* The DP AUX transmit and receive buffer has 16 bytes. */
- if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
- return -E2BIG;
-
- /* Zero-sized messages specify address-only transactions. */
- if (msg->size < 1)
- ctrl2 |= SP_ADDR_ONLY;
- else /* For non-zero-sized set the length field. */
- ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;
-
- if ((msg->request & DP_AUX_I2C_READ) == 0) {
- /* When WRITE | MOT write values to data buffer */
- err = regmap_bulk_write(anx78xx->map[I2C_IDX_TX_P0],
- SP_DP_BUF_DATA0_REG, buffer,
- msg->size);
- if (err)
- return err;
- }
-
- /* Write address and request */
- err = anx78xx_aux_address(anx78xx, msg->address);
- if (err)
- return err;
-
- err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL1_REG,
- ctrl1);
- if (err)
- return err;
-
- /* Start transaction */
- err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0],
- SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY |
- SP_AUX_EN, ctrl2);
- if (err)
- return err;
-
- err = anx78xx_aux_wait(anx78xx);
- if (err)
- return err;
-
- msg->reply = DP_AUX_I2C_REPLY_ACK;
-
- if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
- /* Read values from data buffer */
- err = regmap_bulk_read(anx78xx->map[I2C_IDX_TX_P0],
- SP_DP_BUF_DATA0_REG, buffer,
- msg->size);
- if (err)
- return err;
- }
-
- err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0],
- SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY);
- if (err)
- return err;
-
- return msg->size;
+ return anx_dp_aux_transfer(anx78xx->map[I2C_IDX_TX_P0], msg);
}
static int anx78xx_set_hpd(struct anx78xx *anx78xx)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.h b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.h
new file mode 100644
index 000000000000..db2a2725acb2
--- /dev/null
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.h
@@ -0,0 +1,249 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2016, Analogix Semiconductor. All rights reserved.
+ */
+
+#ifndef __ANX78xx_H
+#define __ANX78xx_H
+
+#include "analogix-i2c-dptx.h"
+#include "analogix-i2c-txcommon.h"
+
+/***************************************************************/
+/* Register definitions for RX_PO */
+/***************************************************************/
+
+/*
+ * System Control and Status
+ */
+
+/* Software Reset Register 1 */
+#define SP_SOFTWARE_RESET1_REG 0x11
+#define SP_VIDEO_RST BIT(4)
+#define SP_HDCP_MAN_RST BIT(2)
+#define SP_TMDS_RST BIT(1)
+#define SP_SW_MAN_RST BIT(0)
+
+/* System Status Register */
+#define SP_SYSTEM_STATUS_REG 0x14
+#define SP_TMDS_CLOCK_DET BIT(1)
+#define SP_TMDS_DE_DET BIT(0)
+
+/* HDMI Status Register */
+#define SP_HDMI_STATUS_REG 0x15
+#define SP_HDMI_AUD_LAYOUT BIT(3)
+#define SP_HDMI_DET BIT(0)
+# define SP_DVI_MODE 0
+# define SP_HDMI_MODE 1
+
+/* HDMI Mute Control Register */
+#define SP_HDMI_MUTE_CTRL_REG 0x16
+#define SP_AUD_MUTE BIT(1)
+#define SP_VID_MUTE BIT(0)
+
+/* System Power Down Register 1 */
+#define SP_SYSTEM_POWER_DOWN1_REG 0x18
+#define SP_PWDN_CTRL BIT(0)
+
+/*
+ * Audio and Video Auto Control
+ */
+
+/* Auto Audio and Video Control register */
+#define SP_AUDVID_CTRL_REG 0x20
+#define SP_AVC_OE BIT(7)
+#define SP_AAC_OE BIT(6)
+#define SP_AVC_EN BIT(1)
+#define SP_AAC_EN BIT(0)
+
+/* Audio Exception Enable Registers */
+#define SP_AUD_EXCEPTION_ENABLE_BASE (0x24 - 1)
+/* Bits for Audio Exception Enable Register 3 */
+#define SP_AEC_EN21 BIT(5)
+
+/*
+ * Interrupt
+ */
+
+/* Interrupt Status Register 1 */
+#define SP_INT_STATUS1_REG 0x31
+/* Bits for Interrupt Status Register 1 */
+#define SP_HDMI_DVI BIT(7)
+#define SP_CKDT_CHG BIT(6)
+#define SP_SCDT_CHG BIT(5)
+#define SP_PCLK_CHG BIT(4)
+#define SP_PLL_UNLOCK BIT(3)
+#define SP_CABLE_PLUG_CHG BIT(2)
+#define SP_SET_MUTE BIT(1)
+#define SP_SW_INTR BIT(0)
+/* Bits for Interrupt Status Register 2 */
+#define SP_HDCP_ERR BIT(5)
+#define SP_AUDIO_SAMPLE_CHG BIT(0) /* undocumented */
+/* Bits for Interrupt Status Register 3 */
+#define SP_AUD_MODE_CHG BIT(0)
+/* Bits for Interrupt Status Register 5 */
+#define SP_AUDIO_RCV BIT(0)
+/* Bits for Interrupt Status Register 6 */
+#define SP_INT_STATUS6_REG 0x36
+#define SP_CTS_RCV BIT(7)
+#define SP_NEW_AUD_PKT BIT(4)
+#define SP_NEW_AVI_PKT BIT(1)
+#define SP_NEW_CP_PKT BIT(0)
+/* Bits for Interrupt Status Register 7 */
+#define SP_NO_VSI BIT(7)
+#define SP_NEW_VS BIT(4)
+
+/* Interrupt Mask 1 Status Registers */
+#define SP_INT_MASK1_REG 0x41
+
+/* HDMI US TIMER Control Register */
+#define SP_HDMI_US_TIMER_CTRL_REG 0x49
+#define SP_MS_TIMER_MARGIN_10_8_MASK 0x07
+
+/*
+ * TMDS Control
+ */
+
+/* TMDS Control Registers */
+#define SP_TMDS_CTRL_BASE (0x50 - 1)
+/* Bits for TMDS Control Register 7 */
+#define SP_PD_RT BIT(0)
+
+/*
+ * Video Control
+ */
+
+/* Video Status Register */
+#define SP_VIDEO_STATUS_REG 0x70
+#define SP_COLOR_DEPTH_MASK 0xf0
+#define SP_COLOR_DEPTH_SHIFT 4
+# define SP_COLOR_DEPTH_MODE_LEGACY 0x00
+# define SP_COLOR_DEPTH_MODE_24BIT 0x04
+# define SP_COLOR_DEPTH_MODE_30BIT 0x05
+# define SP_COLOR_DEPTH_MODE_36BIT 0x06
+# define SP_COLOR_DEPTH_MODE_48BIT 0x07
+
+/* Video Data Range Control Register */
+#define SP_VID_DATA_RANGE_CTRL_REG 0x83
+#define SP_R2Y_INPUT_LIMIT BIT(1)
+
+/* Pixel Clock High Resolution Counter Registers */
+#define SP_PCLK_HIGHRES_CNT_BASE (0x8c - 1)
+
+/*
+ * Audio Control
+ */
+
+/* Number of Audio Channels Status Registers */
+#define SP_AUD_CH_STATUS_REG_NUM 6
+
+/* Audio IN S/PDIF Channel Status Registers */
+#define SP_AUD_SPDIF_CH_STATUS_BASE 0xc7
+
+/* Audio IN S/PDIF Channel Status Register 4 */
+#define SP_FS_FREQ_MASK 0x0f
+# define SP_FS_FREQ_44100HZ 0x00
+# define SP_FS_FREQ_48000HZ 0x02
+# define SP_FS_FREQ_32000HZ 0x03
+# define SP_FS_FREQ_88200HZ 0x08
+# define SP_FS_FREQ_96000HZ 0x0a
+# define SP_FS_FREQ_176400HZ 0x0c
+# define SP_FS_FREQ_192000HZ 0x0e
+
+/*
+ * Micellaneous Control Block
+ */
+
+/* CHIP Control Register */
+#define SP_CHIP_CTRL_REG 0xe3
+#define SP_MAN_HDMI5V_DET BIT(3)
+#define SP_PLLLOCK_CKDT_EN BIT(2)
+#define SP_ANALOG_CKDT_EN BIT(1)
+#define SP_DIGITAL_CKDT_EN BIT(0)
+
+/* Packet Receiving Status Register */
+#define SP_PACKET_RECEIVING_STATUS_REG 0xf3
+#define SP_AVI_RCVD BIT(5)
+#define SP_VSI_RCVD BIT(1)
+
+/***************************************************************/
+/* Register definitions for RX_P1 */
+/***************************************************************/
+
+/* HDCP BCAPS Shadow Register */
+#define SP_HDCP_BCAPS_SHADOW_REG 0x2a
+#define SP_BCAPS_REPEATER BIT(5)
+
+/* HDCP Status Register */
+#define SP_RX_HDCP_STATUS_REG 0x3f
+#define SP_AUTH_EN BIT(4)
+
+/*
+ * InfoFrame and Control Packet Registers
+ */
+
+/* AVI InfoFrame packet checksum */
+#define SP_AVI_INFOFRAME_CHECKSUM 0xa3
+
+/* AVI InfoFrame Registers */
+#define SP_AVI_INFOFRAME_DATA_BASE 0xa4
+
+#define SP_AVI_COLOR_F_MASK 0x60
+#define SP_AVI_COLOR_F_SHIFT 5
+
+/* Audio InfoFrame Registers */
+#define SP_AUD_INFOFRAME_DATA_BASE 0xc4
+#define SP_AUD_INFOFRAME_LAYOUT_MASK 0x0f
+
+/* MPEG/HDMI Vendor Specific InfoFrame Packet type code */
+#define SP_MPEG_VS_INFOFRAME_TYPE_REG 0xe0
+
+/* MPEG/HDMI Vendor Specific InfoFrame Packet length */
+#define SP_MPEG_VS_INFOFRAME_LEN_REG 0xe2
+
+/* MPEG/HDMI Vendor Specific InfoFrame Packet version number */
+#define SP_MPEG_VS_INFOFRAME_VER_REG 0xe1
+
+/* MPEG/HDMI Vendor Specific InfoFrame Packet content */
+#define SP_MPEG_VS_INFOFRAME_DATA_BASE 0xe4
+
+/* General Control Packet Register */
+#define SP_GENERAL_CTRL_PACKET_REG 0x9f
+#define SP_CLEAR_AVMUTE BIT(4)
+#define SP_SET_AVMUTE BIT(0)
+
+/***************************************************************/
+/* Register definitions for TX_P1 */
+/***************************************************************/
+
+/* DP TX Link Training Control Register */
+#define SP_DP_TX_LT_CTRL0_REG 0x30
+
+/* PD 1.2 Lint Training 80bit Pattern Register */
+#define SP_DP_LT_80BIT_PATTERN0_REG 0x80
+#define SP_DP_LT_80BIT_PATTERN_REG_NUM 10
+
+/* Audio Interface Control Register 0 */
+#define SP_AUD_INTERFACE_CTRL0_REG 0x5f
+#define SP_AUD_INTERFACE_DISABLE 0x80
+
+/* Audio Interface Control Register 2 */
+#define SP_AUD_INTERFACE_CTRL2_REG 0x60
+#define SP_M_AUD_ADJUST_ST 0x04
+
+/* Audio Interface Control Register 3 */
+#define SP_AUD_INTERFACE_CTRL3_REG 0x62
+
+/* Audio Interface Control Register 4 */
+#define SP_AUD_INTERFACE_CTRL4_REG 0x67
+
+/* Audio Interface Control Register 5 */
+#define SP_AUD_INTERFACE_CTRL5_REG 0x68
+
+/* Audio Interface Control Register 6 */
+#define SP_AUD_INTERFACE_CTRL6_REG 0x69
+
+/* Firmware Version Register */
+#define SP_FW_VER_REG 0xb7
+
+#endif
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c
new file mode 100644
index 000000000000..fe40bab21530
--- /dev/null
+++ b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2016, Analogix Semiconductor.
+ *
+ * Based on anx7808 driver obtained from chromeos with copyright:
+ * Copyright(c) 2013, Google Inc.
+ */
+#include <linux/regmap.h>
+
+#include <drm/drm.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_print.h>
+
+#include "analogix-i2c-dptx.h"
+
+#define AUX_WAIT_TIMEOUT_MS 15
+#define AUX_CH_BUFFER_SIZE 16
+
+static int anx_i2c_dp_clear_bits(struct regmap *map, u8 reg, u8 mask)
+{
+ return regmap_update_bits(map, reg, mask, 0);
+}
+
+static bool anx_dp_aux_op_finished(struct regmap *map_dptx)
+{
+ unsigned int value;
+ int err;
+
+ err = regmap_read(map_dptx, SP_DP_AUX_CH_CTRL2_REG, &value);
+ if (err < 0)
+ return false;
+
+ return (value & SP_AUX_EN) == 0;
+}
+
+static int anx_dp_aux_wait(struct regmap *map_dptx)
+{
+ unsigned long timeout;
+ unsigned int status;
+ int err;
+
+ timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
+
+ while (!anx_dp_aux_op_finished(map_dptx)) {
+ if (time_after(jiffies, timeout)) {
+ if (!anx_dp_aux_op_finished(map_dptx)) {
+ DRM_ERROR("Timed out waiting AUX to finish\n");
+ return -ETIMEDOUT;
+ }
+
+ break;
+ }
+
+ usleep_range(1000, 2000);
+ }
+
+ /* Read the AUX channel access status */
+ err = regmap_read(map_dptx, SP_AUX_CH_STATUS_REG, &status);
+ if (err < 0) {
+ DRM_ERROR("Failed to read from AUX channel: %d\n", err);
+ return err;
+ }
+
+ if (status & SP_AUX_STATUS) {
+ DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n",
+ status);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int anx_dp_aux_address(struct regmap *map_dptx, unsigned int addr)
+{
+ int err;
+
+ err = regmap_write(map_dptx, SP_AUX_ADDR_7_0_REG, addr & 0xff);
+ if (err)
+ return err;
+
+ err = regmap_write(map_dptx, SP_AUX_ADDR_15_8_REG,
+ (addr & 0xff00) >> 8);
+ if (err)
+ return err;
+
+ /*
+ * DP AUX CH Address Register #2, only update bits[3:0]
+ * [7:4] RESERVED
+ * [3:0] AUX_ADDR[19:16], Register control AUX CH address.
+ */
+ err = regmap_update_bits(map_dptx, SP_AUX_ADDR_19_16_REG,
+ SP_AUX_ADDR_19_16_MASK,
+ (addr & 0xf0000) >> 16);
+
+ if (err)
+ return err;
+
+ return 0;
+}
+
+ssize_t anx_dp_aux_transfer(struct regmap *map_dptx,
+ struct drm_dp_aux_msg *msg)
+{
+ u8 ctrl1 = msg->request;
+ u8 ctrl2 = SP_AUX_EN;
+ u8 *buffer = msg->buffer;
+ int err;
+
+ /* The DP AUX transmit and receive buffer has 16 bytes. */
+ if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
+ return -E2BIG;
+
+ /* Zero-sized messages specify address-only transactions. */
+ if (msg->size < 1)
+ ctrl2 |= SP_ADDR_ONLY;
+ else /* For non-zero-sized set the length field. */
+ ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;
+
+ if ((msg->size > 0) && ((msg->request & DP_AUX_I2C_READ) == 0)) {
+ /* When WRITE | MOT write values to data buffer */
+ err = regmap_bulk_write(map_dptx,
+ SP_DP_BUF_DATA0_REG, buffer,
+ msg->size);
+ if (err)
+ return err;
+ }
+
+ /* Write address and request */
+ err = anx_dp_aux_address(map_dptx, msg->address);
+ if (err)
+ return err;
+
+ err = regmap_write(map_dptx, SP_DP_AUX_CH_CTRL1_REG, ctrl1);
+ if (err)
+ return err;
+
+ /* Start transaction */
+ err = regmap_update_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
+ SP_ADDR_ONLY | SP_AUX_EN, ctrl2);
+ if (err)
+ return err;
+
+ err = anx_dp_aux_wait(map_dptx);
+ if (err)
+ return err;
+
+ msg->reply = DP_AUX_I2C_REPLY_ACK;
+
+ if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
+ /* Read values from data buffer */
+ err = regmap_bulk_read(map_dptx,
+ SP_DP_BUF_DATA0_REG, buffer,
+ msg->size);
+ if (err)
+ return err;
+ }
+
+ err = anx_i2c_dp_clear_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
+ SP_ADDR_ONLY);
+ if (err)
+ return err;
+
+ return msg->size;
+}
+EXPORT_SYMBOL_GPL(anx_dp_aux_transfer);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h
new file mode 100644
index 000000000000..663c4bea6e70
--- /dev/null
+++ b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2016, Analogix Semiconductor.
+ *
+ * Based on anx7808 driver obtained from chromeos with copyright:
+ * Copyright(c) 2013, Google Inc.
+ */
+#ifndef _ANALOGIX_I2C_DPTX_H_
+#define _ANALOGIX_I2C_DPTX_H_
+
+/***************************************************************/
+/* Register definitions for TX_P0 */
+/***************************************************************/
+
+/* HDCP Status Register */
+#define SP_TX_HDCP_STATUS_REG 0x00
+#define SP_AUTH_FAIL BIT(5)
+#define SP_AUTHEN_PASS BIT(1)
+
+/* HDCP Control Register 0 */
+#define SP_HDCP_CTRL0_REG 0x01
+#define SP_RX_REPEATER BIT(6)
+#define SP_RE_AUTH BIT(5)
+#define SP_SW_AUTH_OK BIT(4)
+#define SP_HARD_AUTH_EN BIT(3)
+#define SP_HDCP_ENC_EN BIT(2)
+#define SP_BKSV_SRM_PASS BIT(1)
+#define SP_KSVLIST_VLD BIT(0)
+/* HDCP Function Enabled */
+#define SP_HDCP_FUNCTION_ENABLED (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+/* HDCP Receiver BSTATUS Register 0 */
+#define SP_HDCP_RX_BSTATUS0_REG 0x1b
+/* HDCP Receiver BSTATUS Register 1 */
+#define SP_HDCP_RX_BSTATUS1_REG 0x1c
+
+/* HDCP Embedded "Blue Screen" Content Registers */
+#define SP_HDCP_VID0_BLUE_SCREEN_REG 0x2c
+#define SP_HDCP_VID1_BLUE_SCREEN_REG 0x2d
+#define SP_HDCP_VID2_BLUE_SCREEN_REG 0x2e
+
+/* HDCP Wait R0 Timing Register */
+#define SP_HDCP_WAIT_R0_TIME_REG 0x40
+
+/* HDCP Link Integrity Check Timer Register */
+#define SP_HDCP_LINK_CHECK_TIMER_REG 0x41
+
+/* HDCP Repeater Ready Wait Timer Register */
+#define SP_HDCP_RPTR_RDY_WAIT_TIME_REG 0x42
+
+/* HDCP Auto Timer Register */
+#define SP_HDCP_AUTO_TIMER_REG 0x51
+
+/* HDCP Key Status Register */
+#define SP_HDCP_KEY_STATUS_REG 0x5e
+
+/* HDCP Key Command Register */
+#define SP_HDCP_KEY_COMMAND_REG 0x5f
+#define SP_DISABLE_SYNC_HDCP BIT(2)
+
+/* OTP Memory Key Protection Registers */
+#define SP_OTP_KEY_PROTECT1_REG 0x60
+#define SP_OTP_KEY_PROTECT2_REG 0x61
+#define SP_OTP_KEY_PROTECT3_REG 0x62
+#define SP_OTP_PSW1 0xa2
+#define SP_OTP_PSW2 0x7e
+#define SP_OTP_PSW3 0xc6
+
+/* DP System Control Registers */
+#define SP_DP_SYSTEM_CTRL_BASE (0x80 - 1)
+/* Bits for DP System Control Register 2 */
+#define SP_CHA_STA BIT(2)
+/* Bits for DP System Control Register 3 */
+#define SP_HPD_STATUS BIT(6)
+#define SP_HPD_FORCE BIT(5)
+#define SP_HPD_CTRL BIT(4)
+#define SP_STRM_VALID BIT(2)
+#define SP_STRM_FORCE BIT(1)
+#define SP_STRM_CTRL BIT(0)
+/* Bits for DP System Control Register 4 */
+#define SP_ENHANCED_MODE BIT(3)
+
+/* DP Video Control Register */
+#define SP_DP_VIDEO_CTRL_REG 0x84
+#define SP_COLOR_F_MASK 0x06
+#define SP_COLOR_F_SHIFT 1
+#define SP_BPC_MASK 0xe0
+#define SP_BPC_SHIFT 5
+# define SP_BPC_6BITS 0x00
+# define SP_BPC_8BITS 0x01
+# define SP_BPC_10BITS 0x02
+# define SP_BPC_12BITS 0x03
+
+/* DP Audio Control Register */
+#define SP_DP_AUDIO_CTRL_REG 0x87
+#define SP_AUD_EN BIT(0)
+
+/* 10us Pulse Generate Timer Registers */
+#define SP_I2C_GEN_10US_TIMER0_REG 0x88
+#define SP_I2C_GEN_10US_TIMER1_REG 0x89
+
+/* Packet Send Control Register */
+#define SP_PACKET_SEND_CTRL_REG 0x90
+#define SP_AUD_IF_UP BIT(7)
+#define SP_AVI_IF_UD BIT(6)
+#define SP_MPEG_IF_UD BIT(5)
+#define SP_SPD_IF_UD BIT(4)
+#define SP_AUD_IF_EN BIT(3)
+#define SP_AVI_IF_EN BIT(2)
+#define SP_MPEG_IF_EN BIT(1)
+#define SP_SPD_IF_EN BIT(0)
+
+/* DP HDCP Control Register */
+#define SP_DP_HDCP_CTRL_REG 0x92
+#define SP_AUTO_EN BIT(7)
+#define SP_AUTO_START BIT(5)
+#define SP_LINK_POLLING BIT(1)
+
+/* DP Main Link Bandwidth Setting Register */
+#define SP_DP_MAIN_LINK_BW_SET_REG 0xa0
+#define SP_LINK_BW_SET_MASK 0x1f
+#define SP_INITIAL_SLIM_M_AUD_SEL BIT(5)
+
+/* DP Lane Count Setting Register */
+#define SP_DP_LANE_COUNT_SET_REG 0xa1
+
+/* DP Training Pattern Set Register */
+#define SP_DP_TRAINING_PATTERN_SET_REG 0xa2
+
+/* DP Lane 0 Link Training Control Register */
+#define SP_DP_LANE0_LT_CTRL_REG 0xa3
+#define SP_TX_SW_SET_MASK 0x1b
+#define SP_MAX_PRE_REACH BIT(5)
+#define SP_MAX_DRIVE_REACH BIT(4)
+#define SP_PRE_EMP_LEVEL1 BIT(3)
+#define SP_DRVIE_CURRENT_LEVEL1 BIT(0)
+
+/* DP Link Training Control Register */
+#define SP_DP_LT_CTRL_REG 0xa8
+#define SP_DP_LT_INPROGRESS 0x80
+#define SP_LT_ERROR_TYPE_MASK 0x70
+# define SP_LT_NO_ERROR 0x00
+# define SP_LT_AUX_WRITE_ERROR 0x01
+# define SP_LT_MAX_DRIVE_REACHED 0x02
+# define SP_LT_WRONG_LANE_COUNT_SET 0x03
+# define SP_LT_LOOP_SAME_5_TIME 0x04
+# define SP_LT_CR_FAIL_IN_EQ 0x05
+# define SP_LT_EQ_LOOP_5_TIME 0x06
+#define SP_LT_EN BIT(0)
+
+/* DP CEP Training Control Registers */
+#define SP_DP_CEP_TRAINING_CTRL0_REG 0xa9
+#define SP_DP_CEP_TRAINING_CTRL1_REG 0xaa
+
+/* DP Debug Register 1 */
+#define SP_DP_DEBUG1_REG 0xb0
+#define SP_DEBUG_PLL_LOCK BIT(4)
+#define SP_POLLING_EN BIT(1)
+
+/* DP Polling Control Register */
+#define SP_DP_POLLING_CTRL_REG 0xb4
+#define SP_AUTO_POLLING_DISABLE BIT(0)
+
+/* DP Link Debug Control Register */
+#define SP_DP_LINK_DEBUG_CTRL_REG 0xb8
+#define SP_M_VID_DEBUG BIT(5)
+#define SP_NEW_PRBS7 BIT(4)
+#define SP_INSERT_ER BIT(1)
+#define SP_PRBS31_EN BIT(0)
+
+/* AUX Misc control Register */
+#define SP_AUX_MISC_CTRL_REG 0xbf
+
+/* DP PLL control Register */
+#define SP_DP_PLL_CTRL_REG 0xc7
+#define SP_PLL_RST BIT(6)
+
+/* DP Analog Power Down Register */
+#define SP_DP_ANALOG_POWER_DOWN_REG 0xc8
+#define SP_CH0_PD BIT(0)
+
+/* DP Misc Control Register */
+#define SP_DP_MISC_CTRL_REG 0xcd
+#define SP_EQ_TRAINING_LOOP BIT(6)
+
+/* DP Extra I2C Device Address Register */
+#define SP_DP_EXTRA_I2C_DEV_ADDR_REG 0xce
+#define SP_I2C_STRETCH_DISABLE BIT(7)
+
+#define SP_I2C_EXTRA_ADDR 0x50
+
+/* DP Downspread Control Register 1 */
+#define SP_DP_DOWNSPREAD_CTRL1_REG 0xd0
+
+/* DP M Value Calculation Control Register */
+#define SP_DP_M_CALCULATION_CTRL_REG 0xd9
+#define SP_M_GEN_CLK_SEL BIT(0)
+
+/* AUX Channel Access Status Register */
+#define SP_AUX_CH_STATUS_REG 0xe0
+#define SP_AUX_STATUS 0x0f
+
+/* AUX Channel DEFER Control Register */
+#define SP_AUX_DEFER_CTRL_REG 0xe2
+#define SP_DEFER_CTRL_EN BIT(7)
+
+/* DP Buffer Data Count Register */
+#define SP_BUF_DATA_COUNT_REG 0xe4
+#define SP_BUF_DATA_COUNT_MASK 0x1f
+#define SP_BUF_CLR BIT(7)
+
+/* DP AUX Channel Control Register 1 */
+#define SP_DP_AUX_CH_CTRL1_REG 0xe5
+#define SP_AUX_TX_COMM_MASK 0x0f
+#define SP_AUX_LENGTH_MASK 0xf0
+#define SP_AUX_LENGTH_SHIFT 4
+
+/* DP AUX CH Address Register 0 */
+#define SP_AUX_ADDR_7_0_REG 0xe6
+
+/* DP AUX CH Address Register 1 */
+#define SP_AUX_ADDR_15_8_REG 0xe7
+
+/* DP AUX CH Address Register 2 */
+#define SP_AUX_ADDR_19_16_REG 0xe8
+#define SP_AUX_ADDR_19_16_MASK 0x0f
+
+/* DP AUX Channel Control Register 2 */
+#define SP_DP_AUX_CH_CTRL2_REG 0xe9
+#define SP_AUX_SEL_RXCM BIT(6)
+#define SP_AUX_CHSEL BIT(3)
+#define SP_AUX_PN_INV BIT(2)
+#define SP_ADDR_ONLY BIT(1)
+#define SP_AUX_EN BIT(0)
+
+/* DP Video Stream Control InfoFrame Register */
+#define SP_DP_3D_VSC_CTRL_REG 0xea
+#define SP_INFO_FRAME_VSC_EN BIT(0)
+
+/* DP Video Stream Data Byte 1 Register */
+#define SP_DP_VSC_DB1_REG 0xeb
+
+/* DP AUX Channel Control Register 3 */
+#define SP_DP_AUX_CH_CTRL3_REG 0xec
+#define SP_WAIT_COUNTER_7_0_MASK 0xff
+
+/* DP AUX Channel Control Register 4 */
+#define SP_DP_AUX_CH_CTRL4_REG 0xed
+
+/* DP AUX Buffer Data Registers */
+#define SP_DP_BUF_DATA0_REG 0xf0
+
+ssize_t anx_dp_aux_transfer(struct regmap *map_dptx,
+ struct drm_dp_aux_msg *msg);
+
+#endif
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-i2c-txcommon.h b/drivers/gpu/drm/bridge/analogix/analogix-i2c-txcommon.h
new file mode 100644
index 000000000000..3c843497d835
--- /dev/null
+++ b/drivers/gpu/drm/bridge/analogix/analogix-i2c-txcommon.h
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2016, Analogix Semiconductor. All rights reserved.
+ */
+#ifndef _ANALOGIX_I2C_TXCOMMON_H_
+#define _ANALOGIX_I2C_TXCOMMON_H_
+
+/***************************************************************/
+/* Register definitions for TX_P2 */
+/***************************************************************/
+
+/*
+ * Core Register Definitions
+ */
+
+/* Device ID Low Byte Register */
+#define SP_DEVICE_IDL_REG 0x02
+
+/* Device ID High Byte Register */
+#define SP_DEVICE_IDH_REG 0x03
+
+/* Device version register */
+#define SP_DEVICE_VERSION_REG 0x04
+
+/* Power Down Control Register */
+#define SP_POWERDOWN_CTRL_REG 0x05
+#define SP_REGISTER_PD BIT(7)
+#define SP_HDCP_PD BIT(5)
+#define SP_AUDIO_PD BIT(4)
+#define SP_VIDEO_PD BIT(3)
+#define SP_LINK_PD BIT(2)
+#define SP_TOTAL_PD BIT(1)
+
+/* Reset Control Register 1 */
+#define SP_RESET_CTRL1_REG 0x06
+#define SP_MISC_RST BIT(7)
+#define SP_VIDCAP_RST BIT(6)
+#define SP_VIDFIF_RST BIT(5)
+#define SP_AUDFIF_RST BIT(4)
+#define SP_AUDCAP_RST BIT(3)
+#define SP_HDCP_RST BIT(2)
+#define SP_SW_RST BIT(1)
+#define SP_HW_RST BIT(0)
+
+/* Reset Control Register 2 */
+#define SP_RESET_CTRL2_REG 0x07
+#define SP_AUX_RST BIT(2)
+#define SP_SERDES_FIFO_RST BIT(1)
+#define SP_I2C_REG_RST BIT(0)
+
+/* Video Control Register 1 */
+#define SP_VID_CTRL1_REG 0x08
+#define SP_VIDEO_EN BIT(7)
+#define SP_VIDEO_MUTE BIT(2)
+#define SP_DE_GEN BIT(1)
+#define SP_DEMUX BIT(0)
+
+/* Video Control Register 2 */
+#define SP_VID_CTRL2_REG 0x09
+#define SP_IN_COLOR_F_MASK 0x03
+#define SP_IN_YC_BIT_SEL BIT(2)
+#define SP_IN_BPC_MASK 0x70
+#define SP_IN_BPC_SHIFT 4
+# define SP_IN_BPC_12BIT 0x03
+# define SP_IN_BPC_10BIT 0x02
+# define SP_IN_BPC_8BIT 0x01
+# define SP_IN_BPC_6BIT 0x00
+#define SP_IN_D_RANGE BIT(7)
+
+/* Video Control Register 3 */
+#define SP_VID_CTRL3_REG 0x0a
+#define SP_HPD_OUT BIT(6)
+
+/* Video Control Register 5 */
+#define SP_VID_CTRL5_REG 0x0c
+#define SP_CSC_STD_SEL BIT(7)
+#define SP_XVYCC_RNG_LMT BIT(6)
+#define SP_RANGE_Y2R BIT(5)
+#define SP_CSPACE_Y2R BIT(4)
+#define SP_RGB_RNG_LMT BIT(3)
+#define SP_Y_RNG_LMT BIT(2)
+#define SP_RANGE_R2Y BIT(1)
+#define SP_CSPACE_R2Y BIT(0)
+
+/* Video Control Register 6 */
+#define SP_VID_CTRL6_REG 0x0d
+#define SP_TEST_PATTERN_EN BIT(7)
+#define SP_VIDEO_PROCESS_EN BIT(6)
+#define SP_VID_US_MODE BIT(3)
+#define SP_VID_DS_MODE BIT(2)
+#define SP_UP_SAMPLE BIT(1)
+#define SP_DOWN_SAMPLE BIT(0)
+
+/* Video Control Register 8 */
+#define SP_VID_CTRL8_REG 0x0f
+#define SP_VID_VRES_TH BIT(0)
+
+/* Total Line Status Low Byte Register */
+#define SP_TOTAL_LINE_STAL_REG 0x24
+
+/* Total Line Status High Byte Register */
+#define SP_TOTAL_LINE_STAH_REG 0x25
+
+/* Active Line Status Low Byte Register */
+#define SP_ACT_LINE_STAL_REG 0x26
+
+/* Active Line Status High Byte Register */
+#define SP_ACT_LINE_STAH_REG 0x27
+
+/* Vertical Front Porch Status Register */
+#define SP_V_F_PORCH_STA_REG 0x28
+
+/* Vertical SYNC Width Status Register */
+#define SP_V_SYNC_STA_REG 0x29
+
+/* Vertical Back Porch Status Register */
+#define SP_V_B_PORCH_STA_REG 0x2a
+
+/* Total Pixel Status Low Byte Register */
+#define SP_TOTAL_PIXEL_STAL_REG 0x2b
+
+/* Total Pixel Status High Byte Register */
+#define SP_TOTAL_PIXEL_STAH_REG 0x2c
+
+/* Active Pixel Status Low Byte Register */
+#define SP_ACT_PIXEL_STAL_REG 0x2d
+
+/* Active Pixel Status High Byte Register */
+#define SP_ACT_PIXEL_STAH_REG 0x2e
+
+/* Horizontal Front Porch Status Low Byte Register */
+#define SP_H_F_PORCH_STAL_REG 0x2f
+
+/* Horizontal Front Porch Statys High Byte Register */
+#define SP_H_F_PORCH_STAH_REG 0x30
+
+/* Horizontal SYNC Width Status Low Byte Register */
+#define SP_H_SYNC_STAL_REG 0x31
+
+/* Horizontal SYNC Width Status High Byte Register */
+#define SP_H_SYNC_STAH_REG 0x32
+
+/* Horizontal Back Porch Status Low Byte Register */
+#define SP_H_B_PORCH_STAL_REG 0x33
+
+/* Horizontal Back Porch Status High Byte Register */
+#define SP_H_B_PORCH_STAH_REG 0x34
+
+/* InfoFrame AVI Packet DB1 Register */
+#define SP_INFOFRAME_AVI_DB1_REG 0x70
+
+/* Bit Control Specific Register */
+#define SP_BIT_CTRL_SPECIFIC_REG 0x80
+#define SP_BIT_CTRL_SELECT_SHIFT 1
+#define SP_ENABLE_BIT_CTRL BIT(0)
+
+/* InfoFrame Audio Packet DB1 Register */
+#define SP_INFOFRAME_AUD_DB1_REG 0x83
+
+/* InfoFrame MPEG Packet DB1 Register */
+#define SP_INFOFRAME_MPEG_DB1_REG 0xb0
+
+/* Audio Channel Status Registers */
+#define SP_AUD_CH_STATUS_BASE 0xd0
+
+/* Audio Channel Num Register 5 */
+#define SP_I2S_CHANNEL_NUM_MASK 0xe0
+# define SP_I2S_CH_NUM_1 (0x00 << 5)
+# define SP_I2S_CH_NUM_2 (0x01 << 5)
+# define SP_I2S_CH_NUM_3 (0x02 << 5)
+# define SP_I2S_CH_NUM_4 (0x03 << 5)
+# define SP_I2S_CH_NUM_5 (0x04 << 5)
+# define SP_I2S_CH_NUM_6 (0x05 << 5)
+# define SP_I2S_CH_NUM_7 (0x06 << 5)
+# define SP_I2S_CH_NUM_8 (0x07 << 5)
+#define SP_EXT_VUCP BIT(2)
+#define SP_VBIT BIT(1)
+#define SP_AUDIO_LAYOUT BIT(0)
+
+/* Analog Debug Register 1 */
+#define SP_ANALOG_DEBUG1_REG 0xdc
+
+/* Analog Debug Register 2 */
+#define SP_ANALOG_DEBUG2_REG 0xdd
+#define SP_FORCE_SW_OFF_BYPASS 0x20
+#define SP_XTAL_FRQ 0x1c
+# define SP_XTAL_FRQ_19M2 (0x00 << 2)
+# define SP_XTAL_FRQ_24M (0x01 << 2)
+# define SP_XTAL_FRQ_25M (0x02 << 2)
+# define SP_XTAL_FRQ_26M (0x03 << 2)
+# define SP_XTAL_FRQ_27M (0x04 << 2)
+# define SP_XTAL_FRQ_38M4 (0x05 << 2)
+# define SP_XTAL_FRQ_52M (0x06 << 2)
+#define SP_POWERON_TIME_1P5MS 0x03
+
+/* Analog Control 0 Register */
+#define SP_ANALOG_CTRL0_REG 0xe1
+
+/* Common Interrupt Status Register 1 */
+#define SP_COMMON_INT_STATUS_BASE (0xf1 - 1)
+#define SP_PLL_LOCK_CHG 0x40
+
+/* Common Interrupt Status Register 2 */
+#define SP_COMMON_INT_STATUS2 0xf2
+#define SP_HDCP_AUTH_CHG BIT(1)
+#define SP_HDCP_AUTH_DONE BIT(0)
+
+#define SP_HDCP_LINK_CHECK_FAIL BIT(0)
+
+/* Common Interrupt Status Register 4 */
+#define SP_COMMON_INT_STATUS4_REG 0xf4
+#define SP_HPD_IRQ BIT(6)
+#define SP_HPD_ESYNC_ERR BIT(4)
+#define SP_HPD_CHG BIT(2)
+#define SP_HPD_LOST BIT(1)
+#define SP_HPD_PLUG BIT(0)
+
+/* DP Interrupt Status Register */
+#define SP_DP_INT_STATUS1_REG 0xf7
+#define SP_TRAINING_FINISH BIT(5)
+#define SP_POLLING_ERR BIT(4)
+
+/* Common Interrupt Mask Register */
+#define SP_COMMON_INT_MASK_BASE (0xf8 - 1)
+
+#define SP_COMMON_INT_MASK4_REG 0xfb
+
+/* DP Interrupts Mask Register */
+#define SP_DP_INT_MASK1_REG 0xfe
+
+/* Interrupt Control Register */
+#define SP_INT_CTRL_REG 0xff
+
+#endif /* _ANALOGIX_I2C_TXCOMMON_H_ */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index bb411fe52ae8..6effe532f820 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1111,7 +1111,7 @@ static int analogix_dp_get_modes(struct drm_connector *connector)
int ret, num_modes = 0;
if (dp->plat_data->panel) {
- num_modes += drm_panel_get_modes(dp->plat_data->panel);
+ num_modes += drm_panel_get_modes(dp->plat_data->panel, connector);
} else {
ret = analogix_dp_prepare_panel(dp, true, false);
if (ret) {
diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c
index 3a5bd4e7fd1e..b7c97f060241 100644
--- a/drivers/gpu/drm/bridge/cdns-dsi.c
+++ b/drivers/gpu/drm/bridge/cdns-dsi.c
@@ -512,7 +512,7 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi,
struct cdns_dsi_output *output = &dsi->output;
unsigned int tmp;
bool sync_pulse = false;
- int bpp, nlanes;
+ int bpp;
memset(dsi_cfg, 0, sizeof(*dsi_cfg));
@@ -520,7 +520,6 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi,
sync_pulse = true;
bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format);
- nlanes = output->dev->lanes;
if (mode_valid_check)
tmp = mode->htotal -
@@ -785,13 +784,12 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
unsigned long tx_byte_period;
struct cdns_dsi_cfg dsi_cfg;
u32 tmp, reg_wakeup, div;
- int bpp, nlanes;
+ int nlanes;
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
return;
mode = &bridge->encoder->crtc->state->adjusted_mode;
- bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format);
nlanes = output->dev->lanes;
WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false));
diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c
new file mode 100644
index 000000000000..5f04cc11227e
--- /dev/null
+++ b/drivers/gpu/drm/bridge/lvds-codec.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Renesas Electronics Corporation
+ * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
+
+struct lvds_codec {
+ struct drm_bridge bridge;
+ struct drm_bridge *panel_bridge;
+ struct gpio_desc *powerdown_gpio;
+ u32 connector_type;
+};
+
+static int lvds_codec_attach(struct drm_bridge *bridge)
+{
+ struct lvds_codec *lvds_codec = container_of(bridge,
+ struct lvds_codec, bridge);
+
+ return drm_bridge_attach(bridge->encoder, lvds_codec->panel_bridge,
+ bridge);
+}
+
+static void lvds_codec_enable(struct drm_bridge *bridge)
+{
+ struct lvds_codec *lvds_codec = container_of(bridge,
+ struct lvds_codec, bridge);
+
+ if (lvds_codec->powerdown_gpio)
+ gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0);
+}
+
+static void lvds_codec_disable(struct drm_bridge *bridge)
+{
+ struct lvds_codec *lvds_codec = container_of(bridge,
+ struct lvds_codec, bridge);
+
+ if (lvds_codec->powerdown_gpio)
+ gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1);
+}
+
+static struct drm_bridge_funcs funcs = {
+ .attach = lvds_codec_attach,
+ .enable = lvds_codec_enable,
+ .disable = lvds_codec_disable,
+};
+
+static int lvds_codec_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *panel_node;
+ struct drm_panel *panel;
+ struct lvds_codec *lvds_codec;
+
+ lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
+ if (!lvds_codec)
+ return -ENOMEM;
+
+ lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
+ lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(lvds_codec->powerdown_gpio)) {
+ int err = PTR_ERR(lvds_codec->powerdown_gpio);
+
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "powerdown GPIO failure: %d\n", err);
+ return err;
+ }
+
+ /* Locate the panel DT node. */
+ panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
+ if (!panel_node) {
+ dev_dbg(dev, "panel DT node not found\n");
+ return -ENXIO;
+ }
+
+ panel = of_drm_find_panel(panel_node);
+ of_node_put(panel_node);
+ if (IS_ERR(panel)) {
+ dev_dbg(dev, "panel not found, deferring probe\n");
+ return PTR_ERR(panel);
+ }
+
+ lvds_codec->panel_bridge =
+ devm_drm_panel_bridge_add_typed(dev, panel,
+ lvds_codec->connector_type);
+ if (IS_ERR(lvds_codec->panel_bridge))
+ return PTR_ERR(lvds_codec->panel_bridge);
+
+ /*
+ * The panel_bridge bridge is attached to the panel's of_node,
+ * but we need a bridge attached to our of_node for our user
+ * to look up.
+ */
+ lvds_codec->bridge.of_node = dev->of_node;
+ lvds_codec->bridge.funcs = &funcs;
+ drm_bridge_add(&lvds_codec->bridge);
+
+ platform_set_drvdata(pdev, lvds_codec);
+
+ return 0;
+}
+
+static int lvds_codec_remove(struct platform_device *pdev)
+{
+ struct lvds_codec *lvds_codec = platform_get_drvdata(pdev);
+
+ drm_bridge_remove(&lvds_codec->bridge);
+
+ return 0;
+}
+
+static const struct of_device_id lvds_codec_match[] = {
+ {
+ .compatible = "lvds-decoder",
+ .data = (void *)DRM_MODE_CONNECTOR_DPI,
+ },
+ {
+ .compatible = "lvds-encoder",
+ .data = (void *)DRM_MODE_CONNECTOR_LVDS,
+ },
+ {
+ .compatible = "thine,thc63lvdm83d",
+ .data = (void *)DRM_MODE_CONNECTOR_LVDS,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lvds_codec_match);
+
+static struct platform_driver lvds_codec_driver = {
+ .probe = lvds_codec_probe,
+ .remove = lvds_codec_remove,
+ .driver = {
+ .name = "lvds-codec",
+ .of_match_table = lvds_codec_match,
+ },
+};
+module_platform_driver(lvds_codec_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("LVDS encoders and decoders");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
deleted file mode 100644
index e2132a8d5106..000000000000
--- a/drivers/gpu/drm/bridge/lvds-encoder.c
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- */
-
-#include <linux/gpio/consumer.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
-#include <linux/platform_device.h>
-
-#include <drm/drm_bridge.h>
-#include <drm/drm_panel.h>
-
-struct lvds_encoder {
- struct drm_bridge bridge;
- struct drm_bridge *panel_bridge;
- struct gpio_desc *powerdown_gpio;
-};
-
-static int lvds_encoder_attach(struct drm_bridge *bridge)
-{
- struct lvds_encoder *lvds_encoder = container_of(bridge,
- struct lvds_encoder,
- bridge);
-
- return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge,
- bridge);
-}
-
-static void lvds_encoder_enable(struct drm_bridge *bridge)
-{
- struct lvds_encoder *lvds_encoder = container_of(bridge,
- struct lvds_encoder,
- bridge);
-
- if (lvds_encoder->powerdown_gpio)
- gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0);
-}
-
-static void lvds_encoder_disable(struct drm_bridge *bridge)
-{
- struct lvds_encoder *lvds_encoder = container_of(bridge,
- struct lvds_encoder,
- bridge);
-
- if (lvds_encoder->powerdown_gpio)
- gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1);
-}
-
-static struct drm_bridge_funcs funcs = {
- .attach = lvds_encoder_attach,
- .enable = lvds_encoder_enable,
- .disable = lvds_encoder_disable,
-};
-
-static int lvds_encoder_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *port;
- struct device_node *endpoint;
- struct device_node *panel_node;
- struct drm_panel *panel;
- struct lvds_encoder *lvds_encoder;
-
- lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL);
- if (!lvds_encoder)
- return -ENOMEM;
-
- lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
- GPIOD_OUT_HIGH);
- if (IS_ERR(lvds_encoder->powerdown_gpio)) {
- int err = PTR_ERR(lvds_encoder->powerdown_gpio);
-
- if (err != -EPROBE_DEFER)
- dev_err(dev, "powerdown GPIO failure: %d\n", err);
- return err;
- }
-
- /* Locate the panel DT node. */
- port = of_graph_get_port_by_id(dev->of_node, 1);
- if (!port) {
- dev_dbg(dev, "port 1 not found\n");
- return -ENXIO;
- }
-
- endpoint = of_get_child_by_name(port, "endpoint");
- of_node_put(port);
- if (!endpoint) {
- dev_dbg(dev, "no endpoint for port 1\n");
- return -ENXIO;
- }
-
- panel_node = of_graph_get_remote_port_parent(endpoint);
- of_node_put(endpoint);
- if (!panel_node) {
- dev_dbg(dev, "no remote endpoint for port 1\n");
- return -ENXIO;
- }
-
- panel = of_drm_find_panel(panel_node);
- of_node_put(panel_node);
- if (IS_ERR(panel)) {
- dev_dbg(dev, "panel not found, deferring probe\n");
- return PTR_ERR(panel);
- }
-
- lvds_encoder->panel_bridge =
- devm_drm_panel_bridge_add_typed(dev, panel,
- DRM_MODE_CONNECTOR_LVDS);
- if (IS_ERR(lvds_encoder->panel_bridge))
- return PTR_ERR(lvds_encoder->panel_bridge);
-
- /* The panel_bridge bridge is attached to the panel's of_node,
- * but we need a bridge attached to our of_node for our user
- * to look up.
- */
- lvds_encoder->bridge.of_node = dev->of_node;
- lvds_encoder->bridge.funcs = &funcs;
- drm_bridge_add(&lvds_encoder->bridge);
-
- platform_set_drvdata(pdev, lvds_encoder);
-
- return 0;
-}
-
-static int lvds_encoder_remove(struct platform_device *pdev)
-{
- struct lvds_encoder *lvds_encoder = platform_get_drvdata(pdev);
-
- drm_bridge_remove(&lvds_encoder->bridge);
-
- return 0;
-}
-
-static const struct of_device_id lvds_encoder_match[] = {
- { .compatible = "lvds-encoder" },
- { .compatible = "thine,thc63lvdm83d" },
- {},
-};
-MODULE_DEVICE_TABLE(of, lvds_encoder_match);
-
-static struct platform_driver lvds_encoder_driver = {
- .probe = lvds_encoder_probe,
- .remove = lvds_encoder_remove,
- .driver = {
- .name = "lvds-encoder",
- .of_match_table = lvds_encoder_match,
- },
-};
-module_platform_driver(lvds_encoder_driver);
-
-MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
-MODULE_DESCRIPTION("Transparent parallel to LVDS encoder");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index f4e293e7cf64..f66777e24968 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -37,7 +37,7 @@ static int panel_bridge_connector_get_modes(struct drm_connector *connector)
struct panel_bridge *panel_bridge =
drm_connector_to_panel_bridge(connector);
- return drm_panel_get_modes(panel_bridge->panel);
+ return drm_panel_get_modes(panel_bridge->panel, connector);
}
static const struct drm_connector_helper_funcs
@@ -289,3 +289,21 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
return bridge;
}
EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
+
+/**
+ * drm_panel_bridge_connector - return the connector for the panel bridge
+ *
+ * drm_panel_bridge creates the connector.
+ * This function gives external access to the connector.
+ *
+ * Returns: Pointer to drm_connector
+ */
+struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
+{
+ struct panel_bridge *panel_bridge;
+
+ panel_bridge = drm_bridge_to_panel_bridge(bridge);
+
+ return &panel_bridge->connector;
+}
+EXPORT_SYMBOL(drm_panel_bridge_connector);
diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
index b7a72dfdcac3..10c47c008b40 100644
--- a/drivers/gpu/drm/bridge/parade-ps8622.c
+++ b/drivers/gpu/drm/bridge/parade-ps8622.c
@@ -461,7 +461,7 @@ static int ps8622_get_modes(struct drm_connector *connector)
ps8622 = connector_to_ps8622(connector);
- return drm_panel_get_modes(ps8622->panel);
+ return drm_panel_get_modes(ps8622->panel, connector);
}
static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
index 2b7539701b42..dd56996fe9c7 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c
@@ -291,7 +291,7 @@ static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static struct snd_pcm_hardware dw_hdmi_hw = {
+static const struct snd_pcm_hardware dw_hdmi_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index b6e793bb653c..b18351b6760a 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -719,7 +719,15 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi,
static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
{
+ const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
+ struct dw_mipi_dsi_dphy_timing timing;
u32 hw_version;
+ int ret;
+
+ ret = phy_ops->get_timing(dsi->plat_data->priv_data,
+ dsi->lane_mbps, &timing);
+ if (ret)
+ DRM_DEV_ERROR(dsi->dev, "Retrieving phy timings failed\n");
/*
* TODO dw drv improvements
@@ -732,16 +740,20 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
if (hw_version >= HWVER_131) {
- dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) |
- PHY_LP2HS_TIME_V131(0x40));
+ dsi_write(dsi, DSI_PHY_TMR_CFG,
+ PHY_HS2LP_TIME_V131(timing.data_hs2lp) |
+ PHY_LP2HS_TIME_V131(timing.data_lp2hs));
dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000));
} else {
- dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) |
- PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
+ dsi_write(dsi, DSI_PHY_TMR_CFG,
+ PHY_HS2LP_TIME(timing.data_hs2lp) |
+ PHY_LP2HS_TIME(timing.data_lp2hs) |
+ MAX_RD_TIME(10000));
}
- dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40)
- | PHY_CLKLP2HS_TIME(0x40));
+ dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG,
+ PHY_CLKHS2LP_TIME(timing.clk_hs2lp) |
+ PHY_CLKLP2HS_TIME(timing.clk_lp2hs));
}
static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
@@ -798,9 +810,6 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
- if (phy_ops->power_off)
- phy_ops->power_off(dsi->plat_data->priv_data);
-
/*
* Switch to command mode before panel-bridge post_disable &
* panel unprepare.
@@ -817,6 +826,9 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
*/
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
+ if (phy_ops->power_off)
+ phy_ops->power_off(dsi->plat_data->priv_data);
+
if (dsi->slave) {
dw_mipi_dsi_disable(dsi->slave);
clk_disable_unprepare(dsi->slave->pclk);
@@ -883,6 +895,9 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
/* Switch to cmd mode for panel-bridge pre_enable & panel prepare */
dw_mipi_dsi_set_mode(dsi, 0);
+
+ if (phy_ops->power_on)
+ phy_ops->power_on(dsi->plat_data->priv_data);
}
static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
@@ -899,15 +914,11 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
- const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
/* Switch to video mode for panel-bridge enable & panel enable */
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
if (dsi->slave)
dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
-
- if (phy_ops->power_on)
- phy_ops->power_on(dsi->plat_data->priv_data);
}
static enum drm_mode_status
@@ -991,7 +1002,8 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
dsi->dev = dev;
dsi->plat_data = plat_data;
- if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps) {
+ if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps ||
+ !plat_data->phy_ops->get_timing) {
DRM_ERROR("Phy not properly configured\n");
return ERR_PTR(-ENODEV);
}
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
index db298f550a5a..96207fcfde19 100644
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -282,7 +282,7 @@ static int tc358764_get_modes(struct drm_connector *connector)
{
struct tc358764 *ctx = connector_to_tc358764(connector);
- return drm_panel_get_modes(ctx->panel);
+ return drm_panel_get_modes(ctx->panel, connector);
}
static const
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 8029478ffebb..3709e5ace724 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1346,7 +1346,7 @@ static int tc_connector_get_modes(struct drm_connector *connector)
return 0;
}
- count = drm_panel_get_modes(tc->panel);
+ count = drm_panel_get_modes(tc->panel, connector);
if (count > 0)
return count;
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 43abf01ebd4c..9a2dd986afa5 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -206,7 +206,7 @@ static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector)
{
struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector);
- return drm_panel_get_modes(pdata->panel);
+ return drm_panel_get_modes(pdata->panel, connector);
}
static enum drm_mode_status