From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 03 Jan 2024 09:43:39 +0000 Subject: [PATCH] update kernel to 5.10.198 --- kernel/drivers/mfd/rkx110_x120/rkx110_linktx.c | 685 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 600 insertions(+), 85 deletions(-) diff --git a/kernel/drivers/mfd/rkx110_x120/rkx110_linktx.c b/kernel/drivers/mfd/rkx110_x120/rkx110_linktx.c index 007a825..89cb11a 100644 --- a/kernel/drivers/mfd/rkx110_x120/rkx110_linktx.c +++ b/kernel/drivers/mfd/rkx110_x120/rkx110_linktx.c @@ -55,6 +55,7 @@ #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) @@ -86,11 +87,13 @@ #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) @@ -101,7 +104,33 @@ #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) @@ -144,7 +173,9 @@ #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) @@ -194,6 +225,15 @@ #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, @@ -422,53 +462,124 @@ serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val); } -static int rk_serdes_link_tx_ctrl_enable(struct rk_serdes *serdes, - struct rk_serdes_route *route, - u8 remote_id) +static int rkx110_linktx_ser_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) { - struct hwclk *hwclk = serdes->chip[remote_id].hwclk; - struct i2c_client *client; - u32 ctrl_val, val; - u32 rx_src; - u32 stream_type; + struct i2c_client *client = serdes->chip[dev_id].client; - if (route->stream_type == STREAM_DISPLAY) { - client = serdes->chip[DEVICE_LOCAL].client; - stream_type = SER_STREAM_DISPLAY; - } else { - client = serdes->chip[remote_id].client; - stream_type = SER_STREAM_CAMERA; - } + serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SER_EN, enable ? SER_EN : 0); - serdes->i2c_read_reg(client, RKLINK_TX_SERDES_CTRL, &ctrl_val); + return 0; +} - ctrl_val &= ~(SER_EN | SERDES_DUAL_LANE_EN | SER_CH1_EN | SERDES_MIRROR_EN | - CH1_LVDS_SEL_EN); - ctrl_val |= stream_type; - if (serdes->route_flag & ROUTE_MULTI_LANE) - ctrl_val |= SERDES_DUAL_LANE_EN; - if (serdes->route_flag & ROUTE_MULTI_CHANNEL) - ctrl_val |= SER_CH1_EN; - if (serdes->route_flag & ROUTE_MULTI_MIRROR) - ctrl_val |= SERDES_MIRROR_EN; - if (serdes->route_flag & ROUTE_MULTI_LVDS_INPUT) - ctrl_val |= CH1_LVDS_SEL_EN; +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_write_reg(client, RKLINK_TX_SERDES_CTRL, ctrl_val); + serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SERDES_DUAL_LANE_EN, + enable ? SERDES_DUAL_LANE_EN : 0); - serdes->i2c_read_reg(client, RKLINK_TX_VIDEO_CTRL, &val); - rx_src = rk_serdes_get_stream_source(serdes, route->local_port0); - val |= rx_src; - serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val); + return 0; +} - 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)); - } +void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) +{ + struct i2c_client *client = serdes->chip[dev_id].client; - ctrl_val |= SER_EN; - serdes->i2c_write_reg(client, RKLINK_TX_SERDES_CTRL, ctrl_val); + 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; } @@ -479,22 +590,22 @@ 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 == 0) { - 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)); - } else if (id == 1) { + 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 { - return 0; + 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 */ @@ -507,17 +618,25 @@ value = DSI_VFP(vm->vfront_porch); value |= DSI_VBP(vm->vback_porch); value |= DSI_VSA(vm->vsync_len); - serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC2(id), value); + serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC2(id), DSI_DST_VPORCH_MASK, value); - if (id) - type = (serdes->route_flag & ROUTE_MULTI_CHANNEL) ? DSI_0_DST(0) : DSI_0_DST(2); - else - type = (serdes->route_flag & ROUTE_MULTI_CHANNEL) ? DSI_0_DST(3) : DSI_0_DST(1); + 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 (serdes->dsi_rx.mode_flags & SERDES_MIPI_DSI_MODE_VIDEO) + if (dsi->mode_flags & SERDES_MIPI_DSI_MODE_VIDEO) delay_length = vm->hsync_len + vm->hback_porch + vm->hactive + vm->hfront_porch; else @@ -531,33 +650,12 @@ /* config SER_RKLINK_DSI_REC0 */ value = DSI_REC_START; - if (!(serdes->dsi_rx.mode_flags & SERDES_MIPI_DSI_MODE_VIDEO)) + 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_linktx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route) -{ - u8 remote_id = 0; - - rk_serdes_link_tx_ctrl_enable(serdes, route, remote_id); - - if (route->local_port0 & RK_SERDES_DSI_RX0) { - rk_serdes_link_tx_dsi_enable(serdes, route, 0); - if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT) - rk_serdes_link_tx_dsi_enable(serdes, route, 1); - } - - if (route->local_port0 & RK_SERDES_DSI_RX1) { - rk_serdes_link_tx_dsi_enable(serdes, route, 1); - if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT) - rk_serdes_link_tx_dsi_enable(serdes, route, 0); - } return 0; } @@ -583,24 +681,96 @@ return 0; } -int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route) +static int rkx110_display_linktx_ctrl_enable(struct rk_serdes *serdes, + struct rk_serdes_route *route, + u8 dev_id) { - rk110_linktx_cfg(serdes, route); + 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->route_flag & ROUTE_MULTI_LANE) { + if (serdes->lane_nr == 2) { rk110_ser_pcs_cfg(serdes, route, 1); rk110_ser_pma_cfg(serdes, route, 1); } 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); } void rkx110_linktx_channel_enable(struct rk_serdes *serdes, u8 ch_id, u8 dev_id, bool enable) @@ -636,7 +806,7 @@ } } -void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id) +int rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id) { struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client; u32 val; @@ -656,6 +826,8 @@ 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, @@ -736,3 +908,346 @@ 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; +} -- Gitblit v1.6.2