Skip to content
Snippets Groups Projects
Commit 60c00a5e authored by Shreeya Patel's avatar Shreeya Patel Committed by Sebastian Reichel
Browse files

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.

Signed-off-by: default avatarDingxian Wen <shawn.wen@rock-chips.com>
Co-developed-by: default avatarShreeya Patel <shreeya.patel@collabora.com>
Reviewed-by: default avatarDmitry Osipenko <dmitry.osipenko@collabora.com>
Tested-by: default avatarDmitry Osipenko <dmitry.osipenko@collabora.com>
Signed-off-by: default avatarShreeya Patel <shreeya.patel@collabora.com>
parent 290c966b
No related branches found
No related tags found
No related merge requests found
Pipeline #85928 passed
...@@ -82,6 +82,7 @@ source "drivers/media/platform/rockchip/Kconfig" ...@@ -82,6 +82,7 @@ source "drivers/media/platform/rockchip/Kconfig"
source "drivers/media/platform/samsung/Kconfig" source "drivers/media/platform/samsung/Kconfig"
source "drivers/media/platform/st/Kconfig" source "drivers/media/platform/st/Kconfig"
source "drivers/media/platform/sunxi/Kconfig" source "drivers/media/platform/sunxi/Kconfig"
source "drivers/media/platform/synopsys/Kconfig"
source "drivers/media/platform/ti/Kconfig" source "drivers/media/platform/ti/Kconfig"
source "drivers/media/platform/verisilicon/Kconfig" source "drivers/media/platform/verisilicon/Kconfig"
source "drivers/media/platform/via/Kconfig" source "drivers/media/platform/via/Kconfig"
......
...@@ -25,6 +25,7 @@ obj-y += rockchip/ ...@@ -25,6 +25,7 @@ obj-y += rockchip/
obj-y += samsung/ obj-y += samsung/
obj-y += st/ obj-y += st/
obj-y += sunxi/ obj-y += sunxi/
obj-y += synopsys/
obj-y += ti/ obj-y += ti/
obj-y += verisilicon/ obj-y += verisilicon/
obj-y += via/ obj-y += via/
......
# SPDX-License-Identifier: GPL-2.0-only
source "drivers/media/platform/synopsys/hdmirx/Kconfig"
# SPDX-License-Identifier: GPL-2.0-only
obj-y += hdmirx/
# SPDX-License-Identifier: GPL-2.0
config VIDEO_SYNOPSYS_HDMIRX
tristate "Synopsys DesignWare HDMI Receiver driver"
depends on VIDEO_DEV
depends on ARCH_ROCKCHIP
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
select VIDEOBUF2_DMA_CONTIG
select CEC_CORE
select CEC_NOTIFIER
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.
# SPDX-License-Identifier: GPL-2.0
synopsys-hdmirx-objs := snps_hdmirx.o snps_hdmirx_cec.o
obj-$(CONFIG_VIDEO_SYNOPSYS_HDMIRX) += synopsys-hdmirx.o
This diff is collapsed.
/* 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
// 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/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <media/cec.h>
#include <media/cec-notifier.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;
}
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;
if (msg->len > 16)
msg_len = 16;
if (msg_len <= 0)
return 0;
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 = msg_len / 4 + 1;
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;
}
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;
if (!data)
return NULL;
/*
* 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 NULL;
cec->dev = data->dev;
cec->irq = data->irq;
cec->ops = data->ops;
cec->hdmirx = data->hdmirx;
cec->edid = (struct edid *)data->edid;
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, "rk-hdmirx",
CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT |
CEC_CAP_RC | CEC_CAP_PASSTHROUGH,
CEC_MAX_LOG_ADDRS);
if (IS_ERR(cec->adap)) {
dev_err(cec->dev, "cec adap allocate failed\n");
return NULL;
}
/* 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 NULL;
}
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 NULL;
}
cec->notify = cec_notifier_cec_adap_register(cec->dev,
NULL, cec->adap);
if (!cec->notify) {
dev_err(cec->dev, "cec notify register failed\n");
return NULL;
}
ret = cec_register_adapter(cec->adap, cec->dev);
if (ret < 0) {
dev_err(cec->dev, "cec register adapter failed\n");
cec_unregister_adapter(cec->adap);
return NULL;
}
cec_s_phys_addr_from_edid(cec->adap, cec->edid);
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)
{
if (!cec)
return;
disable_irq(cec->irq);
cec_unregister_adapter(cec->adap);
}
/* 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;
u8 *edid;
};
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;
struct cec_notifier *notify;
int irq;
struct edid *edid;
};
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 */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment