mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-18 12:30:31 +00:00
media: platform: synopsys: Add support for HDMI input driver
Add initial support for the Synopsys DesignWare HDMI RX Controller Driver used by Rockchip RK3588. The driver supports: - HDMI 1.4b and 2.0 modes (HDMI 4k@60Hz) - RGB888, YUV422, YUV444 and YCC420 pixel formats - CEC - EDID configuration The hardware also has Audio and HDCP capabilities, but these are not yet supported by the driver. Co-developed-by: Dingxian Wen <shawn.wen@rock-chips.com> Signed-off-by: Dingxian Wen <shawn.wen@rock-chips.com> Signed-off-by: Shreeya Patel <shreeya.patel@collabora.com> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
This commit is contained in:
parent
9436332618
commit
7b59b132ad
10 changed files with 3508 additions and 0 deletions
|
@ -85,6 +85,7 @@ source "drivers/media/platform/rockchip/Kconfig"
|
|||
source "drivers/media/platform/samsung/Kconfig"
|
||||
source "drivers/media/platform/st/Kconfig"
|
||||
source "drivers/media/platform/sunxi/Kconfig"
|
||||
source "drivers/media/platform/synopsys/Kconfig"
|
||||
source "drivers/media/platform/ti/Kconfig"
|
||||
source "drivers/media/platform/verisilicon/Kconfig"
|
||||
source "drivers/media/platform/via/Kconfig"
|
||||
|
|
|
@ -28,6 +28,7 @@ obj-y += rockchip/
|
|||
obj-y += samsung/
|
||||
obj-y += st/
|
||||
obj-y += sunxi/
|
||||
obj-y += synopsys/
|
||||
obj-y += ti/
|
||||
obj-y += verisilicon/
|
||||
obj-y += via/
|
||||
|
|
3
drivers/media/platform/synopsys/Kconfig
Normal file
3
drivers/media/platform/synopsys/Kconfig
Normal file
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
source "drivers/media/platform/synopsys/hdmirx/Kconfig"
|
2
drivers/media/platform/synopsys/Makefile
Normal file
2
drivers/media/platform/synopsys/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y += hdmirx/
|
35
drivers/media/platform/synopsys/hdmirx/Kconfig
Normal file
35
drivers/media/platform/synopsys/hdmirx/Kconfig
Normal file
|
@ -0,0 +1,35 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config VIDEO_SYNOPSYS_HDMIRX
|
||||
tristate "Synopsys DesignWare HDMI Receiver driver"
|
||||
depends on VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select CEC_CORE
|
||||
select HDMI
|
||||
help
|
||||
Support for Synopsys HDMI HDMI RX Controller.
|
||||
This driver supports HDMI 2.0 version.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called synopsys_hdmirx.
|
||||
|
||||
config VIDEO_SYNOPSYS_HDMIRX_LOAD_DEFAULT_EDID
|
||||
bool "Load default EDID"
|
||||
depends on VIDEO_SYNOPSYS_HDMIRX
|
||||
help
|
||||
Preload default EDID (Extended Display Identification Data)
|
||||
branded by Linux Foundation that exposes display modes up
|
||||
to 4k@30Hz, which have best compatibility with HDMI transmitters.
|
||||
|
||||
Enabling this option is recommended for a non-production use-cases.
|
||||
It will make driver usable out-of-the-box.
|
||||
|
||||
For a higher display modes you will need to load customized EDID
|
||||
from userspace using v4l2-ctl tool or by other means.
|
||||
|
||||
Without enabling this option driver will be practically
|
||||
non-functional until EDID will be loaded from userspace.
|
||||
Which is a wanted behavior when using this driver in a
|
||||
commercial product that should utilize own branded EDID.
|
4
drivers/media/platform/synopsys/hdmirx/Makefile
Normal file
4
drivers/media/platform/synopsys/hdmirx/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
synopsys-hdmirx-objs := snps_hdmirx.o snps_hdmirx_cec.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_SYNOPSYS_HDMIRX) += synopsys-hdmirx.o
|
2750
drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
Normal file
2750
drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
Normal file
File diff suppressed because it is too large
Load diff
394
drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h
Normal file
394
drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h
Normal file
|
@ -0,0 +1,394 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Dingxian Wen <shawn.wen@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef DW_HDMIRX_H
|
||||
#define DW_HDMIRX_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
|
||||
#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16))
|
||||
|
||||
/* SYS_GRF */
|
||||
#define SYS_GRF_SOC_CON1 0x0304
|
||||
#define HDMIRXPHY_SRAM_EXT_LD_DONE BIT(1)
|
||||
#define HDMIRXPHY_SRAM_BYPASS BIT(0)
|
||||
#define SYS_GRF_SOC_STATUS1 0x0384
|
||||
#define HDMIRXPHY_SRAM_INIT_DONE BIT(10)
|
||||
#define SYS_GRF_CHIP_ID 0x0600
|
||||
|
||||
/* VO1_GRF */
|
||||
#define VO1_GRF_VO1_CON2 0x0008
|
||||
#define HDMIRX_SDAIN_MSK BIT(2)
|
||||
#define HDMIRX_SCLIN_MSK BIT(1)
|
||||
|
||||
/* HDMIRX PHY */
|
||||
#define SUP_DIG_ANA_CREGS_SUP_ANA_NC 0x004f
|
||||
|
||||
#define LANE0_DIG_ASIC_RX_OVRD_OUT_0 0x100f
|
||||
#define LANE1_DIG_ASIC_RX_OVRD_OUT_0 0x110f
|
||||
#define LANE2_DIG_ASIC_RX_OVRD_OUT_0 0x120f
|
||||
#define LANE3_DIG_ASIC_RX_OVRD_OUT_0 0x130f
|
||||
#define ASIC_ACK_OVRD_EN BIT(1)
|
||||
#define ASIC_ACK BIT(0)
|
||||
|
||||
#define LANE0_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x104a
|
||||
#define LANE1_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x114a
|
||||
#define LANE2_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x124a
|
||||
#define LANE3_DIG_RX_VCOCAL_RX_VCO_CAL_CTRL_2 0x134a
|
||||
#define FREQ_TUNE_START_VAL_MASK GENMASK(9, 0)
|
||||
#define FREQ_TUNE_START_VAL(x) UPDATE(x, 9, 0)
|
||||
|
||||
#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_FSM_CONFIG 0x20c4
|
||||
#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_ADAPT_REF_FOM 0x20c7
|
||||
#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG 0x20e9
|
||||
#define CDR_SETTING_BOUNDARY_3_DEFAULT 0x52da
|
||||
#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG 0x20ea
|
||||
#define CDR_SETTING_BOUNDARY_4_DEFAULT 0x43cd
|
||||
#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG 0x20eb
|
||||
#define CDR_SETTING_BOUNDARY_5_DEFAULT 0x35b3
|
||||
#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG 0x20fb
|
||||
#define CDR_SETTING_BOUNDARY_6_DEFAULT 0x2799
|
||||
#define HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG 0x20fc
|
||||
#define CDR_SETTING_BOUNDARY_7_DEFAULT 0x1b65
|
||||
|
||||
#define RAWLANE0_DIG_PCS_XF_RX_OVRD_OUT 0x300e
|
||||
#define RAWLANE1_DIG_PCS_XF_RX_OVRD_OUT 0x310e
|
||||
#define RAWLANE2_DIG_PCS_XF_RX_OVRD_OUT 0x320e
|
||||
#define RAWLANE3_DIG_PCS_XF_RX_OVRD_OUT 0x330e
|
||||
#define PCS_ACK_WRITE_SELECT BIT(14)
|
||||
#define PCS_EN_CTL BIT(1)
|
||||
#define PCS_ACK BIT(0)
|
||||
|
||||
#define RAWLANE0_DIG_AON_FAST_FLAGS 0x305c
|
||||
#define RAWLANE1_DIG_AON_FAST_FLAGS 0x315c
|
||||
#define RAWLANE2_DIG_AON_FAST_FLAGS 0x325c
|
||||
#define RAWLANE3_DIG_AON_FAST_FLAGS 0x335c
|
||||
|
||||
/* HDMIRX Ctrler */
|
||||
#define GLOBAL_SWRESET_REQUEST 0x0020
|
||||
#define DATAPATH_SWRESETREQ BIT(12)
|
||||
#define GLOBAL_SWENABLE 0x0024
|
||||
#define PHYCTRL_ENABLE BIT(21)
|
||||
#define CEC_ENABLE BIT(16)
|
||||
#define TMDS_ENABLE BIT(13)
|
||||
#define DATAPATH_ENABLE BIT(12)
|
||||
#define PKTFIFO_ENABLE BIT(11)
|
||||
#define AVPUNIT_ENABLE BIT(8)
|
||||
#define MAIN_ENABLE BIT(0)
|
||||
#define GLOBAL_TIMER_REF_BASE 0x0028
|
||||
#define CORE_CONFIG 0x0050
|
||||
#define CMU_CONFIG0 0x0060
|
||||
#define TMDSQPCLK_STABLE_FREQ_MARGIN_MASK GENMASK(30, 16)
|
||||
#define TMDSQPCLK_STABLE_FREQ_MARGIN(x) UPDATE(x, 30, 16)
|
||||
#define AUDCLK_STABLE_FREQ_MARGIN_MASK GENMASK(11, 9)
|
||||
#define AUDCLK_STABLE_FREQ_MARGIN(x) UPDATE(x, 11, 9)
|
||||
#define CMU_STATUS 0x007c
|
||||
#define TMDSQPCLK_LOCKED_ST BIT(4)
|
||||
#define CMU_TMDSQPCLK_FREQ 0x0084
|
||||
#define PHY_CONFIG 0x00c0
|
||||
#define LDO_AFE_PROG_MASK GENMASK(24, 23)
|
||||
#define LDO_AFE_PROG(x) UPDATE(x, 24, 23)
|
||||
#define LDO_PWRDN BIT(21)
|
||||
#define TMDS_CLOCK_RATIO BIT(16)
|
||||
#define RXDATA_WIDTH BIT(15)
|
||||
#define REFFREQ_SEL_MASK GENMASK(11, 9)
|
||||
#define REFFREQ_SEL(x) UPDATE(x, 11, 9)
|
||||
#define HDMI_DISABLE BIT(8)
|
||||
#define PHY_PDDQ BIT(1)
|
||||
#define PHY_RESET BIT(0)
|
||||
#define PHY_STATUS 0x00c8
|
||||
#define HDMI_DISABLE_ACK BIT(1)
|
||||
#define PDDQ_ACK BIT(0)
|
||||
#define PHYCREG_CONFIG0 0x00e0
|
||||
#define PHYCREG_CR_PARA_SELECTION_MODE_MASK GENMASK(1, 0)
|
||||
#define PHYCREG_CR_PARA_SELECTION_MODE(x) UPDATE(x, 1, 0)
|
||||
#define PHYCREG_CONFIG1 0x00e4
|
||||
#define PHYCREG_CONFIG2 0x00e8
|
||||
#define PHYCREG_CONFIG3 0x00ec
|
||||
#define PHYCREG_CONTROL 0x00f0
|
||||
#define PHYCREG_CR_PARA_WRITE_P BIT(1)
|
||||
#define PHYCREG_CR_PARA_READ_P BIT(0)
|
||||
#define PHYCREG_STATUS 0x00f4
|
||||
|
||||
#define MAINUNIT_STATUS 0x0150
|
||||
#define TMDSVALID_STABLE_ST BIT(1)
|
||||
#define DESCRAND_EN_CONTROL 0x0210
|
||||
#define SCRAMB_EN_SEL_QST_MASK GENMASK(1, 0)
|
||||
#define SCRAMB_EN_SEL_QST(x) UPDATE(x, 1, 0)
|
||||
#define DESCRAND_SYNC_CONTROL 0x0214
|
||||
#define RECOVER_UNSYNC_STREAM_QST BIT(0)
|
||||
#define DESCRAND_SYNC_SEQ_CONFIG 0x022c
|
||||
#define DESCRAND_SYNC_SEQ_ERR_CNT_EN BIT(0)
|
||||
#define DESCRAND_SYNC_SEQ_STATUS 0x0234
|
||||
#define DEFRAMER_CONFIG0 0x0270
|
||||
#define VS_CNT_THR_QST_MASK GENMASK(27, 20)
|
||||
#define VS_CNT_THR_QST(x) UPDATE(x, 27, 20)
|
||||
#define HS_POL_QST_MASK GENMASK(19, 18)
|
||||
#define HS_POL_QST(x) UPDATE(x, 19, 18)
|
||||
#define VS_POL_QST_MASK GENMASK(17, 16)
|
||||
#define VS_POL_QST(x) UPDATE(x, 17, 16)
|
||||
#define VS_REMAPFILTER_EN_QST BIT(8)
|
||||
#define VS_FILTER_ORDER_QST_MASK GENMASK(1, 0)
|
||||
#define VS_FILTER_ORDER_QST(x) UPDATE(x, 1, 0)
|
||||
#define DEFRAMER_VSYNC_CNT_CLEAR 0x0278
|
||||
#define VSYNC_CNT_CLR_P BIT(0)
|
||||
#define DEFRAMER_STATUS 0x027c
|
||||
#define OPMODE_STS_MASK GENMASK(6, 4)
|
||||
#define I2C_SLAVE_CONFIG1 0x0164
|
||||
#define I2C_SDA_OUT_HOLD_VALUE_QST_MASK GENMASK(15, 8)
|
||||
#define I2C_SDA_OUT_HOLD_VALUE_QST(x) UPDATE(x, 15, 8)
|
||||
#define I2C_SDA_IN_HOLD_VALUE_QST_MASK GENMASK(7, 0)
|
||||
#define I2C_SDA_IN_HOLD_VALUE_QST(x) UPDATE(x, 7, 0)
|
||||
#define OPMODE_STS_MASK GENMASK(6, 4)
|
||||
#define REPEATER_QST BIT(28)
|
||||
#define FASTREAUTH_QST BIT(27)
|
||||
#define FEATURES_1DOT1_QST BIT(26)
|
||||
#define FASTI2C_QST BIT(25)
|
||||
#define EESS_CTL_THR_QST_MASK GENMASK(19, 16)
|
||||
#define EESS_CTL_THR_QST(x) UPDATE(x, 19, 16)
|
||||
#define OESS_CTL3_THR_QST_MASK GENMASK(11, 8)
|
||||
#define OESS_CTL3_THR_QST(x) UPDATE(x, 11, 8)
|
||||
#define EESS_OESS_SEL_QST_MASK GENMASK(5, 4)
|
||||
#define EESS_OESS_SEL_QST(x) UPDATE(x, 5, 4)
|
||||
#define KEY_DECRYPT_EN_QST BIT(0)
|
||||
#define KEY_DECRYPT_SEED_QST_MASK GENMASK(15, 0)
|
||||
#define KEY_DECRYPT_SEED_QST(x) UPDATE(x, 15, 0)
|
||||
#define HDCP_INT_CLEAR 0x50d8
|
||||
#define HDCP_1_INT_CLEAR 0x50e8
|
||||
#define HDCP2_CONFIG 0x02f0
|
||||
#define HDCP2_SWITCH_OVR_VALUE BIT(2)
|
||||
#define HDCP2_SWITCH_OVR_EN BIT(1)
|
||||
|
||||
#define VIDEO_CONFIG2 0x042c
|
||||
#define VPROC_VSYNC_POL_OVR_VALUE BIT(19)
|
||||
#define VPROC_VSYNC_POL_OVR_EN BIT(18)
|
||||
#define VPROC_HSYNC_POL_OVR_VALUE BIT(17)
|
||||
#define VPROC_HSYNC_POL_OVR_EN BIT(16)
|
||||
#define VPROC_FMT_OVR_VALUE_MASK GENMASK(6, 4)
|
||||
#define VPROC_FMT_OVR_VALUE(x) UPDATE(x, 6, 4)
|
||||
#define VPROC_FMT_OVR_EN BIT(0)
|
||||
|
||||
#define AFIFO_FILL_RESTART BIT(0)
|
||||
#define AFIFO_INIT_P BIT(0)
|
||||
#define AFIFO_THR_LOW_QST_MASK GENMASK(25, 16)
|
||||
#define AFIFO_THR_LOW_QST(x) UPDATE(x, 25, 16)
|
||||
#define AFIFO_THR_HIGH_QST_MASK GENMASK(9, 0)
|
||||
#define AFIFO_THR_HIGH_QST(x) UPDATE(x, 9, 0)
|
||||
#define AFIFO_THR_MUTE_LOW_QST_MASK GENMASK(25, 16)
|
||||
#define AFIFO_THR_MUTE_LOW_QST(x) UPDATE(x, 25, 16)
|
||||
#define AFIFO_THR_MUTE_HIGH_QST_MASK GENMASK(9, 0)
|
||||
#define AFIFO_THR_MUTE_HIGH_QST(x) UPDATE(x, 9, 0)
|
||||
|
||||
#define AFIFO_UNDERFLOW_ST BIT(25)
|
||||
#define AFIFO_OVERFLOW_ST BIT(24)
|
||||
|
||||
#define SPEAKER_ALLOC_OVR_EN BIT(16)
|
||||
#define I2S_BPCUV_EN BIT(4)
|
||||
#define SPDIF_EN BIT(2)
|
||||
#define I2S_EN BIT(1)
|
||||
#define AFIFO_THR_PASS_DEMUTEMASK_N BIT(24)
|
||||
#define AVMUTE_DEMUTEMASK_N BIT(16)
|
||||
#define AFIFO_THR_MUTE_LOW_MUTEMASK_N BIT(9)
|
||||
#define AFIFO_THR_MUTE_HIGH_MUTEMASK_N BIT(8)
|
||||
#define AVMUTE_MUTEMASK_N BIT(0)
|
||||
#define SCDC_CONFIG 0x0580
|
||||
#define HPDLOW BIT(1)
|
||||
#define POWERPROVIDED BIT(0)
|
||||
#define SCDC_REGBANK_STATUS1 0x058c
|
||||
#define SCDC_TMDSBITCLKRATIO BIT(1)
|
||||
#define SCDC_REGBANK_STATUS3 0x0594
|
||||
#define SCDC_REGBANK_CONFIG0 0x05c0
|
||||
#define SCDC_SINKVERSION_QST_MASK GENMASK(7, 0)
|
||||
#define SCDC_SINKVERSION_QST(x) UPDATE(x, 7, 0)
|
||||
#define AGEN_LAYOUT BIT(4)
|
||||
#define AGEN_SPEAKER_ALLOC GENMASK(15, 8)
|
||||
|
||||
#define CED_CONFIG 0x0760
|
||||
#define CED_VIDDATACHECKEN_QST BIT(27)
|
||||
#define CED_DATAISCHECKEN_QST BIT(26)
|
||||
#define CED_GBCHECKEN_QST BIT(25)
|
||||
#define CED_CTRLCHECKEN_QST BIT(24)
|
||||
#define CED_CHLOCKMAXER_QST_MASK GENMASK(14, 0)
|
||||
#define CED_CHLOCKMAXER_QST(x) UPDATE(x, 14, 0)
|
||||
#define CED_DYN_CONFIG 0x0768
|
||||
#define CED_DYN_CONTROL 0x076c
|
||||
#define PKTEX_BCH_ERRFILT_CONFIG 0x07c4
|
||||
#define PKTEX_CHKSUM_ERRFILT_CONFIG 0x07c8
|
||||
|
||||
#define PKTDEC_ACR_PH2_1 0x1100
|
||||
#define PKTDEC_ACR_PB3_0 0x1104
|
||||
#define PKTDEC_ACR_PB7_4 0x1108
|
||||
#define PKTDEC_AVIIF_PH2_1 0x1200
|
||||
#define PKTDEC_AVIIF_PB3_0 0x1204
|
||||
#define PKTDEC_AVIIF_PB7_4 0x1208
|
||||
#define VIC_VAL_MASK GENMASK(6, 0)
|
||||
#define PKTDEC_AVIIF_PB11_8 0x120c
|
||||
#define PKTDEC_AVIIF_PB15_12 0x1210
|
||||
#define PKTDEC_AVIIF_PB19_16 0x1214
|
||||
#define PKTDEC_AVIIF_PB23_20 0x1218
|
||||
#define PKTDEC_AVIIF_PB27_24 0x121c
|
||||
|
||||
#define PKTFIFO_CONFIG 0x1500
|
||||
#define PKTFIFO_STORE_FILT_CONFIG 0x1504
|
||||
#define PKTFIFO_THR_CONFIG0 0x1508
|
||||
#define PKTFIFO_THR_CONFIG1 0x150c
|
||||
#define PKTFIFO_CONTROL 0x1510
|
||||
|
||||
#define VMON_STATUS1 0x1580
|
||||
#define VMON_STATUS2 0x1584
|
||||
#define VMON_STATUS3 0x1588
|
||||
#define VMON_STATUS4 0x158c
|
||||
#define VMON_STATUS5 0x1590
|
||||
#define VMON_STATUS6 0x1594
|
||||
#define VMON_STATUS7 0x1598
|
||||
#define VMON_ILACE_DETECT BIT(4)
|
||||
|
||||
#define CEC_TX_CONTROL 0x2000
|
||||
#define CEC_STATUS 0x2004
|
||||
#define CEC_CONFIG 0x2008
|
||||
#define RX_AUTO_DRIVE_ACKNOWLEDGE BIT(9)
|
||||
#define CEC_ADDR 0x200c
|
||||
#define CEC_TX_COUNT 0x2020
|
||||
#define CEC_TX_DATA3_0 0x2024
|
||||
#define CEC_RX_COUNT_STATUS 0x2040
|
||||
#define CEC_RX_DATA3_0 0x2044
|
||||
#define CEC_LOCK_CONTROL 0x2054
|
||||
#define CEC_RXQUAL_BITTIME_CONFIG 0x2060
|
||||
#define CEC_RX_BITTIME_CONFIG 0x2064
|
||||
#define CEC_TX_BITTIME_CONFIG 0x2068
|
||||
|
||||
#define DMA_CONFIG1 0x4400
|
||||
#define UV_WID_MASK GENMASK(31, 28)
|
||||
#define UV_WID(x) UPDATE(x, 31, 28)
|
||||
#define Y_WID_MASK GENMASK(27, 24)
|
||||
#define Y_WID(x) UPDATE(x, 27, 24)
|
||||
#define DDR_STORE_FORMAT_MASK GENMASK(15, 12)
|
||||
#define DDR_STORE_FORMAT(x) UPDATE(x, 15, 12)
|
||||
#define ABANDON_EN BIT(0)
|
||||
#define DMA_CONFIG2 0x4404
|
||||
#define DMA_CONFIG3 0x4408
|
||||
#define DMA_CONFIG4 0x440c // dma irq en
|
||||
#define DMA_CONFIG5 0x4410 // dma irq clear status
|
||||
#define LINE_FLAG_INT_EN BIT(8)
|
||||
#define HDMIRX_DMA_IDLE_INT BIT(7)
|
||||
#define HDMIRX_LOCK_DISABLE_INT BIT(6)
|
||||
#define LAST_FRAME_AXI_UNFINISH_INT_EN BIT(5)
|
||||
#define FIFO_OVERFLOW_INT_EN BIT(2)
|
||||
#define FIFO_UNDERFLOW_INT_EN BIT(1)
|
||||
#define HDMIRX_AXI_ERROR_INT_EN BIT(0)
|
||||
#define DMA_CONFIG6 0x4414
|
||||
#define RB_SWAP_EN BIT(9)
|
||||
#define HSYNC_TOGGLE_EN BIT(5)
|
||||
#define VSYNC_TOGGLE_EN BIT(4)
|
||||
#define HDMIRX_DMA_EN BIT(1)
|
||||
#define DMA_CONFIG7 0x4418
|
||||
#define LINE_FLAG_NUM_MASK GENMASK(31, 16)
|
||||
#define LINE_FLAG_NUM(x) UPDATE(x, 31, 16)
|
||||
#define LOCK_FRAME_NUM_MASK GENMASK(11, 0)
|
||||
#define LOCK_FRAME_NUM(x) UPDATE(x, 11, 0)
|
||||
#define DMA_CONFIG8 0x441c
|
||||
#define REG_MIRROR_EN BIT(0)
|
||||
#define DMA_CONFIG9 0x4420
|
||||
#define DMA_CONFIG10 0x4424
|
||||
#define DMA_CONFIG11 0x4428
|
||||
#define EDID_READ_EN_MASK BIT(8)
|
||||
#define EDID_READ_EN(x) UPDATE(x, 8, 8)
|
||||
#define EDID_WRITE_EN_MASK BIT(7)
|
||||
#define EDID_WRITE_EN(x) UPDATE(x, 7, 7)
|
||||
#define EDID_SLAVE_ADDR_MASK GENMASK(6, 0)
|
||||
#define EDID_SLAVE_ADDR(x) UPDATE(x, 6, 0)
|
||||
#define DMA_STATUS1 0x4430 // dma irq status
|
||||
#define DMA_STATUS2 0x4434
|
||||
#define DMA_STATUS3 0x4438
|
||||
#define DMA_STATUS4 0x443c
|
||||
#define DMA_STATUS5 0x4440
|
||||
#define DMA_STATUS6 0x4444
|
||||
#define DMA_STATUS7 0x4448
|
||||
#define DMA_STATUS8 0x444c
|
||||
#define DMA_STATUS9 0x4450
|
||||
#define DMA_STATUS10 0x4454
|
||||
#define HDMIRX_LOCK BIT(3)
|
||||
#define DMA_STATUS11 0x4458
|
||||
#define HDMIRX_TYPE_MASK GENMASK(8, 7)
|
||||
#define HDMIRX_COLOR_DEPTH_MASK GENMASK(6, 3)
|
||||
#define HDMIRX_FORMAT_MASK GENMASK(2, 0)
|
||||
#define DMA_STATUS12 0x445c
|
||||
#define DMA_STATUS13 0x4460
|
||||
#define DMA_STATUS14 0x4464
|
||||
|
||||
#define MAINUNIT_INTVEC_INDEX 0x5000
|
||||
#define MAINUNIT_0_INT_STATUS 0x5010
|
||||
#define CECRX_NOTIFY_ERR BIT(12)
|
||||
#define CECRX_EOM BIT(11)
|
||||
#define CECTX_DRIVE_ERR BIT(10)
|
||||
#define CECRX_BUSY BIT(9)
|
||||
#define CECTX_BUSY BIT(8)
|
||||
#define CECTX_FRAME_DISCARDED BIT(5)
|
||||
#define CECTX_NRETRANSMIT_FAIL BIT(4)
|
||||
#define CECTX_LINE_ERR BIT(3)
|
||||
#define CECTX_ARBLOST BIT(2)
|
||||
#define CECTX_NACK BIT(1)
|
||||
#define CECTX_DONE BIT(0)
|
||||
#define MAINUNIT_0_INT_MASK_N 0x5014
|
||||
#define MAINUNIT_0_INT_CLEAR 0x5018
|
||||
#define MAINUNIT_0_INT_FORCE 0x501c
|
||||
#define TIMER_BASE_LOCKED_IRQ BIT(26)
|
||||
#define TMDSQPCLK_OFF_CHG BIT(5)
|
||||
#define TMDSQPCLK_LOCKED_CHG BIT(4)
|
||||
#define MAINUNIT_1_INT_STATUS 0x5020
|
||||
#define MAINUNIT_1_INT_MASK_N 0x5024
|
||||
#define MAINUNIT_1_INT_CLEAR 0x5028
|
||||
#define MAINUNIT_1_INT_FORCE 0x502c
|
||||
#define MAINUNIT_2_INT_STATUS 0x5030
|
||||
#define MAINUNIT_2_INT_MASK_N 0x5034
|
||||
#define MAINUNIT_2_INT_CLEAR 0x5038
|
||||
#define MAINUNIT_2_INT_FORCE 0x503c
|
||||
#define PHYCREG_CR_READ_DONE BIT(11)
|
||||
#define PHYCREG_CR_WRITE_DONE BIT(10)
|
||||
#define TMDSVALID_STABLE_CHG BIT(1)
|
||||
|
||||
#define AVPUNIT_0_INT_STATUS 0x5040
|
||||
#define AVPUNIT_0_INT_MASK_N 0x5044
|
||||
#define AVPUNIT_0_INT_CLEAR 0x5048
|
||||
#define AVPUNIT_0_INT_FORCE 0x504c
|
||||
#define CED_DYN_CNT_CH2_IRQ BIT(22)
|
||||
#define CED_DYN_CNT_CH1_IRQ BIT(21)
|
||||
#define CED_DYN_CNT_CH0_IRQ BIT(20)
|
||||
#define AVPUNIT_1_INT_STATUS 0x5050
|
||||
#define DEFRAMER_VSYNC_THR_REACHED_IRQ BIT(1)
|
||||
#define AVPUNIT_1_INT_MASK_N 0x5054
|
||||
#define DEFRAMER_VSYNC_THR_REACHED_MASK_N BIT(1)
|
||||
#define DEFRAMER_VSYNC_MASK_N BIT(0)
|
||||
#define AVPUNIT_1_INT_CLEAR 0x5058
|
||||
#define DEFRAMER_VSYNC_THR_REACHED_CLEAR BIT(1)
|
||||
#define PKT_0_INT_STATUS 0x5080
|
||||
#define PKTDEC_ACR_CHG_IRQ BIT(3)
|
||||
#define PKT_0_INT_MASK_N 0x5084
|
||||
#define PKTDEC_ACR_CHG_MASK_N BIT(3)
|
||||
#define PKT_0_INT_CLEAR 0x5088
|
||||
#define PKT_1_INT_STATUS 0x5090
|
||||
#define PKT_1_INT_MASK_N 0x5094
|
||||
#define PKT_1_INT_CLEAR 0x5098
|
||||
#define PKT_2_INT_STATUS 0x50a0
|
||||
#define PKTDEC_ACR_RCV_IRQ BIT(3)
|
||||
#define PKT_2_INT_MASK_N 0x50a4
|
||||
#define PKTDEC_AVIIF_RCV_IRQ BIT(11)
|
||||
#define PKTDEC_ACR_RCV_MASK_N BIT(3)
|
||||
#define PKT_2_INT_CLEAR 0x50a8
|
||||
#define PKTDEC_AVIIF_RCV_CLEAR BIT(11)
|
||||
#define PKTDEC_ACR_RCV_CLEAR BIT(3)
|
||||
#define SCDC_INT_STATUS 0x50c0
|
||||
#define SCDC_INT_MASK_N 0x50c4
|
||||
#define SCDC_INT_CLEAR 0x50c8
|
||||
#define SCDCTMDSCCFG_CHG BIT(2)
|
||||
|
||||
#define CEC_INT_STATUS 0x5100
|
||||
#define CEC_INT_MASK_N 0x5104
|
||||
#define CEC_INT_CLEAR 0x5108
|
||||
|
||||
#endif
|
275
drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c
Normal file
275
drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c
Normal file
|
@ -0,0 +1,275 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Shunqing Chen <csq@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <media/cec.h>
|
||||
|
||||
#include "snps_hdmirx.h"
|
||||
#include "snps_hdmirx_cec.h"
|
||||
|
||||
static void hdmirx_cec_write(struct hdmirx_cec *cec, int reg, u32 val)
|
||||
{
|
||||
cec->ops->write(cec->hdmirx, reg, val);
|
||||
}
|
||||
|
||||
static u32 hdmirx_cec_read(struct hdmirx_cec *cec, int reg)
|
||||
{
|
||||
return cec->ops->read(cec->hdmirx, reg);
|
||||
}
|
||||
|
||||
static void hdmirx_cec_update_bits(struct hdmirx_cec *cec, int reg, u32 mask,
|
||||
u32 data)
|
||||
{
|
||||
u32 val = hdmirx_cec_read(cec, reg) & ~mask;
|
||||
|
||||
val |= (data & mask);
|
||||
hdmirx_cec_write(cec, reg, val);
|
||||
}
|
||||
|
||||
static int hdmirx_cec_log_addr(struct cec_adapter *adap, u8 logical_addr)
|
||||
{
|
||||
struct hdmirx_cec *cec = cec_get_drvdata(adap);
|
||||
|
||||
if (logical_addr == CEC_LOG_ADDR_INVALID)
|
||||
cec->addresses = 0;
|
||||
else
|
||||
cec->addresses |= BIT(logical_addr) | BIT(15);
|
||||
|
||||
hdmirx_cec_write(cec, CEC_ADDR, cec->addresses);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* signal_free_time is handled by the Synopsys Designware
|
||||
* HDMIRX Controller hardware.
|
||||
*/
|
||||
static int hdmirx_cec_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *msg)
|
||||
{
|
||||
struct hdmirx_cec *cec = cec_get_drvdata(adap);
|
||||
u32 data[4] = {0};
|
||||
int i, data_len, msg_len;
|
||||
|
||||
msg_len = msg->len;
|
||||
|
||||
hdmirx_cec_write(cec, CEC_TX_COUNT, msg_len - 1);
|
||||
for (i = 0; i < msg_len; i++)
|
||||
data[i / 4] |= msg->msg[i] << (i % 4) * 8;
|
||||
|
||||
data_len = DIV_ROUND_UP(msg_len, 4);
|
||||
|
||||
for (i = 0; i < data_len; i++)
|
||||
hdmirx_cec_write(cec, CEC_TX_DATA3_0 + i * 4, data[i]);
|
||||
|
||||
hdmirx_cec_write(cec, CEC_TX_CONTROL, 0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t hdmirx_cec_hardirq(int irq, void *data)
|
||||
{
|
||||
struct cec_adapter *adap = data;
|
||||
struct hdmirx_cec *cec = cec_get_drvdata(adap);
|
||||
u32 stat = hdmirx_cec_read(cec, CEC_INT_STATUS);
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
u32 val;
|
||||
|
||||
if (!stat)
|
||||
return IRQ_NONE;
|
||||
|
||||
hdmirx_cec_write(cec, CEC_INT_CLEAR, stat);
|
||||
|
||||
if (stat & CECTX_LINE_ERR) {
|
||||
cec->tx_status = CEC_TX_STATUS_ERROR;
|
||||
cec->tx_done = true;
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
} else if (stat & CECTX_DONE) {
|
||||
cec->tx_status = CEC_TX_STATUS_OK;
|
||||
cec->tx_done = true;
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
} else if (stat & CECTX_NACK) {
|
||||
cec->tx_status = CEC_TX_STATUS_NACK;
|
||||
cec->tx_done = true;
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
} else if (stat & CECTX_ARBLOST) {
|
||||
cec->tx_status = CEC_TX_STATUS_ARB_LOST;
|
||||
cec->tx_done = true;
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
if (stat & CECRX_EOM) {
|
||||
unsigned int len, i;
|
||||
|
||||
val = hdmirx_cec_read(cec, CEC_RX_COUNT_STATUS);
|
||||
/* rxbuffer locked status */
|
||||
if ((val & 0x80))
|
||||
return ret;
|
||||
|
||||
len = (val & 0xf) + 1;
|
||||
if (len > sizeof(cec->rx_msg.msg))
|
||||
len = sizeof(cec->rx_msg.msg);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!(i % 4))
|
||||
val = hdmirx_cec_read(cec, CEC_RX_DATA3_0 + i / 4 * 4);
|
||||
cec->rx_msg.msg[i] = (val >> ((i % 4) * 8)) & 0xff;
|
||||
}
|
||||
|
||||
cec->rx_msg.len = len;
|
||||
smp_wmb(); /* receive RX msg */
|
||||
cec->rx_done = true;
|
||||
hdmirx_cec_write(cec, CEC_LOCK_CONTROL, 0x1);
|
||||
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t hdmirx_cec_thread(int irq, void *data)
|
||||
{
|
||||
struct cec_adapter *adap = data;
|
||||
struct hdmirx_cec *cec = cec_get_drvdata(adap);
|
||||
|
||||
if (cec->tx_done) {
|
||||
cec->tx_done = false;
|
||||
cec_transmit_attempt_done(adap, cec->tx_status);
|
||||
}
|
||||
if (cec->rx_done) {
|
||||
cec->rx_done = false;
|
||||
smp_rmb(); /* RX msg has been received */
|
||||
cec_received_msg(adap, &cec->rx_msg);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int hdmirx_cec_enable(struct cec_adapter *adap, bool enable)
|
||||
{
|
||||
struct hdmirx_cec *cec = cec_get_drvdata(adap);
|
||||
|
||||
if (!enable) {
|
||||
hdmirx_cec_write(cec, CEC_INT_MASK_N, 0);
|
||||
hdmirx_cec_write(cec, CEC_INT_CLEAR, 0);
|
||||
if (cec->ops->disable)
|
||||
cec->ops->disable(cec->hdmirx);
|
||||
} else {
|
||||
unsigned int irqs;
|
||||
|
||||
hdmirx_cec_log_addr(cec->adap, CEC_LOG_ADDR_INVALID);
|
||||
if (cec->ops->enable)
|
||||
cec->ops->enable(cec->hdmirx);
|
||||
hdmirx_cec_update_bits(cec, GLOBAL_SWENABLE, CEC_ENABLE, CEC_ENABLE);
|
||||
|
||||
irqs = CECTX_LINE_ERR | CECTX_NACK | CECRX_EOM | CECTX_DONE;
|
||||
hdmirx_cec_write(cec, CEC_INT_MASK_N, irqs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cec_adap_ops hdmirx_cec_ops = {
|
||||
.adap_enable = hdmirx_cec_enable,
|
||||
.adap_log_addr = hdmirx_cec_log_addr,
|
||||
.adap_transmit = hdmirx_cec_transmit,
|
||||
};
|
||||
|
||||
static void hdmirx_cec_del(void *data)
|
||||
{
|
||||
struct hdmirx_cec *cec = data;
|
||||
|
||||
cec_delete_adapter(cec->adap);
|
||||
}
|
||||
|
||||
struct hdmirx_cec *snps_hdmirx_cec_register(struct hdmirx_cec_data *data)
|
||||
{
|
||||
struct hdmirx_cec *cec;
|
||||
unsigned int irqs;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Our device is just a convenience - we want to link to the real
|
||||
* hardware device here, so that userspace can see the association
|
||||
* between the HDMI hardware and its associated CEC chardev.
|
||||
*/
|
||||
cec = devm_kzalloc(data->dev, sizeof(*cec), GFP_KERNEL);
|
||||
if (!cec)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cec->dev = data->dev;
|
||||
cec->irq = data->irq;
|
||||
cec->ops = data->ops;
|
||||
cec->hdmirx = data->hdmirx;
|
||||
|
||||
hdmirx_cec_update_bits(cec, GLOBAL_SWENABLE, CEC_ENABLE, CEC_ENABLE);
|
||||
hdmirx_cec_update_bits(cec, CEC_CONFIG, RX_AUTO_DRIVE_ACKNOWLEDGE,
|
||||
RX_AUTO_DRIVE_ACKNOWLEDGE);
|
||||
|
||||
hdmirx_cec_write(cec, CEC_TX_COUNT, 0);
|
||||
hdmirx_cec_write(cec, CEC_INT_MASK_N, 0);
|
||||
hdmirx_cec_write(cec, CEC_INT_CLEAR, ~0);
|
||||
|
||||
cec->adap = cec_allocate_adapter(&hdmirx_cec_ops, cec, "snps-hdmirx",
|
||||
CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL,
|
||||
CEC_MAX_LOG_ADDRS);
|
||||
if (IS_ERR(cec->adap)) {
|
||||
dev_err(cec->dev, "cec adapter allocation failed\n");
|
||||
return ERR_CAST(cec->adap);
|
||||
}
|
||||
|
||||
/* override the module pointer */
|
||||
cec->adap->owner = THIS_MODULE;
|
||||
|
||||
ret = devm_add_action(cec->dev, hdmirx_cec_del, cec);
|
||||
if (ret) {
|
||||
cec_delete_adapter(cec->adap);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
irq_set_status_flags(cec->irq, IRQ_NOAUTOEN);
|
||||
|
||||
ret = devm_request_threaded_irq(cec->dev, cec->irq,
|
||||
hdmirx_cec_hardirq,
|
||||
hdmirx_cec_thread, IRQF_ONESHOT,
|
||||
"rk_hdmirx_cec", cec->adap);
|
||||
if (ret) {
|
||||
dev_err(cec->dev, "cec irq request failed\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = cec_register_adapter(cec->adap, cec->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(cec->dev, "cec adapter registration failed\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
irqs = CECTX_LINE_ERR | CECTX_NACK | CECRX_EOM | CECTX_DONE;
|
||||
hdmirx_cec_write(cec, CEC_INT_MASK_N, irqs);
|
||||
|
||||
/*
|
||||
* CEC documentation says we must not call cec_delete_adapter
|
||||
* after a successful call to cec_register_adapter().
|
||||
*/
|
||||
devm_remove_action(cec->dev, hdmirx_cec_del, cec);
|
||||
|
||||
enable_irq(cec->irq);
|
||||
|
||||
return cec;
|
||||
}
|
||||
|
||||
void snps_hdmirx_cec_unregister(struct hdmirx_cec *cec)
|
||||
{
|
||||
disable_irq(cec->irq);
|
||||
|
||||
cec_unregister_adapter(cec->adap);
|
||||
}
|
43
drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h
Normal file
43
drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Shunqing Chen <csq@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef DW_HDMI_RX_CEC_H
|
||||
#define DW_HDMI_RX_CEC_H
|
||||
|
||||
struct snps_hdmirx_dev;
|
||||
|
||||
struct hdmirx_cec_ops {
|
||||
void (*write)(struct snps_hdmirx_dev *hdmirx_dev, int reg, u32 val);
|
||||
u32 (*read)(struct snps_hdmirx_dev *hdmirx_dev, int reg);
|
||||
void (*enable)(struct snps_hdmirx_dev *hdmirx);
|
||||
void (*disable)(struct snps_hdmirx_dev *hdmirx);
|
||||
};
|
||||
|
||||
struct hdmirx_cec_data {
|
||||
struct snps_hdmirx_dev *hdmirx;
|
||||
const struct hdmirx_cec_ops *ops;
|
||||
struct device *dev;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct hdmirx_cec {
|
||||
struct snps_hdmirx_dev *hdmirx;
|
||||
struct device *dev;
|
||||
const struct hdmirx_cec_ops *ops;
|
||||
u32 addresses;
|
||||
struct cec_adapter *adap;
|
||||
struct cec_msg rx_msg;
|
||||
unsigned int tx_status;
|
||||
bool tx_done;
|
||||
bool rx_done;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct hdmirx_cec *snps_hdmirx_cec_register(struct hdmirx_cec_data *data);
|
||||
void snps_hdmirx_cec_unregister(struct hdmirx_cec *cec);
|
||||
|
||||
#endif /* DW_HDMI_RX_CEC_H */
|
Loading…
Add table
Reference in a new issue