// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2022 Rockchip Electronics Co., Ltd. * * Author: Zhang Yubing */ #include #include #include #include #include #include "hal/cru_api.h" #include "hal/pinctrl_api.h" #include "rkx110_x120.h" #include "rkx110_reg.h" #define LINK_REG(x) ((x) + RKX110_SER_RKLINK_BASE) #define RKLINK_TX_SERDES_CTRL LINK_REG(0x0000) #define VIDEO_CH0_EN_MASK BIT(31) #define VIDEO_CH1_EN_MASK BIT(30) #define STOP_AUDIO BIT(18) #define STOP_VIDEO_CH1 BIT(17) #define STOP_VIDEO_CH0 BIT(16) #define CH1_LVDS_SEL_EN BIT(15) #define TRAIN_CLK_SEL_MASK GENMASK(14, 13) #define TRAIN_CLK_SEL_CH0 UPDATE(0, 14, 13) #define TRAIN_CLK_SEL_CH1 UPDATE(1, 14, 13) #define TRAIN_CLK_SEL_I2S UPDATE(2, 14, 13) #define STREAM_TYPE_MASK BIT(12) #define SER_STREAM_CAMERA UPDATE(0, 12, 12) #define SER_STREAM_DISPLAY UPDATE(1, 12, 12) #define VIDEO_EN BIT(11) #define SERDES_LANE_SWAP_EN BIT(10) #define SERDES_MIRROR_EN BIT(9) #define SER_CH1_EN BIT(8) #define CH1_DSOURCE_ID(x) UPDATE(x, 7, 6) #define CH0_DSOURCE_ID(x) UPDATE(x, 5, 4) #define SERDES_DATA_WIDTH_MASK GENMASK(3, 2) #define SERDES_DATA_WIDTH_8BIT UPDATE(0, 3, 2) #define SERDES_DATA_WIDTH_16BIT UPDATE(1, 3, 2) #define SERDES_DATA_WIDTH_24BIT UPDATE(2, 3, 2) #define SERDES_DATA_WIDTH_32BIT UPDATE(3, 3, 2) #define SERDES_DUAL_LANE_EN BIT(1) #define SER_EN BIT(0) #define RKLINK_TX_VIDEO_CTRL LINK_REG(0x0004) #define VIDEO_REPKT_LENGTH_MASK GENMASK(29, 16) #define VIDEO_REPKT_LENGTH(x) UPDATE(x, 29, 16) #define DUAL_LVDS_CYCLE_DIFF(x) UPDATE(x, 13, 4) #define PIXEL_VSYNC_SEL BIT(3) #define SOURCE_ID_MASK UPDATE(7, 2, 0) #define CAMERA_SRC_CSI UPDATE(0, 2, 0) #define CAMERA_SRC_LVDS UPDATE(1, 2, 0) #define CAMERA_SRC_DVP UPDATE(2, 2, 0) #define DISPLAY_SRC_DSI UPDATE(0, 2, 0) #define DISPLAY_SRC_DUAL_LDVS UPDATE(1, 2, 0) #define DISPLAY_SRC_LVDS0 UPDATE(2, 2, 0) #define DISPLAY_SRC_LVDS1 UPDATE(3, 2, 0) #define DISPLAY_SRC_RGB UPDATE(5, 2, 0) #define SER_RKLINK_DSI_REC0(x) LINK_REG(0x0008 + 0x10 * x) #define DSI_REC_START BIT(31) #define DSI_CMD_TYPE BIT(30) #define DSI_HACT(x) UPDATE(x, 29, 16) #define DSI_VACT(x) UPDATE(x, 13, 0) #define SER_RKLINK_DSI_REC1(x) LINK_REG(0x000C + 0x10 * x) #define DSI_SPLIT_LR_SWAP BIT(30) #define DSI_FRAME_MODE(x) UPDATE(x, 29, 28) #define DSI_HFP(x) UPDATE(x, 27, 16) #define DSI_HBP(x) UPDATE(x, 11, 0) #define SER_RKLINK_DSI_REC2(x) LINK_REG(0x0010 + 0x10 * x) #define DSI_0_DST_MASK GENMASK(31, 30) #define DSI_0_DST(x) UPDATE(x, 31, 30) #define DSI_CHANNEL_SWAP UPDATE(2, 31, 30) #define DSI0_SPLIT_MODE UPDATE(0, 31, 30) #define DSI1_SPLIT_MODE UPDATE(3, 31, 30) #define DSI_DST_VPORCH_MASK GENMASK(29, 0) #define DSI_VFP(x) UPDATE(x, 29, 20) #define DSI_VBP(x) UPDATE(x, 19, 10) #define DSI_VSA(x) UPDATE(x, 9, 0) #define SER_RKLINK_DSI_REC3(x) LINK_REG(0x0014 + 0x10 * x) #define DSI_DELAY_LENGTH_MASK GENMASK(31, 12) #define DSI_DELAY_LENGTH(x) UPDATE(x, 31, 12) #define DSI_HSA(x) UPDATE(x, 11, 0) #define SER_RKLINK_AUDIO_CRTL LINK_REG(0x0028) #define SER_RKLINK_AUDIO_CTRL LINK_REG(0x0028) #define SER_RKLINK_AUDIO_FDIV LINK_REG(0x002C) #define SER_RKLINK_AUDIO_LRCK LINK_REG(0x0030) #define SER_RKLINK_AUDIO_RECOVER LINK_REG(0x0034) #define SER_RKLINK_AUDIO_FM_STATUS LINK_REG(0x0038) #define SER_RKLINK_FIFO_STATUS LINK_REG(0x003C) #define CH1_CMD_FIFO_UNDERRUN BIT(24) #define CH0_CMD_FIFO_UNDERRUN BIT(23) #define DATA1_FIFO_UNDERRUN BIT(22) #define DATA0_FIFO_UNDERRUN BIT(21) #define AUDIO_FIFO_UNDERRUN BIT(20) #define LVDS1_FIFO_UNDERRUN BIT(19) #define LVDS0_FIFO_UNDERRUN BIT(18) #define DSI_CH1_FIFO_UNDERRUN BIT(17) #define DSI_CH0_FIFO_UNDERRUN BIT(16) #define CH1_CMD_FIFO_OVERFLOW BIT(8) #define CH0_CMD_FIFO_OVERFLOW BIT(7) #define DATA0_FIFO_OVERFLOW BIT(6) #define DATA1_FIFO_OVERFLOW BIT(5) #define AUDIO_FIFO_OVERFLOW BIT(4) #define LVDS1_FIFO_OVERFLOW BIT(3) #define LVDS0_FIFO_OVERFLOW BIT(2) #define DSI_CH1_FIFO_OVERFLOW BIT(1) #define DSI_CH0_FIFO_OVERFLOW BIT(0) #define SER_RKLINK_SOURCE_IRQ_EN LINK_REG(0x0040) #define TRAIN_DONE_IRQ_FLAG BIT(19) #define FIFO_UNDERRUN_IRQ_FLAG BIT(18) #define FIFO_OVERFLOW_IRQ_FLAG BIT(17) #define AUDIO_FM_IRQ_OUTPUT_FLAG BIT(16) #define TRAIN_DONE_IRQ_OUTPUT_EN BIT(3) #define FIFO_UNDERRUN_IRQ_OUTPUT_EN BIT(2) #define FIFO_OVERFLOW_IRQ_OUTPUT_EN BIT(1) #define AUDIO_FM_IRQ_OUTPUT_EN BIT(0) #define SER_RKLINK_TRAIN_CTRL LINK_REG(0x0044) #define SER_RKLINK_I2C_CFG LINK_REG(0x00C0) #define SER_RKLINK_SPI_CFG LINK_REG(0x00C4) #define SER_RKLINK_UART_CFG LINK_REG(0x00C8) #define SER_RKLINK_GPIO_CFG LINK_REG(0x00CC) #define GPIO_GROUP1_EN BIT(17) #define GPIO_GROUP0_EN BIT(16) #define SER_RKLINK_IO_DEF_INV_CFG LINK_REG(0x00D0) #define OTHER_LANE_ACTIVE(x) HIWORD_UPDATE(x, 12, 12) #define FORWARD_NON_ACK(x) HIWORD_UPDATE(x, 11, 11) #define SER_RKLINK_DISP_DSI_SPLIT BIT(1) #define SER_RKLINK_DISP_MIRROR BIT(2) #define SER_RKLINK_DISP_DUAL_CHANNEL BIT(3) #define PCS_REG(id, x) ((x) + RKX110_SER_PCS0_BASE + (id) * RKX110_SER_PCS_OFFSET) #define PCS_REG00(id) PCS_REG(id, 0x00) #define PCS_DUAL_LANE_MODE_EN HIWORD_UPDATE(1, GENMASK(12, 12), 12) #define PCS_AUTO_START_EN HIWORD_UPDATE(1, GENMASK(3, 3), 3) #define PCS_EN_MASK HIWORD_MASK(2, 2) #define PCS_EN HIWORD_UPDATE(1, GENMASK(2, 2), 2) #define PCS_DISABLE HIWORD_UPDATE(0, GENMASK(2, 2), 2) #define PCS_ECU_MODE HIWORD_UPDATE(0, GENMASK(2, 2), 1) #define PCS_REMOTE_MODE HIWORD_UPDATE(1, GENMASK(2, 2), 1) #define PCS_SAFE_MODE_EN HIWORD_UPDATE(1, GENMASK(0, 0), 0) #define PCS_REG04(id) PCS_REG(id, 0x04) #define PCS_REG08(id) PCS_REG(id, 0x08) #define VIDEO_SUS_EN(x) HIWORD_UPDATE(x, GENMASK(15, 15), 15) #define PCS_REG10(id) PCS_REG(id, 0x10) #define PCS_REG14(id) PCS_REG(id, 0x14) #define PCS_REG18(id) PCS_REG(id, 0x18) #define PCS_REG1C(id) PCS_REG(id, 0x1C) #define PCS_REG20(id) PCS_REG(id, 0x20) #define PCS_REG24(id) PCS_REG(id, 0x24) #define PCS_REG28(id) PCS_REG(id, 0x28) #define PCS_REG30(id) PCS_REG(id, 0x30) #define PCS_INT_STARTUP(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0) #define PCS_REG34(id) PCS_REG(id, 0x34) #define PCS_INT_REMOTE_MODE(x) HIWORD_UPDATE(x, GENMASK(15, 0), 0) #define PCS_REG40(id) PCS_REG(id, 0x40) #define PMA_REG(id, x) ((x) + RKX110_SER_PMA0_BASE + (id) * RKX110_SER_PMA_OFFSET) #define SER_PMA_STATUS(id) PMA_REG(id, 0x00) #define SER_PMA_FORCE_INIT_STA BIT(8) #define SER_PMA_CTRL(id) PMA_REG(id, 0x04) #define SER_PMA_FORCE_INIT_MASK HIWORD_MASK(8, 8) #define SER_PMA_FORCE_INIT_EN HIWORD_UPDATE(1, BIT(8), 8) #define SER_PMA_FORCE_INIT_DISABLE HIWORD_UPDATE(0, BIT(8), 8) #define SER_PMA_DUAL_CHANNEL HIWORD_UPDATE(1, BIT(3), 3) #define SER_PMA_INIT_CNT_CLR_MASK HIWORD_MASK(2, 2) #define SER_PMA_INIT_CNT_CLR HIWORD_UPDATE(1, BIT(2), 2) #define SER_PMA_LOAD00(id) PMA_REG(id, 0x10) #define PMA_RATE_MODE_MASK HIWORD_MASK(2, 0) #define PMA_FDR_MODE HIWORD_UPDATE(1, GENMASK(2, 0), 0) #define PMA_HDR_MODE HIWORD_UPDATE(2, GENMASK(2, 0), 0) #define PMA_QDR_MODE HIWORD_UPDATE(4, GENMASK(2, 0), 0) #define SER_PMA_LOAD01(id) PMA_REG(id, 0x14) #define SER_PMA_LOAD02(id) PMA_REG(id, 0x18) #define SER_PMA_LOAD03(id) PMA_REG(id, 0x1C) #define SER_PMA_LOAD04(id) PMA_REG(id, 0x20) #define PMA_PLL_DIV_MASK HIWORD_MASK(14, 0) #define PLL_I_POST_DIV(x) HIWORD_UPDATE(x, GENMASK(14, 10), 10) #define PLL_F_POST_DIV(x) HIWORD_UPDATE(x, GENMASK(9, 0), 0) #define PMA_PLL_DIV(x) HIWORD_UPDATE(x, GENMASK(14, 0), 0) #define SER_PMA_LOAD05(id) PMA_REG(id, 0x2C) #define PMA_PLL_REFCLK_DIV_MASK HIWORD_MASK(3, 0) #define PMA_PLL_REFCLK_DIV(x) HIWORD_UPDATE(x, GENMASK(3, 0), 0) #define SER_PMA_LOAD06(id) PMA_REG(id, 0x28) #define SER_PMA_LOAD07(id) PMA_REG(id, 0x2C) #define SER_PMA_LOAD08(id) PMA_REG(id, 0x30) #define PMA_FCK_VCO_MASK HIWORD_MASK(15, 15) #define PMA_FCK_VCO HIWORD_UPDATE(1, BIT(15), 15) #define PMA_FCK_VCO_DIV2 HIWORD_UPDATE(0, BIT(15), 15) #define SER_PMA_LOAD09(id) PMA_REG(id, 0x34) #define PMA_PLL_DIV4_MASK HIWORD_MASK(12, 12) #define PMA_PLL_DIV4 HIWORD_UPDATE(1, GENMASK(12, 12), 12) #define PMA_PLL_DIV8 HIWORD_UPDATE(0, GENMASK(12, 12), 12) #define SER_PMA_LOAD0A(id) PMA_REG(id, 0x38) #define PMA_CLK_8X_DIV_MASK HIWORD_MASK(7, 1) #define PMA_CLK_8X_DIV(x) HIWORD_UPDATE(x, GENMASK(7, 1), 1) #define SER_PMA_IRQ_EN(id) PMA_REG(id, 0xF0) #define FORCE_INITIAL_IRQ_EN HIWORD_UPDATE(1, BIT(3), 3) #define RTERM_ONCE_TIMEOUT_IRQ_EN HIWORD_UPDATE(1, BIT(1), 1) #define PLL_LOCK_TIMEOUT_IRQ_EN HIWORD_UPDATE(1, BIT(0), 0) #define SER_PMA_IRQ_STATUS(id) PMA_REG(id, 0xF4) #define FORCE_INITIAL_PULSE_STATUS BIT(3) #define RTERM_ONCE_TIMEOUT_STATUS BIT(1) #define PLL_LOCK_TIMEOUT_STATUS BIT(0) enum { SER_LINK_CH_ID0 = 0, SER_LINK_CH_ID1, SER_LINK_CH_ID2, SER_LINK_CH_ID3, }; static const struct rk_serdes_pt ser_pt[] = { { /* gpi_gpo_0 */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x10001, .en_val = 0x10001, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x10, .dir_val = 0x10, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_A5, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, }, }, }, { /* gpi_gpo_1 */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x10002, .en_val = 0x10002, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x20, .dir_val = 0x20, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_A6, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, }, }, }, { /* gpi_gpo_2 */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x10004, .en_val = 0x10004, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x40, .dir_val = 0x40, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_A7, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, }, }, }, { /* gpi_gpo_3 */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x10008, .en_val = 0x10008, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x80, .dir_val = 0x80, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_B0, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC6, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC5, }, }, }, { /* gpi_gpo_4 */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x20100, .en_val = 0x20100, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x1000, .dir_val = 0x1000, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_B3, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, }, }, }, { /* gpi_gpo_5 */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x20200, .en_val = 0x20200, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x2000, .dir_val = 0x2000, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_B4, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, }, }, }, { /* gpi_gpo_6 */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x20400, .en_val = 0x20400, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x4000, .dir_val = 0x4000, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_B5, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, }, }, }, { /* passthrough irq */ .en_reg = SER_RKLINK_GPIO_CFG, .en_mask = 0x20800, .en_val = 0x20800, .dir_reg = SER_RKLINK_GPIO_CFG, .dir_mask = 0x8000, .dir_val = 0x8000, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_A4, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC1, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, }, }, }, { /* passthrough uart0 */ .en_reg = SER_RKLINK_UART_CFG, .en_mask = 0x1, .en_val = 0x1, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_A5 | RK_SERDES_GPIO_PIN_A6, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC4, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, }, }, }, { /* passthrough uart1 */ .en_reg = SER_RKLINK_UART_CFG, .en_mask = 0x2, .en_val = 0x2, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_A7 | RK_SERDES_GPIO_PIN_B0, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC4, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC3, }, }, }, { /* passthrough spi */ .en_reg = SER_RKLINK_SPI_CFG, .en_mask = 0x4, .en_val = 0x4, .dir_reg = SER_RKLINK_SPI_CFG, .dir_mask = 0x1, .dir_val = 0x0, .configs = 1, { { .bank = RK_SERDES_SER_GPIO_BANK0, .pin = RK_SERDES_GPIO_PIN_A5 | RK_SERDES_GPIO_PIN_A6 | RK_SERDES_GPIO_PIN_A7 | RK_SERDES_GPIO_PIN_B0, .incfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC2, .outcfgs = RK_SERDES_PIN_CONFIG_MUX_FUNC1, }, }, }, }; static int rk_serdes_get_stream_source(struct rk_serdes *serdes, int local_port) { if (serdes->stream_type == STREAM_DISPLAY) { if (local_port & RK_SERDES_RGB_RX) return DISPLAY_SRC_RGB; else if (local_port & RK_SERDES_LVDS_RX0) return DISPLAY_SRC_LVDS0; else if (local_port & RK_SERDES_LVDS_RX1) return DISPLAY_SRC_LVDS1; else if (local_port & RK_SERDES_DUAL_LVDS_RX) return DISPLAY_SRC_DUAL_LDVS; else if (local_port & RK_SERDES_DSI_RX0) return DISPLAY_SRC_DSI; else if (local_port & RK_SERDES_DSI_RX1) return DISPLAY_SRC_DSI; } else { return CAMERA_SRC_CSI; } return 0; } void rkx110_set_stream_source(struct rk_serdes *serdes, int local_port, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val, rx_src; serdes->i2c_read_reg(client, RKLINK_TX_VIDEO_CTRL, &val); val &= ~SOURCE_ID_MASK; rx_src = rk_serdes_get_stream_source(serdes, local_port); val |= rx_src; serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val); } static int rkx110_linktx_ser_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SER_EN, enable ? SER_EN : 0); return 0; } static int rk110_linktx_dual_lane_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SERDES_DUAL_LANE_EN, enable ? SERDES_DUAL_LANE_EN : 0); return 0; } void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, VIDEO_EN, enable ? VIDEO_EN : 0); } static int rk110_linktx_dual_channel_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SER_CH1_EN, enable ? SER_CH1_EN : 0); return 0; } static int rk110_linktx_config_pkg_length(struct rk_serdes *serdes, u8 dev_id, u32 length) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, RKLINK_TX_VIDEO_CTRL, VIDEO_REPKT_LENGTH_MASK, VIDEO_REPKT_LENGTH(length)); return 0; } static int rk110_linktx_stream_type_cfg(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; if (serdes->stream_type == STREAM_DISPLAY) serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STREAM_TYPE_MASK, SER_STREAM_DISPLAY); else serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STREAM_TYPE_MASK, SER_STREAM_CAMERA); return 0; } static int rk110_linktx_replicate_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SERDES_MIRROR_EN, enable ? SERDES_MIRROR_EN : 0); return 0; } static int rkx110_linktx_dual_input_cfg(struct rk_serdes *serdes, u8 dev_id, bool is_lvds) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, CH1_LVDS_SEL_EN, is_lvds ? CH1_LVDS_SEL_EN : 0); return 0; } static int rkx110_linktx_input_port_cfg(struct rk_serdes *serdes, u8 dev_id, u32 port) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val; val = rk_serdes_get_stream_source(serdes, port); serdes->i2c_update_bits(client, RKLINK_TX_VIDEO_CTRL, SOURCE_ID_MASK, val); return 0; } int rkx110_linktx_dsi_rec_start(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id, bool enable) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC0(dsi_id), DSI_REC_START, enable ? DSI_REC_START : 0); return 0; } int rkx110_linktx_dsi_type_select(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id, bool is_cmd) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC0(dsi_id), DSI_CMD_TYPE, is_cmd ? DSI_CMD_TYPE : 0); return 0; } int rkx110_linktx_dsi_deley_length_config(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id, u32 length) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC3(dsi_id), DSI_DELAY_LENGTH_MASK, DSI_DELAY_LENGTH(length)); return 0; } static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, int id) { struct videomode *vm = &route->vm; struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client; struct hwclk *hwclk = serdes->chip[DEVICE_LOCAL].hwclk; struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); struct rkx110_dsi_rx *dsi = &sd_panel->dsi_rx; int delay_length; u32 value, type; if (id) { hwclk_set_rate(hwclk, RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX, route->vm.pixelclock); dev_info(serdes->dev, "RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX:%d\n", hwclk_get_rate(hwclk, RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX)); } else { hwclk_set_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX, route->vm.pixelclock); dev_info(serdes->dev, "RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX:%d\n", hwclk_get_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX)); } /* config SER_RKLINK_DSI_REC1 */ value = DSI_FRAME_MODE(route->frame_mode); value |= DSI_HFP(vm->hfront_porch); value |= DSI_HBP(vm->hback_porch); serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC1(id), value); /* config SER_RKLINK_DSI_REC2 */ value = DSI_VFP(vm->vfront_porch); value |= DSI_VBP(vm->vback_porch); value |= DSI_VSA(vm->vsync_len); serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC2(id), DSI_DST_VPORCH_MASK, value); if (route->local_port0) { if (serdes->route_nr == 2) { type = id ? DSI_0_DST(2) : DSI_0_DST(1); } else { if (id) type = (serdes->channel_nr == 2) ? DSI_0_DST(0) : DSI_0_DST(2); else type = (serdes->channel_nr == 2) ? DSI_0_DST(3) : DSI_0_DST(1); } } else { type = id ? DSI_0_DST(1) : DSI_0_DST(2); } serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC2(0), DSI_0_DST_MASK, type); /* config SER_RKLINK_DSI_REC3 */ if (dsi->mode_flags & SERDES_MIPI_DSI_MODE_VIDEO) delay_length = vm->hsync_len + vm->hback_porch + vm->hactive + vm->hfront_porch; else delay_length = (vm->vfront_porch + 1) * (vm->hsync_len + vm->hback_porch + vm->hactive + vm->hfront_porch); value = DSI_DELAY_LENGTH(delay_length); value |= DSI_HSA(vm->hsync_len); serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC3(id), value); /* config SER_RKLINK_DSI_REC0 */ value = DSI_REC_START; if (!(dsi->mode_flags & SERDES_MIPI_DSI_MODE_VIDEO)) value |= DSI_CMD_TYPE; value |= DSI_HACT(vm->hactive); value |= DSI_VACT(vm->vactive); serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC0(id), value); return 0; } static int rk110_ser_pcs_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 pcs_id) { struct i2c_client *client; u8 remote_id = 0; if (route->stream_type == STREAM_DISPLAY) client = serdes->chip[DEVICE_LOCAL].client; else client = serdes->chip[remote_id].client; if (serdes->version == SERDES_V1) serdes->i2c_write_reg(client, PCS_REG08(pcs_id), VIDEO_SUS_EN(0)); return 0; } static int rk110_ser_pma_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 pcs_id) { return 0; } static int rkx110_display_linktx_ctrl_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 dev_id) { struct hwclk *hwclk = serdes->chip[dev_id].hwclk; bool enable; bool is_lvds = false; rk110_linktx_stream_type_cfg(serdes, dev_id); enable = (serdes->lane_nr == 2) ? true : false; rk110_linktx_dual_lane_enable(serdes, dev_id, enable); enable = (serdes->channel_nr == 2) ? true : false; rk110_linktx_dual_channel_enable(serdes, dev_id, enable); enable = (route->route_flag & ROUTE_MULTI_MIRROR) ? true : false; rk110_linktx_replicate_enable(serdes, dev_id, enable); if (((route->local_port0 == RK_SERDES_LVDS_RX0) || (route->local_port0 == RK_SERDES_LVDS_RX1) || (route->local_port1 == RK_SERDES_LVDS_RX0) || (route->local_port1 == RK_SERDES_LVDS_RX1)) && (serdes->route_nr == 2)) is_lvds = true; rkx110_linktx_dual_input_cfg(serdes, dev_id, is_lvds); if (route->local_port0) { rkx110_linktx_input_port_cfg(serdes, dev_id, route->local_port0); } else { if (route->local_port1 == RK_SERDES_LVDS_RX0) rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_LVDS_RX1); else if (route->local_port1 == RK_SERDES_LVDS_RX1) rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_LVDS_RX0); else if (route->local_port1 == RK_SERDES_DSI_RX0) rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_DSI_RX1); else if (route->local_port1 == RK_SERDES_DSI_RX1) rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_DSI_RX0); } if (route->local_port0 & RK_SERDES_DUAL_LVDS_RX) { hwclk_set_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX, route->vm.pixelclock); dev_info(serdes->dev, "RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:%d\n", hwclk_get_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX)); } if (serdes->version == SERDES_V1) { /* * The serdes v1 have a bug when enable video suspend function, which * is used to enhance the i2c frequency. A workaround ways to do it is * reducing the video packet length: * length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16 */ u32 length; length = route->vm.hactive * 24 / 32 / 16; length = (length + 15) / 16 * 16; rk110_linktx_config_pkg_length(serdes, dev_id, length); } rkx110_linktx_ser_enable(serdes, dev_id, true); return 0; } int rkx110_display_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route) { rkx110_display_linktx_ctrl_enable(serdes, route, DEVICE_LOCAL); if (route->local_port0 & RK_SERDES_DSI_RX0) rk_serdes_link_tx_dsi_enable(serdes, route, 0); if (route->local_port0 & RK_SERDES_DSI_RX1) rk_serdes_link_tx_dsi_enable(serdes, route, 1); if (route->local_port1 & RK_SERDES_DSI_RX0) rk_serdes_link_tx_dsi_enable(serdes, route, 0); if (route->local_port1 & RK_SERDES_DSI_RX1) rk_serdes_link_tx_dsi_enable(serdes, route, 1); rk110_ser_pcs_cfg(serdes, route, 0); rk110_ser_pma_cfg(serdes, route, 0); if (serdes->lane_nr == 2) { rk110_ser_pcs_cfg(serdes, route, 1); rk110_ser_pma_cfg(serdes, route, 1); } return 0; } void rkx110_linktx_channel_enable(struct rk_serdes *serdes, u8 ch_id, u8 dev_id, bool enable) { struct i2c_client *client = serdes->chip[dev_id].client; if (ch_id) serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STOP_VIDEO_CH1, enable ? 0 : STOP_VIDEO_CH1); else serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STOP_VIDEO_CH0, enable ? 0 : STOP_VIDEO_CH0); } void rkx110_linktx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 func_id, bool is_rx) { struct i2c_client *client = serdes->chip[client_id].client; const struct rk_serdes_pt_pin *pt_pin = ser_pt[func_id].pt_pins; int i; /* config link passthrough */ serdes->i2c_update_bits(client, ser_pt[func_id].en_reg, ser_pt[func_id].en_mask, ser_pt[func_id].en_val); if (ser_pt[func_id].en_reg) serdes->i2c_update_bits(client, ser_pt[func_id].dir_reg, ser_pt[func_id].dir_mask, is_rx ? ser_pt[func_id].dir_val : ~ser_pt[func_id].dir_val); /* config passthrough pinctrl */ for (i = 0; i < ser_pt[func_id].configs; i++) { serdes->set_hwpin(serdes, client, PIN_RKX110, pt_pin[i].bank, pt_pin[i].pin, is_rx ? pt_pin[i].incfgs : pt_pin[i].outcfgs); } } int rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id) { struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client; u32 val; int ret; int sta; if (id) sta = SER_PCS1_READY; else sta = SER_PCS0_READY; ret = read_poll_timeout(serdes->i2c_read_reg, ret, !(ret < 0) && (val & sta), 1000, USEC_PER_SEC, false, client, SER_GRF_SOC_STATUS0, &val); if (ret < 0) dev_err(&client->dev, "wait link ready timeout: 0x%08x\n", val); else dev_info(&client->dev, "link success: 0x%08x\n", val); return ret; } void rkx110_pma_set_rate(struct rk_serdes *serdes, struct rk_serdes_pma_pll *pll, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val; serdes->i2c_read_reg(client, SER_PMA_STATUS(pcs_id), &val); if (val & SER_PMA_FORCE_INIT_STA) serdes->i2c_update_bits(client, SER_PMA_CTRL(pcs_id), SER_PMA_INIT_CNT_CLR_MASK, SER_PMA_INIT_CNT_CLR); if (pll->force_init_en) serdes->i2c_update_bits(client, SER_PMA_CTRL(pcs_id), SER_PMA_FORCE_INIT_MASK, SER_PMA_FORCE_INIT_EN); else serdes->i2c_update_bits(client, SER_PMA_CTRL(pcs_id), SER_PMA_FORCE_INIT_MASK, SER_PMA_FORCE_INIT_DISABLE); if (pll->rate_mode == FDR_RATE_MODE) serdes->i2c_update_bits(client, SER_PMA_LOAD00(pcs_id), PMA_RATE_MODE_MASK, PMA_FDR_MODE); else if (pll->rate_mode == HDR_RATE_MODE) serdes->i2c_update_bits(client, SER_PMA_LOAD00(pcs_id), PMA_RATE_MODE_MASK, PMA_HDR_MODE); else serdes->i2c_update_bits(client, SER_PMA_LOAD00(pcs_id), PMA_RATE_MODE_MASK, PMA_QDR_MODE); serdes->i2c_update_bits(client, SER_PMA_LOAD04(pcs_id), PMA_PLL_DIV_MASK, PMA_PLL_DIV(pll->pll_div)); serdes->i2c_update_bits(client, SER_PMA_LOAD05(pcs_id), PMA_PLL_REFCLK_DIV_MASK, PMA_PLL_REFCLK_DIV(pll->pll_refclk_div)); if (pll->pll_fck_vco_div2) serdes->i2c_update_bits(client, SER_PMA_LOAD08(pcs_id), PMA_FCK_VCO_MASK, PMA_FCK_VCO_DIV2); else serdes->i2c_update_bits(client, SER_PMA_LOAD08(pcs_id), PMA_FCK_VCO_MASK, PMA_FCK_VCO); if (pll->pll_div4) serdes->i2c_update_bits(client, SER_PMA_LOAD09(pcs_id), PMA_PLL_DIV4_MASK, PMA_PLL_DIV4); else serdes->i2c_update_bits(client, SER_PMA_LOAD09(pcs_id), PMA_PLL_DIV4_MASK, PMA_PLL_DIV8); serdes->i2c_update_bits(client, SER_PMA_LOAD0A(pcs_id), PMA_CLK_8X_DIV_MASK, PMA_CLK_8X_DIV(pll->clk_div)); } void rkx110_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; dev_info(serdes->dev, "%s: %d\n", __func__, enable); if (enable) serdes->i2c_update_bits(client, PCS_REG00(pcs_id), PCS_EN_MASK, PCS_EN); else serdes->i2c_update_bits(client, PCS_REG00(pcs_id), PCS_EN_MASK, PCS_DISABLE); } void rkx110_ser_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 mask, val; if (pma_id) { mask = PMA1_EN_MASK; val = enable ? PMA1_EN : PMA1_DISABLE; } else { mask = PMA0_EN_MASK; val = enable ? PMA0_EN : PMA0_DISABLE; } serdes->i2c_update_bits(client, SER_GRF_SOC_CON7, mask, val); } static void rkx110_linktx_irq_enable(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_LINK_EN); serdes->i2c_write_reg(client, SER_RKLINK_SOURCE_IRQ_EN, TRAIN_DONE_IRQ_OUTPUT_EN | FIFO_UNDERRUN_IRQ_OUTPUT_EN | FIFO_OVERFLOW_IRQ_OUTPUT_EN); } static void rkx110_linktx_irq_disable(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val = 0; serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_LINK_DIS); serdes->i2c_read_reg(client, SER_RKLINK_SOURCE_IRQ_EN, &val); val &= ~(SER_RKLINK_SOURCE_IRQ_EN | TRAIN_DONE_IRQ_OUTPUT_EN | FIFO_UNDERRUN_IRQ_OUTPUT_EN | FIFO_OVERFLOW_IRQ_OUTPUT_EN); serdes->i2c_write_reg(client, SER_RKLINK_SOURCE_IRQ_EN, val); } static void rkx110_linktx_fifo_handler(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 value; serdes->i2c_read_reg(client, SER_RKLINK_FIFO_STATUS, &value); dev_err(serdes->dev, "ser rklink fifo status:0x%x\n", value); if (value & CH1_CMD_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx ch1 cmd fifo underrun\n"); if (value & CH0_CMD_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx ch0 cmd fifo underrun\n"); if (value & DATA1_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx data1 fifo underrun\n"); if (value & DATA0_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx data0 fifo underrun\n"); if (value & AUDIO_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx audio fifo underrun\n"); if (value & LVDS1_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx lvds1 fifo underrun\n"); if (value & LVDS0_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx lvds0 fifo underrun\n"); if (value & DSI_CH1_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx dsi ch1 fifo underrun\n"); if (value & DSI_CH0_FIFO_UNDERRUN) dev_err(serdes->dev, "linktx dsi ch0 fifo underrun\n"); if (value & CH1_CMD_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx ch1 cmd fifo overflow\n"); if (value & CH0_CMD_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx ch0 cmd fifo overflow\n"); if (value & DATA1_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx data1 fifo overflow\n"); if (value & DATA0_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx data0 fifo overflow\n"); if (value & AUDIO_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx audio fifo overflow\n"); if (value & LVDS1_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx lvds1 fifo overflow\n"); if (value & LVDS0_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx lvds0 fifo overflow\n"); if (value & DSI_CH1_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx dsi ch1 fifo overflow\n"); if (value & DSI_CH0_FIFO_OVERFLOW) dev_err(serdes->dev, "linktx dsi ch0 fifo overflow\n"); /* clear fifo status */ serdes->i2c_write_reg(client, SER_RKLINK_FIFO_STATUS, value); } static void rkx110_linktx_irq_handler(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 flag, value; int i = 0; serdes->i2c_read_reg(client, SER_RKLINK_SOURCE_IRQ_EN, &flag); flag &= TRAIN_DONE_IRQ_FLAG | FIFO_UNDERRUN_IRQ_FLAG | FIFO_OVERFLOW_IRQ_FLAG | AUDIO_FM_IRQ_OUTPUT_FLAG; dev_info(serdes->dev, "linktx irq flag:0x%08x\n", flag); while (flag) { switch (flag & BIT(i)) { case TRAIN_DONE_IRQ_FLAG: serdes->i2c_read_reg(client, SER_RKLINK_TRAIN_CTRL, &value); dev_info(serdes->dev, "linktx train done, status:0x%08x\n", value); /* write any thing to train ctrl will clear the train done irq flag */ serdes->i2c_write_reg(client, SER_RKLINK_TRAIN_CTRL, value); break; case FIFO_UNDERRUN_IRQ_FLAG: case FIFO_OVERFLOW_IRQ_FLAG: flag &= ~(FIFO_UNDERRUN_IRQ_FLAG | FIFO_OVERFLOW_IRQ_FLAG); rkx110_linktx_fifo_handler(serdes, dev_id); break; case AUDIO_FM_IRQ_OUTPUT_FLAG: break; default: break; } flag &= ~BIT(i); i++; } } static void rkx110_pcs_irq_enable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val; val = pcs_id ? SER_IRQ_PCS1_EN : SER_IRQ_PCS0_EN; serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); serdes->i2c_write_reg(client, PCS_REG30(pcs_id), PCS_INT_STARTUP(0xffff)); serdes->i2c_write_reg(client, PCS_REG34(pcs_id), PCS_INT_REMOTE_MODE(0xffff)); } static void rkx110_pcs_irq_disable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val; val = pcs_id ? SER_IRQ_PCS1_DIS : SER_IRQ_PCS0_DIS; serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); serdes->i2c_write_reg(client, PCS_REG30(pcs_id), PCS_INT_STARTUP(0)); serdes->i2c_write_reg(client, PCS_REG34(pcs_id), PCS_INT_REMOTE_MODE(0)); } static void rkx110_pcs_irq_handler(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 value; serdes->i2c_read_reg(client, PCS_REG24(pcs_id), &value); dev_info(serdes->dev, "ser pcs%d startup fatal status:0x%08x\n", pcs_id, value); serdes->i2c_read_reg(client, PCS_REG28(pcs_id), &value); dev_info(serdes->dev, "ser pcs%d remote mode fatal status:0x%08x\n", pcs_id, value); /* clear startup fatal status */ serdes->i2c_write_reg(client, PCS_REG1C(pcs_id), 0xffffffff); serdes->i2c_write_reg(client, PCS_REG1C(pcs_id), 0xffff0000); /* clear remote fatal status */ serdes->i2c_write_reg(client, PCS_REG14(pcs_id), 0xffffffff); serdes->i2c_write_reg(client, PCS_REG14(pcs_id), 0xffff0000); } static void rkx110_pma_irq_enable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val; val = pcs_id ? SER_IRQ_PMA_ADAPT1_EN : SER_IRQ_PMA_ADAPT0_EN; serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); serdes->i2c_write_reg(client, SER_PMA_IRQ_EN(pcs_id), FORCE_INITIAL_IRQ_EN | RTERM_ONCE_TIMEOUT_IRQ_EN | PLL_LOCK_TIMEOUT_IRQ_EN); } static void rkx110_pma_irq_disable(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 val; val = pcs_id ? SER_IRQ_PMA_ADAPT1_DIS : SER_IRQ_PMA_ADAPT0_DIS; serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, val); serdes->i2c_write_reg(client, SER_PMA_IRQ_EN(pcs_id), 0); } static void rkx110_pma_irq_handler(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 value; serdes->i2c_read_reg(client, SER_PMA_IRQ_STATUS(pcs_id), &value); dev_info(serdes->dev, "ser pma%d irq status:0x%08x\n", pcs_id, value); if (value & FORCE_INITIAL_PULSE_STATUS) dev_info(serdes->dev, "ser pma trig force initial pulse status\n"); else if (value & RTERM_ONCE_TIMEOUT_STATUS) dev_info(serdes->dev, "ser pma trig rterm once timeout status\n"); else if (value & PLL_LOCK_TIMEOUT_STATUS) dev_info(serdes->dev, "ser pma trig pll lock timeout status\n"); /* clear pma irq status */ serdes->i2c_write_reg(client, SER_PMA_IRQ_STATUS(pcs_id), value); } static void rkx110_remote_irq_enable(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; if (serdes->stream_type == STREAM_DISPLAY) { serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_REMOTE_EN); rkx120_irq_enable(serdes, DEVICE_REMOTE0); } } static void rkx110_remote_irq_disable(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; if (serdes->stream_type == STREAM_DISPLAY) { serdes->i2c_write_reg(client, SER_GRF_IRQ_EN, SER_IRQ_REMOTE_DIS); rkx120_irq_disable(serdes, DEVICE_REMOTE0); } } static void rkx110_remote_irq_handler(struct rk_serdes *serdes, u8 dev_id) { if (serdes->stream_type == STREAM_DISPLAY) rkx120_irq_handler(serdes, DEVICE_REMOTE0); } void rkx110_irq_enable(struct rk_serdes *serdes, u8 dev_id) { /* enable pcs irq */ rkx110_pcs_irq_enable(serdes, 0, dev_id); /* enable dsirx irq */ /* enable gpio irq */ /* enable csihost irq */ /* enable pma_adapt irq */ rkx110_pma_irq_enable(serdes, 0, dev_id); /* enable efuse irq */ /* enable vicap irq */ /* enable remote irq */ rkx110_remote_irq_enable(serdes, dev_id); /* enable ext irq */ /* enable link irq */ rkx110_linktx_irq_enable(serdes, dev_id); } void rkx110_irq_disable(struct rk_serdes *serdes, u8 dev_id) { /* disable pcs irq */ rkx110_pcs_irq_disable(serdes, 0, dev_id); /* disable dsirx irq */ /* disable gpio irq */ /* disable csihost irq */ /* disable pma_adapt irq */ rkx110_pma_irq_disable(serdes, 0, dev_id); /* disable efuse irq */ /* disable vicap irq */ /* disable remote irq and other lane irq*/ rkx110_remote_irq_disable(serdes, dev_id); /* disable ext irq */ /* disable link irq */ rkx110_linktx_irq_disable(serdes, dev_id); } int rkx110_irq_handler(struct rk_serdes *serdes, u8 dev_id) { struct i2c_client *client = serdes->chip[dev_id].client; u32 status, mask; u32 i = 0; serdes->i2c_read_reg(client, SER_GRF_IRQ_EN, &mask); serdes->i2c_read_reg(client, SER_GRF_IRQ_STATUS, &status); dev_info(serdes->dev, "dev%d get the ser irq status:0x%08x\n", dev_id, status); status &= mask; while (status) { switch (status & BIT(i)) { case SER_IRQ_PCS0: rkx110_pcs_irq_handler(serdes, 0, dev_id); break; case SER_IRQ_PCS1: rkx110_pcs_irq_handler(serdes, 1, dev_id); break; case SER_IRQ_DSIRX0: /* TBD */ break; case SER_IRQ_DSIRX1: /* TBD */ break; case SER_IRQ_GPIO0: /* TBD */ break; case SER_IRQ_GPIO1: /* TBD */ break; case SER_IRQ_CSIHOST0: /* TBD */ break; case SER_IRQ_CSIHOST1: /* TBD */ break; case SER_IRQ_PMA_ADAPT0: rkx110_pma_irq_handler(serdes, 0, dev_id); break; case SER_IRQ_PMA_ADAPT1: rkx110_pma_irq_handler(serdes, 1, dev_id); break; case SER_IRQ_EFUSE: /* TBD */ break; case SER_IRQ_VICAP: /* TBD */ break; case SER_IRQ_REMOTE: rkx110_remote_irq_handler(serdes, dev_id); break; case SER_IRQ_EXT: /* TBD */ break; case SER_IRQ_LINK: rkx110_linktx_irq_handler(serdes, dev_id); break; case SER_IRQ_OTHER_LANE: /* TBD */ break; default: break; } status &= ~BIT(i); i++; } return 0; }