diff --git a/drivers/mfd/rkx110_x120/Makefile b/drivers/mfd/rkx110_x120/Makefile index db4f6726982f..d22fa9163327 100644 --- a/drivers/mfd/rkx110_x120/Makefile +++ b/drivers/mfd/rkx110_x120/Makefile @@ -12,6 +12,7 @@ rkx110_x120-objs := \ rkx110_combrxphy.o \ rkx110_dsi_rx.o \ rkx110_x120_core.o \ + rkx110_x120_display.o\ rkx110_linktx.o \ rkx110.o \ rkx120.o \ diff --git a/drivers/mfd/rkx110_x120/rkx110.c b/drivers/mfd/rkx110_x120/rkx110.c index 0e3fc4f7c274..8b80aff6733a 100644 --- a/drivers/mfd/rkx110_x120/rkx110.c +++ b/drivers/mfd/rkx110_x120/rkx110.c @@ -295,9 +295,11 @@ int rkx110_rgb_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route int rkx110_lvds_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, int id) { - rkx110_combrxphy_set_mode(serdes, COMBRX_PHY_MODE_VIDEO_LVDS); + struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); + struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy; - rkx110_combrxphy_power_on(serdes, id ? COMBPHY_1 : COMBPHY_0); + rkx110_combrxphy_set_mode(combrxphy, COMBRX_PHY_MODE_VIDEO_LVDS); + rkx110_combrxphy_power_on(serdes, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0); return 0; } diff --git a/drivers/mfd/rkx110_x120/rkx110_combrxphy.c b/drivers/mfd/rkx110_x120/rkx110_combrxphy.c index 4152728aec9b..fb8eaa0ce645 100644 --- a/drivers/mfd/rkx110_x120/rkx110_combrxphy.c +++ b/drivers/mfd/rkx110_x120/rkx110_combrxphy.c @@ -114,15 +114,18 @@ #define LVDS0_MSBSEL(x) HIWORD_UPDATE(x, BIT(2), 2) static void -rkx110_combrxphy_dsi_timing_init(struct rk_serdes *ser, enum comb_phy_id id) +rkx110_combrxphy_dsi_timing_init(struct rk_serdes *ser, + struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { } -static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, enum comb_phy_id id) +static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, + struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { - struct hwclk *hwclk = ser->chip[DEVICE_LOCAL].hwclk; - struct rkx110_combrxphy *combrxphy = &ser->combrxphy; - struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + struct hwclk *hwclk = ser->chip[dev_id].hwclk; + struct i2c_client *client = ser->chip[dev_id].client; u32 val = 0; u32 grf_base; @@ -144,7 +147,7 @@ static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, enum comb_phy_i serdes_combphy_get_default_config(combrxphy->rate, &combrxphy->mipi_dphy_cfg); - switch (ser->dsi_rx.lanes) { + switch (combrxphy->lanes) { case 4: val |= LANE3_ENABLE(1); fallthrough; @@ -164,12 +167,14 @@ static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, enum comb_phy_i ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0, PHY_MODE(COMBRX_PHY_MODE_VIDEO_MIPI) | val); - rkx110_combrxphy_dsi_timing_init(ser, id); + rkx110_combrxphy_dsi_timing_init(ser, combrxphy, dev_id, id); } -static void rkx110_combrxphy_dsi_power_off(struct rk_serdes *ser, enum comb_phy_id id) +static void rkx110_combrxphy_dsi_power_off(struct rk_serdes *ser, + struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { - struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + struct i2c_client *client = ser->chip[dev_id].client; u32 grf_base; grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE; @@ -178,9 +183,11 @@ static void rkx110_combrxphy_dsi_power_off(struct rk_serdes *ser, enum comb_phy_ LANE1_ENABLE(0) | LANE0_ENABLE(0)); } -static void rkx110_combrxphy_lvds_power_on(struct rk_serdes *ser, enum comb_phy_id id) +static void rkx110_combrxphy_lvds_power_on(struct rk_serdes *ser, + struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { - struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + struct i2c_client *client = ser->chip[dev_id].client; u32 grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE; u32 val; int ret; @@ -209,9 +216,11 @@ static void rkx110_combrxphy_lvds_power_on(struct rk_serdes *ser, enum comb_phy_ LVDS_RX1_PD(0) | LVDS_RX0_PD(0)); } -static void rkx110_combrxphy_lvds_power_off(struct rk_serdes *ser, enum comb_phy_id id) +static void rkx110_combrxphy_lvds_power_off(struct rk_serdes *ser, + struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { - struct i2c_client *client = ser->chip[DEVICE_LOCAL].client; + struct i2c_client *client = ser->chip[dev_id].client; u32 grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE; ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0, @@ -219,62 +228,65 @@ static void rkx110_combrxphy_lvds_power_off(struct rk_serdes *ser, enum comb_phy LVDS_RX1_PD(1) | LVDS_RX0_PD(1)); } -static void rkx110_combrxphy_lvds_camera_power_on(struct rk_serdes *ser, enum comb_phy_id id) +static void rkx110_combrxphy_lvds_camera_power_on(struct rk_serdes *ser, + struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { } -static void rkx110_combrxphy_lvds_camera_power_off(struct rk_serdes *ser, enum comb_phy_id id) +static void rkx110_combrxphy_lvds_camera_power_off(struct rk_serdes *ser, + struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { } -void rkx110_combrxphy_power_on(struct rk_serdes *ser, enum comb_phy_id id) +void rkx110_combrxphy_power_on(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { - struct rkx110_combrxphy *combrxphy = &ser->combrxphy; - switch (combrxphy->mode) { case COMBRX_PHY_MODE_VIDEO_MIPI: - rkx110_combrxphy_dsi_power_on(ser, id); + rkx110_combrxphy_dsi_power_on(ser, combrxphy, dev_id, id); break; case COMBRX_PHY_MODE_VIDEO_LVDS: - rkx110_combrxphy_lvds_power_on(ser, id); + rkx110_combrxphy_lvds_power_on(ser, combrxphy, dev_id, id); break; case COMBRX_PHY_MODE_LVDS_CAMERA: - rkx110_combrxphy_lvds_camera_power_on(ser, id); + rkx110_combrxphy_lvds_camera_power_on(ser, combrxphy, dev_id, id); break; default: break; } } -void rkx110_combrxphy_power_off(struct rk_serdes *ser, enum comb_phy_id id) +void rkx110_combrxphy_power_off(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id) { - struct rkx110_combrxphy *combrxphy = &ser->combrxphy; - switch (combrxphy->mode) { case COMBRX_PHY_MODE_VIDEO_MIPI: - rkx110_combrxphy_dsi_power_off(ser, id); + rkx110_combrxphy_dsi_power_off(ser, combrxphy, dev_id, id); break; case COMBRX_PHY_MODE_VIDEO_LVDS: - rkx110_combrxphy_lvds_power_off(ser, id); + rkx110_combrxphy_lvds_power_off(ser, combrxphy, dev_id, id); break; case COMBRX_PHY_MODE_LVDS_CAMERA: - rkx110_combrxphy_lvds_camera_power_off(ser, id); + rkx110_combrxphy_lvds_camera_power_off(ser, combrxphy, dev_id, id); break; default: break; } } -void rkx110_combrxphy_set_rate(struct rk_serdes *ser, u64 rate) +void rkx110_combrxphy_set_rate(struct rkx110_combrxphy *combrxphy, u64 rate) { - struct rkx110_combrxphy *combrxphy = &ser->combrxphy; - combrxphy->rate = rate; } -void rkx110_combrxphy_set_mode(struct rk_serdes *ser, enum combrx_phy_mode mode) +void rkx110_combrxphy_set_lanes(struct rkx110_combrxphy *combrxphy, uint8_t lanes) { - struct rkx110_combrxphy *combrxphy = &ser->combrxphy; + combrxphy->lanes = lanes; +} +void rkx110_combrxphy_set_mode(struct rkx110_combrxphy *combrxphy, enum combrx_phy_mode mode) +{ combrxphy->mode = mode; } diff --git a/drivers/mfd/rkx110_x120/rkx110_dsi_rx.c b/drivers/mfd/rkx110_x120/rkx110_dsi_rx.c index 8c012caa5063..eecfe97f1808 100644 --- a/drivers/mfd/rkx110_x120/rkx110_dsi_rx.c +++ b/drivers/mfd/rkx110_x120/rkx110_dsi_rx.c @@ -55,7 +55,9 @@ static inline int dsi_rx_update_bits(struct rk_serdes *ser, void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route, int id) { - struct rkx110_dsi_rx *dsi = &ser->dsi_rx; + struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); + struct rkx110_dsi_rx *dsi = &sd_panel->dsi_rx; + struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy; const struct videomode *vm = &route->vm; unsigned long pixelclock; u32 hactive, vactive; @@ -87,9 +89,10 @@ void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route, rate = DIV_ROUND_CLOSEST_ULL(pixelclock, dsi->lanes); - rkx110_combrxphy_set_mode(ser, COMBRX_PHY_MODE_VIDEO_MIPI); - rkx110_combrxphy_set_rate(ser, rate * MSEC_PER_SEC); - rkx110_combrxphy_power_on(ser, id ? COMBPHY_1 : COMBPHY_0); + rkx110_combrxphy_set_mode(combrxphy, COMBRX_PHY_MODE_VIDEO_MIPI); + rkx110_combrxphy_set_rate(combrxphy, rate * MSEC_PER_SEC); + rkx110_combrxphy_set_lanes(combrxphy, dsi->lanes); + rkx110_combrxphy_power_on(ser, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0); csi_base = id ? RKX110_CSI2HOST1_BASE : RKX110_CSI2HOST0_BASE; dsirx_base = id ? RKX110_DSI_RX1_BASE : RKX110_DSI_RX0_BASE; @@ -120,5 +123,8 @@ void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route, void rkx110_dsi_rx_disable(struct rk_serdes *ser, struct rk_serdes_route *route, int id) { - rkx110_combrxphy_power_off(ser, id ? COMBPHY_1 : COMBPHY_0); + struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); + struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy; + + rkx110_combrxphy_power_off(ser, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0); } diff --git a/drivers/mfd/rkx110_x120/rkx110_linktx.c b/drivers/mfd/rkx110_x120/rkx110_linktx.c index 3052dac553b6..4506aa13b54f 100644 --- a/drivers/mfd/rkx110_x120/rkx110_linktx.c +++ b/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,6 +87,7 @@ #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) @@ -459,67 +461,93 @@ void rkx110_set_stream_source(struct rk_serdes *serdes, int local_port, u8 dev_i 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; - struct videomode *vm = &route->vm; - u32 ctrl_val, val; - u32 rx_src; - u32 stream_type; - u32 length; + 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; - 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 - */ - length = vm->hactive * 24 / 32 / 16; - length = (length + 15) / 16 * 16; - val &= ~VIDEO_REPKT_LENGTH(0xffff); - val |= VIDEO_REPKT_LENGTH(length); - } - 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); +} + +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; } @@ -530,22 +558,22 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd 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 */ @@ -558,17 +586,25 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd 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 @@ -582,7 +618,7 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd /* 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); @@ -592,27 +628,6 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd 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; -} - static int rk110_ser_pcs_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 pcs_id) { struct i2c_client *client; @@ -634,12 +649,91 @@ static int rk110_ser_pma_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r 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); } @@ -647,13 +741,6 @@ int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route 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) { struct i2c_client *client = serdes->chip[dev_id].client; @@ -687,7 +774,7 @@ void rkx110_linktx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 } } -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; @@ -707,6 +794,8 @@ void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id) 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, diff --git a/drivers/mfd/rkx110_x120/rkx110_x120.h b/drivers/mfd/rkx110_x120/rkx110_x120.h index 67e544fb7b47..493980a9c505 100644 --- a/drivers/mfd/rkx110_x120/rkx110_x120.h +++ b/drivers/mfd/rkx110_x120/rkx110_x120.h @@ -142,11 +142,14 @@ struct rkx120_combtxphy { struct rkx110_combrxphy { enum combrx_phy_mode mode; + uint8_t lanes; u64 rate; struct configure_opts_combphy mipi_dphy_cfg; }; struct rkx120_dsi_tx { + struct rkx120_combtxphy *combtxphy; + int bpp; /* 24/18/16*/ enum serdes_dsi_bus_format bus_format; enum serdes_dsi_mode_flags mode_flags; @@ -221,6 +224,7 @@ struct rk_serdes_route { u32 remote0_port1; u32 remote1_port0; u32 remote1_port1; + u32 route_flag; }; struct rk_serdes_chip { @@ -282,12 +286,10 @@ struct rk_serdes { struct videomode *vm; u32 stream_type; u32 version; - u32 route_flag; u8 remote_nr; - struct rkx110_combrxphy combrxphy; - struct rkx110_dsi_rx dsi_rx; - struct rkx120_combtxphy combtxphy; - struct rkx120_dsi_tx dsi_tx; + u8 lane_nr; + u8 channel_nr; + u8 route_nr; int (*i2c_read_reg)(struct i2c_client *client, u32 addr, u32 *value); int (*i2c_write_reg)(struct i2c_client *client, u32 addr, u32 value); @@ -318,13 +320,12 @@ struct panel_cmds { int cmd_cnt; }; +struct rk_serdes_panel; struct rk_serdes_panel { struct drm_panel panel; struct device *dev; struct rk_serdes *parent; - struct rk_serdes_route route; - unsigned int bus_format; - int link_mode; + struct rk_serdes_panel *secondary; struct panel_cmds *on_cmds; struct panel_cmds *off_cmds; @@ -332,14 +333,25 @@ struct rk_serdes_panel { struct regulator *supply; struct gpio_desc *enable_gpio; struct gpio_desc *reset_gpio; + + struct rk_serdes_route route; + struct rkx110_combrxphy combrxphy; + struct rkx110_dsi_rx dsi_rx; + struct rkx120_combtxphy combtxphy; + struct rkx120_dsi_tx dsi_tx; + + unsigned int bus_format; + unsigned int id; + bool multi_panel; }; -int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route); +int rkx110_display_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route); void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable); void rkx110_linktx_channel_enable(struct rk_serdes *serdes, u8 ch_id, u8 dev_id, bool enable); void rkx120_linkrx_engine_enable(struct rk_serdes *serdes, u8 en_id, u8 dev_id, bool enable); void rkx110_set_stream_source(struct rk_serdes *serdes, int local_port, u8 dev_id); -int rkx120_linkrx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id); +int rkx120_display_linkrx_enable(struct rk_serdes *serdes, + struct rk_serdes_route *route, u8 remote_id); int rkx120_rgb_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id); int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id, u8 phy_id); @@ -357,8 +369,8 @@ void rkx110_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_ void rkx120_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_id); void rkx110_ser_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 remote_id); void rkx120_des_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 remote_id); -void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id); -void rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id); +int rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id); +int rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id); void rkx110_x120_pattern_gen_debugfs_create_file(struct pattern_gen *pattern_gen, struct rk_serdes_chip *chip, struct dentry *dentry); diff --git a/drivers/mfd/rkx110_x120/rkx110_x120_core.c b/drivers/mfd/rkx110_x120/rkx110_x120_core.c index 603f43fa82f9..ee9e962c944b 100644 --- a/drivers/mfd/rkx110_x120/rkx110_x120_core.c +++ b/drivers/mfd/rkx110_x120/rkx110_x120_core.c @@ -15,6 +15,7 @@ #include #include #include "rkx110_x120.h" +#include "rkx110_x120_display.h" #include "rkx110_reg.h" #include "rkx110_dsi_rx.h" #include "rkx120_dsi_tx.h" @@ -27,6 +28,10 @@ static const struct mfd_cell rkx110_x120_devs[] = { .name = "rockchip-serdes-panel", .of_compatible = "rockchip,serdes-panel", }, + { + .name = "rockchip-serdes-panel1", + .of_compatible = "rockchip,serdes-panel", + }, { .name = "rkx120-pwm0", .of_compatible = "rockchip,rkx120-pwm", @@ -145,26 +150,40 @@ static bool rk_serdes_debug_mode(struct rk_serdes *serdes) return serdes->rkx110_debug || serdes->rkx120_debug; } -static void rk_serdes_wait_link_ready(struct rk_serdes *serdes) +static int rk_serdes_wait_link_ready(struct rk_serdes *serdes) { + int ret; + if (serdes->stream_type == STREAM_DISPLAY) { - rkx110_linktx_wait_link_ready(serdes, 0); - if (serdes->route_flag & ROUTE_MULTI_LANE) { + ret = rkx110_linktx_wait_link_ready(serdes, 0); + if (ret) + return ret; + + if (serdes->lane_nr == 2) { rkx110_ser_pma_enable(serdes, true, 1, DEVICE_LOCAL); - if (!(serdes->route_flag & ROUTE_MULTI_REMOTE)) + if (!(serdes->remote_nr == 2)) rkx120_des_pma_enable(serdes, true, 1, DEVICE_REMOTE0); - rkx110_linktx_wait_link_ready(serdes, 1); + ret = rkx110_linktx_wait_link_ready(serdes, 1); + if (ret) + return ret; } } else { - rkx120_linkrx_wait_link_ready(serdes, 0); - if (serdes->route_flag & ROUTE_MULTI_LANE) { + ret = rkx120_linkrx_wait_link_ready(serdes, 0); + if (ret) + return ret; + + if (serdes->lane_nr == 2) { rkx120_des_pma_enable(serdes, true, 1, DEVICE_LOCAL); - if (!(serdes->route_flag & ROUTE_MULTI_REMOTE)) + if (!(serdes->remote_nr == 2)) rkx110_ser_pma_enable(serdes, true, 1, DEVICE_REMOTE0); - rkx120_linkrx_wait_link_ready(serdes, 1); + ret = rkx120_linkrx_wait_link_ready(serdes, 1); + if (ret) + return ret; } } + + return 0; } static void rk_serdes_print_rate(struct rk_serdes *serdes, enum rk_serdes_rate rate) @@ -336,9 +355,9 @@ static void rk_serdes_set_rate(struct rk_serdes *serdes, enum rk_serdes_rate rat if (serdes->stream_type == STREAM_DISPLAY) { rkx110_pma_set_rate(serdes, &rkx110_pll, 0, DEVICE_LOCAL); rkx120_pma_set_rate(serdes, &rkx120_pll, 0, DEVICE_REMOTE0); - if (serdes->route_flag & ROUTE_MULTI_LANE) { + if (serdes->lane_nr == 2) { rkx110_pma_set_rate(serdes, &rkx110_pll, 1, DEVICE_LOCAL); - if (serdes->route_flag & ROUTE_MULTI_REMOTE) + if (serdes->remote_nr == 2) rkx120_pma_set_rate(serdes, &rkx120_pll, 0, DEVICE_REMOTE1); else rkx120_pma_set_rate(serdes, &rkx120_pll, 1, DEVICE_REMOTE0); @@ -349,9 +368,9 @@ static void rk_serdes_set_rate(struct rk_serdes *serdes, enum rk_serdes_rate rat } else { rkx120_pma_set_rate(serdes, &rkx120_pll, 0, DEVICE_LOCAL); rkx110_pma_set_rate(serdes, &rkx110_pll, 0, DEVICE_REMOTE0); - if (serdes->route_flag & ROUTE_MULTI_LANE) { + if (serdes->lane_nr == 2) { rkx120_pma_set_rate(serdes, &rkx120_pll, 1, DEVICE_LOCAL); - if (serdes->route_flag & ROUTE_MULTI_REMOTE) + if (serdes->remote_nr == 2) rkx110_pma_set_rate(serdes, &rkx110_pll, 0, DEVICE_REMOTE1); else rkx110_pma_set_rate(serdes, &rkx110_pll, 1, DEVICE_REMOTE0); @@ -366,225 +385,6 @@ static void rk_serdes_set_rate(struct rk_serdes *serdes, enum rk_serdes_rate rat serdes->rate = rate; } -static int rk_serdes_route_prepare(struct rk_serdes *serdes, struct rk_serdes_route *route) -{ - if (rk_serdes_debug_mode(serdes)) - return 0; - - if (route->stream_type == STREAM_DISPLAY) { - switch (route->local_port0) { - case RK_SERDES_RGB_RX: - rkx110_rgb_rx_enable(serdes, route); - break; - case RK_SERDES_LVDS_RX0: - rkx110_lvds_rx_enable(serdes, route, 0); - if (serdes->route_flag & ROUTE_MULTI_LVDS_INPUT) - rkx110_lvds_rx_enable(serdes, route, 1); - break; - case RK_SERDES_LVDS_RX1: - rkx110_lvds_rx_enable(serdes, route, 1); - if (serdes->route_flag & ROUTE_MULTI_LVDS_INPUT) - rkx110_lvds_rx_enable(serdes, route, 0); - break; - case RK_SERDES_DUAL_LVDS_RX: - rkx110_lvds_rx_enable(serdes, route, 0); - rkx110_lvds_rx_enable(serdes, route, 1); - break; - case RK_SERDES_DSI_RX0: - rkx110_dsi_rx_enable(serdes, route, 0); - if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT) - rkx110_dsi_rx_enable(serdes, route, 1); - break; - case RK_SERDES_DSI_RX1: - rkx110_dsi_rx_enable(serdes, route, 1); - if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT) - rkx110_dsi_rx_enable(serdes, route, 0); - break; - default: - dev_info(serdes->dev, "undefined local port0"); - return -EINVAL; - } - - rkx110_linktx_enable(serdes, route); - - rkx120_linkrx_enable(serdes, route, DEVICE_REMOTE0); - if (serdes->route_flag & ROUTE_MULTI_REMOTE) - rkx120_linkrx_enable(serdes, route, DEVICE_REMOTE1); - - if (route->remote0_port0 & RK_SERDES_DSI_TX0) - rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE0); - if (route->remote1_port0 & RK_SERDES_DSI_TX0) - rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE1); - } else { - /* for camera stream */ - } - - return 0; -} - -static int rk_serdes_route_enable(struct rk_serdes *serdes, struct rk_serdes_route *route) -{ - if (rk_serdes_debug_mode(serdes)) - return 0; - - if (route->stream_type == STREAM_DISPLAY) { - switch (route->remote0_port0) { - case RK_SERDES_RGB_TX: - rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE0); - break; - case RK_SERDES_LVDS_TX0: - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0); - break; - case RK_SERDES_LVDS_TX1: - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1); - break; - case RK_SERDES_DUAL_LVDS_TX: - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0); - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1); - break; - case RK_SERDES_DSI_TX0: - rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE0); - break; - default: - dev_err(serdes->dev, "undefined remote0_port0\n"); - return -EINVAL; - } - - if (serdes->route_flag & ROUTE_MULTI_REMOTE) { - switch (route->remote1_port0) { - case RK_SERDES_RGB_TX: - rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE1); - break; - case RK_SERDES_LVDS_TX0: - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0); - break; - case RK_SERDES_LVDS_TX1: - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1); - break; - case RK_SERDES_DUAL_LVDS_TX: - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0); - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1); - break; - case RK_SERDES_DSI_TX0: - rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE1); - break; - default: - dev_err(serdes->dev, "undefined remote1_port0\n"); - return -EINVAL; - } - } else if (serdes->route_flag & ROUTE_MULTI_CHANNEL) { - if (route->remote0_port1 & RK_SERDES_LVDS_TX0) { - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0); - } else if (route->remote0_port1 & RK_SERDES_LVDS_TX1) { - rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1); - } else { - dev_err(serdes->dev, "undefined remote0_port1\n"); - return -EINVAL; - } - } - - if (serdes->version == SERDES_V1) { - rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, true); - rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, true); - } - - rkx110_linktx_video_enable(serdes, DEVICE_LOCAL, true); - } else { - /* for camera stream */ - } - - return 0; -} - -static int rk_serdes_route_disable(struct rk_serdes *serdes, struct rk_serdes_route *route) -{ - if (route->stream_type == STREAM_DISPLAY) { - if (route->remote0_port0 & RK_SERDES_DSI_TX0) - rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE0); - - if (serdes->version == SERDES_V1) { - rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, false); - rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, false); - - if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) { - rkx110_set_stream_source(serdes, RK_SERDES_RGB_RX, - DEVICE_LOCAL); - hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX); - hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX); - hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX); - } - - if ((route->local_port0 == RK_SERDES_DSI_RX0) || - (route->local_port1 == RK_SERDES_DSI_RX0)) { - serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, - 0x1400140); - hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, - RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX); - hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX); - } - - if ((route->local_port0 == RK_SERDES_DSI_RX1) || - (route->local_port1 == RK_SERDES_DSI_RX1)) { - serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, - 0x2800280); - hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, - RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX); - hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX); - } - } - } - - return 0; -} - -static int rk_serdes_route_unprepare(struct rk_serdes *serdes, struct rk_serdes_route *route) -{ - if (route->stream_type == STREAM_DISPLAY) { - if (route->remote0_port0 & RK_SERDES_DSI_TX0) - rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE0); - - if (serdes->version == SERDES_V1) { - if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) { - hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX); - hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX); - hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX); - rkx110_set_stream_source(serdes, RK_SERDES_DUAL_LVDS_RX, - DEVICE_LOCAL); - } - - if ((route->local_port0 == RK_SERDES_DSI_RX0) || - (route->local_port1 == RK_SERDES_DSI_RX0)) { - hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX); - hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, - RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX); - serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, - 0x1400000); - } - - if ((route->local_port0 == RK_SERDES_DSI_RX1) || - (route->local_port1 == RK_SERDES_DSI_RX1)) { - hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, - RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX); - hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, - RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX); - serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, - 0x2800000); - } - } - } - - return 0; -} - static int rk_serdes_set_hwpin(struct rk_serdes *serdes, struct i2c_client *client, int pintype, int bank, uint32_t mpins, uint32_t param) { @@ -610,11 +410,17 @@ static void rk_serdes_add_callback(struct rk_serdes *serdes) serdes->i2c_read_reg = rk_serdes_i2c_read; serdes->i2c_write_reg = rk_serdes_i2c_write; serdes->i2c_update_bits = rk_serdes_i2c_update_bits; - serdes->route_prepare = rk_serdes_route_prepare; - serdes->route_enable = rk_serdes_route_enable; - serdes->route_disable = rk_serdes_route_disable; - serdes->route_unprepare = rk_serdes_route_unprepare; serdes->set_hwpin = rk_serdes_set_hwpin; + + if (rk_serdes_debug_mode(serdes)) + return; + + if (serdes->stream_type == STREAM_DISPLAY) { + serdes->route_prepare = rk_serdes_display_route_prepare; + serdes->route_enable = rk_serdes_display_route_enable; + serdes->route_disable = rk_serdes_display_route_disable; + serdes->route_unprepare = rk_serdes_display_route_unprepare; + } } static int rk_serdes_passthrough_init(struct rk_serdes *serdes) @@ -956,6 +762,9 @@ static int rk_serdes_add_remote_i2c_device(struct rk_serdes *serdes) i2c_set_clientdata(client, serdes); } + if (serdes->remote_nr == 2) + serdes->lane_nr = 2; + if (serdes->remote_nr == 0) return -ENODEV; @@ -1071,6 +880,7 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic struct device_node *disp_np; struct rk_serdes *serdes; int ret; + bool dual_lane; serdes = devm_kzalloc(dev, sizeof(*serdes), GFP_KERNEL); if (!serdes) @@ -1161,6 +971,11 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic if (ret) return ret; + if (serdes->remote_nr != 2) { + dual_lane = device_property_read_bool(dev, "dual-lane"); + serdes->lane_nr = dual_lane ? 2 : 1; + } + ret = mfd_add_devices(dev, -1, rkx110_x120_devs, ARRAY_SIZE(rkx110_x120_devs), NULL, 0, NULL); if (ret) { @@ -1198,6 +1013,9 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic rk_serdes_irq_enable(serdes); enable_irq(serdes->irq); + if (serdes->stream_type == STREAM_DISPLAY) + rk_serdes_display_route_init(serdes); + out: rk_serdes_debugfs_init(serdes); diff --git a/drivers/mfd/rkx110_x120/rkx110_x120_display.c b/drivers/mfd/rkx110_x120/rkx110_x120_display.c new file mode 100644 index 000000000000..bc92c7a333a5 --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_x120_display.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Zhang Yubing + */ + +#include "hal/cru_api.h" +#include "rkx110_x120.h" +#include "rkx110_dsi_rx.h" +#include "rkx120_dsi_tx.h" + +int rk_serdes_display_route_prepare(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + u32 local_port; + + local_port = route->local_port0 ? route->local_port0 : route->local_port1; + + switch (local_port) { + case RK_SERDES_RGB_RX: + rkx110_rgb_rx_enable(serdes, route); + break; + case RK_SERDES_LVDS_RX0: + rkx110_lvds_rx_enable(serdes, route, 0); + break; + case RK_SERDES_LVDS_RX1: + rkx110_lvds_rx_enable(serdes, route, 1); + break; + case RK_SERDES_DUAL_LVDS_RX: + rkx110_lvds_rx_enable(serdes, route, 0); + rkx110_lvds_rx_enable(serdes, route, 1); + break; + case RK_SERDES_DSI_RX0: + rkx110_dsi_rx_enable(serdes, route, 0); + break; + case RK_SERDES_DSI_RX1: + rkx110_dsi_rx_enable(serdes, route, 1); + break; + default: + dev_info(serdes->dev, "undefined local port\n"); + } + + rkx110_display_linktx_enable(serdes, route); + + if (route->local_port0) { + rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE0); + if (serdes->remote_nr == 2 && serdes->route_nr != 2) + rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE1); + + if (route->remote0_port0 & RK_SERDES_DSI_TX0) + rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE0); + if (route->remote1_port0 & RK_SERDES_DSI_TX0) + rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE1); + } + + if (route->local_port1) { + if (serdes->remote_nr == 2) + rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE1); + else + rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE0); + + if (route->remote1_port0 & RK_SERDES_DSI_TX0) + rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE1); + } + + return 0; +} + +static int rk_serdes_display_video_start(struct rk_serdes *serdes, + struct rk_serdes_route *route, bool enable) +{ + if (route->local_port0) { + if (route->route_flag & ROUTE_MULTI_CHANNEL) { + if (route->route_flag & ROUTE_MULTI_REMOTE) { + rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable); + rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, enable); + } else { + rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable); + rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, enable); + } + rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, enable); + rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, enable); + } else { + rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable); + rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, enable); + } + } else { + if (serdes->remote_nr == 2) + rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, enable); + else + rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, enable); + + rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, enable); + } + + return 0; +} + +int rk_serdes_display_route_init(struct rk_serdes *serdes) +{ + rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, false); + if (serdes->remote_nr == 2) + rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, false); + else + rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, false); + + rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, false); + rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, false); + + return 0; +} + +int rk_serdes_display_route_enable(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + if (route->remote0_port0) { + switch (route->remote0_port0) { + case RK_SERDES_RGB_TX: + rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE0); + break; + case RK_SERDES_LVDS_TX0: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0); + break; + case RK_SERDES_LVDS_TX1: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1); + break; + case RK_SERDES_DUAL_LVDS_TX: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0); + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1); + break; + case RK_SERDES_DSI_TX0: + rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE0); + break; + default: + dev_err(serdes->dev, "undefined remote0_port0\n"); + break; + } + } + + if (route->remote1_port0) { + switch (route->remote1_port0) { + case RK_SERDES_RGB_TX: + rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE1); + break; + case RK_SERDES_LVDS_TX0: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0); + break; + case RK_SERDES_LVDS_TX1: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1); + break; + case RK_SERDES_DUAL_LVDS_TX: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0); + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1); + break; + case RK_SERDES_DSI_TX0: + rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE1); + break; + default: + dev_err(serdes->dev, "undefined remote1_port0\n"); + break; + } + } + + if (route->remote0_port1) { + switch (route->remote0_port1) { + case RK_SERDES_LVDS_TX0: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0); + break; + case RK_SERDES_LVDS_TX1: + rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1); + break; + default: + dev_err(serdes->dev, "undefined remote0_port1\n"); + break; + } + } + + if (serdes->version == SERDES_V1) + rk_serdes_display_video_start(serdes, route, true); + + rkx110_linktx_video_enable(serdes, DEVICE_LOCAL, true); + + return 0; +} + +int rk_serdes_display_route_disable(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + if (route->remote0_port0 & RK_SERDES_DSI_TX0) + rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE0); + + if (route->remote1_port0 & RK_SERDES_DSI_TX0) + rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE1); + + if (serdes->version == SERDES_V1) { + rk_serdes_display_video_start(serdes, route, false); + + if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) { + rkx110_set_stream_source(serdes, RK_SERDES_RGB_RX, + DEVICE_LOCAL); + hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX); + hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX); + hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX); + } + + if ((route->local_port0 == RK_SERDES_DSI_RX0) || + (route->local_port1 == RK_SERDES_DSI_RX0)) { + serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, + 0x1400140); + hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, + RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX); + hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX); + } + + if ((route->local_port0 == RK_SERDES_DSI_RX1) || + (route->local_port1 == RK_SERDES_DSI_RX1)) { + serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, + 0x2800280); + hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, + RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX); + hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX); + } + } + + return 0; +} + +int rk_serdes_display_route_unprepare(struct rk_serdes *serdes, struct rk_serdes_route *route) +{ + if (route->remote0_port0 & RK_SERDES_DSI_TX0) + rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE0); + + if (route->remote1_port0 & RK_SERDES_DSI_TX0) + rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE1); + + if (serdes->version == SERDES_V1) { + if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) { + hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX); + hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX); + hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX); + rkx110_set_stream_source(serdes, RK_SERDES_DUAL_LVDS_RX, + DEVICE_LOCAL); + } + + if ((route->local_port0 == RK_SERDES_DSI_RX0) || + (route->local_port1 == RK_SERDES_DSI_RX0)) { + hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX); + hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, + RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX); + serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, + 0x1400000); + } + + if ((route->local_port0 == RK_SERDES_DSI_RX1) || + (route->local_port1 == RK_SERDES_DSI_RX1)) { + hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, + RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX); + hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk, + RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX); + serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314, + 0x2800000); + } + } + + return 0; +} + diff --git a/drivers/mfd/rkx110_x120/rkx110_x120_display.h b/drivers/mfd/rkx110_x120/rkx110_x120_display.h new file mode 100644 index 000000000000..3bac1a4f0d6b --- /dev/null +++ b/drivers/mfd/rkx110_x120/rkx110_x120_display.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Rockchip Electronics Co. Ltd. + * + * Author: Zhang Yubing + */ + +#ifndef _RKX110_RKX120_DISPLAY_H +#define _RKX110_RKX120_DISPLAY_H + +int rk_serdes_display_route_prepare(struct rk_serdes *serdes, struct rk_serdes_route *route); +int rk_serdes_display_route_enable(struct rk_serdes *serdes, struct rk_serdes_route *route); +int rk_serdes_display_route_disable(struct rk_serdes *serdes, struct rk_serdes_route *route); +int rk_serdes_display_route_unprepare(struct rk_serdes *serdes, struct rk_serdes_route *route); +int rk_serdes_display_route_init(struct rk_serdes *serdes); + +#endif diff --git a/drivers/mfd/rkx110_x120/rkx110_x120_panel.c b/drivers/mfd/rkx110_x120/rkx110_x120_panel.c index 2896fff4f9a5..f2d006236340 100644 --- a/drivers/mfd/rkx110_x120/rkx110_x120_panel.c +++ b/drivers/mfd/rkx110_x120/rkx110_x120_panel.c @@ -30,12 +30,8 @@ static inline struct rk_serdes_panel *to_serdes_panel(struct drm_panel *panel) return container_of(panel, struct rk_serdes_panel, panel); } -static int serdes_panel_prepare(struct drm_panel *panel) +static int serdes_panel_hw_prepare(struct rk_serdes_panel *sd_panel) { - struct rk_serdes_panel *sd_panel = to_serdes_panel(panel); - struct rk_serdes_route *route = &sd_panel->route; - struct rk_serdes *serdes = sd_panel->parent; - if (sd_panel->supply) { int err; @@ -58,16 +54,47 @@ static int serdes_panel_prepare(struct drm_panel *panel) mdelay(20); } + return 0; +} + +static int serdes_panel_dsi_prepare(struct rk_serdes_panel *sd_panel) +{ + struct rk_serdes *serdes = sd_panel->parent; + + if (sd_panel->id == 0 && sd_panel->route.remote0_port0 == RK_SERDES_DSI_TX0 && + !!(sd_panel->on_cmds)) + rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE0, + sd_panel->on_cmds); + + if (sd_panel->id == 1 && sd_panel->route.remote1_port0 == RK_SERDES_DSI_TX0 && + !!(sd_panel->on_cmds)) + rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE1, + sd_panel->on_cmds); + + return 0; +} + +static int serdes_panel_prepare(struct drm_panel *panel) +{ + struct rk_serdes_panel *sd_panel = to_serdes_panel(panel); + struct rk_serdes *serdes = sd_panel->parent; + int ret; + + ret = serdes_panel_hw_prepare(sd_panel); + if (ret) + return ret; + if (sd_panel->secondary) { + ret = serdes_panel_hw_prepare(sd_panel->secondary); + if (ret) + return ret; + } + if (serdes->route_prepare) serdes->route_prepare(serdes, &sd_panel->route); - if (route->remote0_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds)) - rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE0, - sd_panel->on_cmds); - - if (route->remote1_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds)) - rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE1, - sd_panel->on_cmds); + serdes_panel_dsi_prepare(sd_panel); + if (sd_panel->secondary) + serdes_panel_dsi_prepare(sd_panel->secondary); return 0; } @@ -76,10 +103,19 @@ static int serdes_panel_enable(struct drm_panel *panel) { struct rk_serdes_panel *sd_panel = to_serdes_panel(panel); struct rk_serdes *serdes = sd_panel->parent; + int ret; if (serdes->route_enable) serdes->route_enable(serdes, &sd_panel->route); + if (sd_panel->secondary) { + ret = backlight_enable(sd_panel->secondary->panel.backlight); + if (ret < 0) { + dev_err(sd_panel->dev, "failed to enable backlight: %d\n", ret); + return ret; + } + } + return 0; } @@ -87,7 +123,15 @@ static int serdes_panel_disable(struct drm_panel *panel) { struct rk_serdes_panel *sd_panel = to_serdes_panel(panel); struct rk_serdes *serdes = sd_panel->parent; + int ret; + if (sd_panel->secondary) { + ret = backlight_disable(sd_panel->secondary->panel.backlight); + if (ret < 0) { + dev_err(sd_panel->dev, "failed to disable backlight: %d\n", ret); + return ret; + } + } if (serdes->route_disable) serdes->route_disable(serdes, &sd_panel->route); @@ -95,22 +139,8 @@ static int serdes_panel_disable(struct drm_panel *panel) return 0; } -static int serdes_panel_unprepare(struct drm_panel *panel) +static int serdes_panel_hw_unprepare(struct rk_serdes_panel *sd_panel) { - struct rk_serdes_panel *sd_panel = to_serdes_panel(panel); - struct rk_serdes_route *route = &sd_panel->route; - struct rk_serdes *serdes = sd_panel->parent; - - if (route->remote0_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds)) - rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE0, - sd_panel->off_cmds); - - if (route->remote1_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds)) - rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE1, - sd_panel->off_cmds); - if (serdes->route_unprepare) - serdes->route_unprepare(serdes, &sd_panel->route); - if (sd_panel->reset_gpio) { gpiod_set_value_cansleep(sd_panel->reset_gpio, 0); mdelay(20); @@ -127,6 +157,42 @@ static int serdes_panel_unprepare(struct drm_panel *panel) return 0; } +static int serdes_panel_dsi_unprepare(struct rk_serdes_panel *sd_panel) +{ + struct rk_serdes *serdes = sd_panel->parent; + + if (sd_panel->id == 0 && sd_panel->route.remote0_port0 == RK_SERDES_DSI_TX0 && + !!(sd_panel->off_cmds)) + rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE0, + sd_panel->off_cmds); + + if (sd_panel->id == 1 && sd_panel->route.remote1_port0 == RK_SERDES_DSI_TX0 && + !!(sd_panel->off_cmds)) + rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE1, + sd_panel->off_cmds); + + return 0; +} + +static int serdes_panel_unprepare(struct drm_panel *panel) +{ + struct rk_serdes_panel *sd_panel = to_serdes_panel(panel); + struct rk_serdes *serdes = sd_panel->parent; + + serdes_panel_dsi_unprepare(sd_panel); + if (sd_panel->secondary) + serdes_panel_dsi_unprepare(sd_panel->secondary); + + if (serdes->route_unprepare) + serdes->route_unprepare(serdes, &sd_panel->route); + + serdes_panel_hw_unprepare(sd_panel); + if (sd_panel->secondary) + serdes_panel_hw_unprepare(sd_panel->secondary); + + return 0; +} + static int serdes_panel_of_get_native_mode(struct rk_serdes_panel *sd_panel, struct drm_connector *connector) { @@ -336,11 +402,10 @@ static struct mipi_dsi_device *serdes_attach_dsi(struct rk_serdes_panel *sd_pane return dsi; } -static int rkx120_dsi_rx_parse(struct rk_serdes_panel *sd_panel) +static int rkx110_dsi_rx_parse(struct rk_serdes_panel *sd_panel) { struct device_node *np = sd_panel->dev->of_node; - struct rk_serdes *serdes = sd_panel->parent; - struct rkx110_dsi_rx *dsi_rx = &serdes->dsi_rx; + struct rkx110_dsi_rx *dsi_rx = &sd_panel->dsi_rx; struct mipi_dsi_device *dsi; struct device_node *dsi_node; u32 val; @@ -370,12 +435,13 @@ static int rkx120_dsi_rx_parse(struct rk_serdes_panel *sd_panel) static int rkx120_dsi_tx_parse(struct rk_serdes_panel *sd_panel) { struct device_node *np = sd_panel->dev->of_node; - struct rk_serdes *serdes = sd_panel->parent; - struct rkx120_dsi_tx *dsi_tx = &serdes->dsi_tx; + struct rkx120_dsi_tx *dsi_tx = &sd_panel->dsi_tx; const char *string; int ret; u32 val; + dsi_tx->combtxphy = &sd_panel->combtxphy; + if (of_property_read_u32(np, "dsi-tx,lanes", &val)) dsi_tx->lanes = 4; else @@ -418,12 +484,9 @@ static int rkx120_dsi_tx_parse(struct rk_serdes_panel *sd_panel) return 0; } -static int serdes_panel_parse_dt(struct rk_serdes_panel *sd_panel) +static int serdes_panel_parse_route(struct rk_serdes_panel *sd_panel) { struct rk_serdes_route *route = &sd_panel->route; - struct rk_serdes *serdes = sd_panel->parent; - u32 lanes; - int ret; device_property_read_u32(sd_panel->dev, "local-port0", &route->local_port0); device_property_read_u32(sd_panel->dev, "local-port1", &route->local_port1); @@ -431,68 +494,50 @@ static int serdes_panel_parse_dt(struct rk_serdes_panel *sd_panel) device_property_read_u32(sd_panel->dev, "remote0-port1", &route->remote0_port1); device_property_read_u32(sd_panel->dev, "remote1-port0", &route->remote1_port0); device_property_read_u32(sd_panel->dev, "remote1-port1", &route->remote1_port1); - device_property_read_u32(sd_panel->dev, "num-lanes", &lanes); - serdes->route_flag = 0; - - if (!route->local_port0) { - dev_err(sd_panel->dev, "local_port0 should set\n"); + if (!route->local_port0 && !route->local_port1) { + dev_err(sd_panel->dev, "local port should set\n"); return -EINVAL; } - if (!route->remote0_port0) { + if (route->local_port0 && !route->remote0_port0) { dev_err(sd_panel->dev, "remote0_port0 should set\n"); return -EINVAL; } + if (route->local_port1 && !route->remote1_port0) { + dev_err(sd_panel->dev, "remote1_port0 should set\n"); + return -EINVAL; + } + if (route->remote1_port0 && route->remote0_port1) { dev_err(sd_panel->dev, "too many output\n"); return -EINVAL; } route->frame_mode = SERDES_FRAME_NORMAL_MODE; + route->route_flag = 0; - /* 2 video stream output */ - if (route->remote1_port0 || route->remote0_port1) { + /* 2 video stream output in a route */ + if (route->local_port0 && (route->remote1_port0 || route->remote0_port1)) { if (route->remote1_port0) - serdes->route_flag |= ROUTE_MULTI_REMOTE | ROUTE_MULTI_CHANNEL | + route->route_flag |= ROUTE_MULTI_REMOTE | ROUTE_MULTI_CHANNEL| ROUTE_MULTI_LANE; if (route->remote0_port1) { if ((route->remote0_port0 == RK_SERDES_LVDS_TX0) && (route->remote0_port1 == RK_SERDES_LVDS_TX1)) { - serdes->route_flag |= ROUTE_MULTI_CHANNEL; + route->route_flag |= ROUTE_MULTI_CHANNEL; } else if ((route->remote0_port0 == RK_SERDES_LVDS_TX1) && (route->remote0_port1 == RK_SERDES_LVDS_TX0)) { - serdes->route_flag |= ROUTE_MULTI_CHANNEL; + route->route_flag |= ROUTE_MULTI_CHANNEL; } else { dev_err(sd_panel->dev, "invalid multi output type\n"); return -EINVAL; } - - if (lanes == 2) - serdes->route_flag |= ROUTE_MULTI_LANE; } - if (route->local_port1) { - if ((route->local_port0 == RK_SERDES_DSI_RX0) && - (route->local_port1 == RK_SERDES_DSI_RX1)) - serdes->route_flag |= ROUTE_MULTI_DSI_INPUT; - else if ((route->local_port0 == RK_SERDES_DSI_RX1) && - (route->local_port1 == RK_SERDES_DSI_RX0)) - serdes->route_flag |= ROUTE_MULTI_DSI_INPUT; - else if ((route->local_port0 == RK_SERDES_LVDS_RX0) && - (route->local_port1 == RK_SERDES_LVDS_RX1)) - serdes->route_flag |= ROUTE_MULTI_LVDS_INPUT; - else if ((route->local_port0 == RK_SERDES_LVDS_RX1) && - (route->local_port1 == RK_SERDES_LVDS_RX0)) - serdes->route_flag |= ROUTE_MULTI_LVDS_INPUT; - else { - dev_err(sd_panel->dev, "invalid multi input type\n"); - return -EINVAL; - } - serdes->route_flag |= ROUTE_MULTI_SOURCE; - } else { + if (route->local_port0) { if (device_property_read_bool(sd_panel->dev, "split-mode")) { /* only dsi input support split mode */ if ((route->local_port0 != RK_SERDES_DSI_RX0) && @@ -510,41 +555,43 @@ static int serdes_panel_parse_dt(struct rk_serdes_panel *sd_panel) else route->frame_mode = SERDES_SP_LEFT_RIGHT_SPLIT; - serdes->route_flag |= ROUTE_MULTI_SPLIT; + route->route_flag |= ROUTE_MULTI_SPLIT; } else { - serdes->route_flag |= ROUTE_MULTI_MIRROR; + route->route_flag |= ROUTE_MULTI_MIRROR; } } - } else { - if (lanes == 2) - serdes->route_flag |= ROUTE_MULTI_LANE; - } - - if (route->remote0_port0 & RK_SERDES_DSI_TX0 || - route->remote1_port0 & RK_SERDES_DSI_TX0) { - ret = rkx120_dsi_tx_parse(sd_panel); - if (ret) { - dev_err(sd_panel->dev, "failed to get cmds\n"); - return ret; - } - } - - if (route->local_port0 & RK_SERDES_DSI_RX0 || - route->local_port0 & RK_SERDES_DSI_TX1) { - ret = rkx120_dsi_rx_parse(sd_panel); - if (ret < 0) - return ret; } return 0; } +static int serdes_panel_match_by_id(struct device *dev, const void *data) +{ + struct rk_serdes_panel *sd_panel = dev_get_drvdata(dev); + unsigned int *id = (unsigned int *)data; + + return sd_panel->id == *id; +} + +static struct rk_serdes_panel *serdes_panel_find_by_id(struct device_driver *drv, + unsigned int id) +{ + struct device *dev; + + dev = driver_find_device(drv, NULL, &id, serdes_panel_match_by_id); + if (!dev) + return NULL; + + return dev_get_drvdata(dev); +} + static int serdes_panel_probe(struct platform_device *pdev) { struct rk_serdes *serdes = dev_get_drvdata(pdev->dev.parent); - struct rk_serdes_panel *sd_panel; + struct rk_serdes_panel *sd_panel, *secondary; int ret; + u32 reg; sd_panel = devm_kzalloc(&pdev->dev, sizeof(*sd_panel), GFP_KERNEL); if (!sd_panel) @@ -553,7 +600,20 @@ static int serdes_panel_probe(struct platform_device *pdev) sd_panel->dev = &pdev->dev; sd_panel->parent = serdes; sd_panel->route.stream_type = STREAM_DISPLAY; - serdes->vm = &sd_panel->route.vm; + + ret = of_property_read_u32(sd_panel->dev->of_node, "reg", ®); + if (ret) + sd_panel->id = 0; + sd_panel->id = reg; + + sd_panel->multi_panel = device_property_read_bool(sd_panel->dev, "multi-panel"); + if (sd_panel->multi_panel) { + secondary = serdes_panel_find_by_id(sd_panel->dev->driver, 1); + if (!secondary) + return -EPROBE_DEFER; + sd_panel->secondary = secondary; + dev_info(sd_panel->dev, "%s get secondary panel\n", __func__); + } sd_panel->supply = devm_regulator_get_optional(sd_panel->dev, "power"); if (IS_ERR(sd_panel->supply)) { @@ -588,6 +648,19 @@ static int serdes_panel_probe(struct platform_device *pdev) return ret; } + ret = serdes_panel_parse_route(sd_panel); + if (ret < 0) + return ret; + + if (sd_panel->route.remote0_port0 & RK_SERDES_DSI_TX0 || + sd_panel->route.remote1_port0 & RK_SERDES_DSI_TX0) { + ret = rkx120_dsi_tx_parse(sd_panel); + if (ret) { + dev_err(sd_panel->dev, "failed to get cmds\n"); + return ret; + } + } + /* Register the panel. */ drm_panel_init(&sd_panel->panel, sd_panel->dev, &serdes_panel_funcs, 0); @@ -597,13 +670,37 @@ static int serdes_panel_probe(struct platform_device *pdev) drm_panel_add(&sd_panel->panel); + if ((sd_panel->route.local_port0 & RK_SERDES_DSI_RX0 || + sd_panel->route.local_port0 & RK_SERDES_DSI_RX1) && sd_panel->id == 0) { + ret = rkx110_dsi_rx_parse(sd_panel); + if (ret < 0) { + drm_panel_remove(&sd_panel->panel); + return ret; + } + } + + if ((sd_panel->route.local_port1 & RK_SERDES_DSI_RX0 || + sd_panel->route.local_port1 & RK_SERDES_DSI_RX1) && sd_panel->id == 1) { + ret = rkx110_dsi_rx_parse(sd_panel); + if (ret < 0) { + drm_panel_remove(&sd_panel->panel); + return ret; + } + } + dev_set_drvdata(sd_panel->dev, sd_panel); - ret = serdes_panel_parse_dt(sd_panel); - if (ret < 0) { - drm_panel_remove(&sd_panel->panel); - return ret; - } + if (sd_panel->route.route_flag & ROUTE_MULTI_CHANNEL) + serdes->channel_nr = 2; + + if (sd_panel->route.local_port0 && sd_panel->id == 0) + serdes->route_nr++; + + if (sd_panel->route.local_port1 && sd_panel->id == 1) + serdes->route_nr++; + + if (serdes->route_nr == 2) + serdes->channel_nr = 2; return 0; } diff --git a/drivers/mfd/rkx110_x120/rkx120.c b/drivers/mfd/rkx110_x120/rkx120.c index db9f99d47a2b..7db7702bc62b 100644 --- a/drivers/mfd/rkx110_x120/rkx120.c +++ b/drivers/mfd/rkx110_x120/rkx120.c @@ -294,6 +294,8 @@ int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *rout u8 phy_id) { struct i2c_client *client = serdes->chip[remote_id].client; + struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); + struct rkx120_combtxphy *combtxphy = &sd_panel->combtxphy; if (phy_id) { serdes->i2c_write_reg(client, DES_GRF_SOC_CON7, 0xfff00630); @@ -303,12 +305,12 @@ int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *rout serdes->i2c_write_reg(client, DES_GRF_SOC_CON2, 0x00040004); } - rkx120_combtxphy_set_mode(serdes, COMBTX_PHY_MODE_VIDEO_LVDS); + rkx120_combtxphy_set_mode(combtxphy, COMBTX_PHY_MODE_VIDEO_LVDS); if (route->remote0_port0 & RK_SERDES_DUAL_LVDS_TX) - rkx120_combtxphy_set_rate(serdes, route->vm.pixelclock * 7 / 2); + rkx120_combtxphy_set_rate(combtxphy, route->vm.pixelclock * 7 / 2); else - rkx120_combtxphy_set_rate(serdes, route->vm.pixelclock * 7); - rkx120_combtxphy_power_on(serdes, remote_id, phy_id); + rkx120_combtxphy_set_rate(combtxphy, route->vm.pixelclock * 7); + rkx120_combtxphy_power_on(serdes, combtxphy, remote_id, phy_id); return 0; } diff --git a/drivers/mfd/rkx110_x120/rkx120_combtxphy.c b/drivers/mfd/rkx110_x120/rkx120_combtxphy.c index 7a44e7128bee..6e516c7826b3 100644 --- a/drivers/mfd/rkx110_x120/rkx120_combtxphy.c +++ b/drivers/mfd/rkx110_x120/rkx120_combtxphy.c @@ -111,9 +111,10 @@ #define GRF_MIPI_STATUS 0x0080 #define PHYLOCK BIT(0) -static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, u8 remote_id) +static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, + struct rkx120_combtxphy *combtxphy, + u8 dev_id) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; const struct configure_opts_combphy cfg = combtxphy->mipi_dphy_cfg; u32 byte_clk = DIV_ROUND_CLOSEST_ULL(combtxphy->rate, 8); u32 esc_div = DIV_ROUND_UP(byte_clk, 20 * USEC_PER_SEC); @@ -123,30 +124,30 @@ static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, u8 remote_id u32 t_tago, t_tasure, t_taget; u32 base = RKX120_MIPI_LVDS_TX_PHY0_BASE; - serdes_combphy_write(des, remote_id, base + INTERFACE_PARA, + serdes_combphy_write(des, dev_id, base + INTERFACE_PARA, TXREADYESC_VLD(esc_div - 2) | RXVALIDESC_VLD(esc_div - 2)); - serdes_combphy_write(des, remote_id, base + COMMON_PARA0, esc_div); - serdes_combphy_update_bits(des, remote_id, base + TEST_PARA0, FSET_EN, FSET_EN); + serdes_combphy_write(des, dev_id, base + COMMON_PARA0, esc_div); + serdes_combphy_update_bits(des, dev_id, base + TEST_PARA0, FSET_EN, FSET_EN); t_init = DIV_ROUND_UP(cfg.init, t_byte_clk) - 1; - serdes_combphy_write(des, remote_id, base + CLANE_PARA1, T_INITTIME_C(t_init)); - serdes_combphy_write(des, remote_id, base + DLANE0_PARA1, T_INITTIME_D(t_init)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA1(1), T_INITTIME_D(t_init)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA1(2), T_INITTIME_D(t_init)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA1(3), T_INITTIME_D(t_init)); + serdes_combphy_write(des, dev_id, base + CLANE_PARA1, T_INITTIME_C(t_init)); + serdes_combphy_write(des, dev_id, base + DLANE0_PARA1, T_INITTIME_D(t_init)); + serdes_combphy_write(des, dev_id, base + DLANE_PARA1(1), T_INITTIME_D(t_init)); + serdes_combphy_write(des, dev_id, base + DLANE_PARA1(2), T_INITTIME_D(t_init)); + serdes_combphy_write(des, dev_id, base + DLANE_PARA1(3), T_INITTIME_D(t_init)); t_clkprepare = DIV_ROUND_UP(cfg.clk_prepare, t_byte_clk) - 1; t_clkzero = DIV_ROUND_UP(cfg.clk_zero, t_byte_clk) - 1; t_clkpre = DIV_ROUND_UP(cfg.clk_pre, t_byte_clk) - 1; - serdes_combphy_write(des, remote_id, base + CLANE_PARA2, + serdes_combphy_write(des, dev_id, base + CLANE_PARA2, T_CLKPREPARE_C(t_clkprepare) | T_CLKZERO_C(t_clkzero) | T_CLKPRE_C(t_clkpre)); t_clkpost = DIV_ROUND_UP(cfg.clk_post, t_byte_clk) - 1; t_clktrail = DIV_ROUND_UP(cfg.clk_trail, t_byte_clk) - 1; t_hsexit = DIV_ROUND_UP(cfg.hs_exit, t_byte_clk) - 1; - serdes_combphy_write(des, remote_id, base + CLANE_PARA3, + serdes_combphy_write(des, dev_id, base + CLANE_PARA3, T_CLKPOST_C(t_clkpost) | T_CLKTRAIL_C(t_clktrail) | T_HSEXIT_C(t_hsexit)); @@ -154,62 +155,63 @@ static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, u8 remote_id t_hsprepare = DIV_ROUND_UP(cfg.hs_prepare, t_byte_clk) - 1; t_hszero = DIV_ROUND_UP(cfg.hs_zero, t_byte_clk) - 1; t_hstrail = DIV_ROUND_UP(cfg.hs_trail, t_byte_clk) - 1; - serdes_combphy_write(des, remote_id, base + DLANE0_PARA2, + serdes_combphy_write(des, dev_id, base + DLANE0_PARA2, T_HSPREPARE_D(t_hsprepare) | T_HSZERO_D(t_hszero) | T_HSTRAIL_D(t_hstrail) | T_HSEXIT_D(t_hsexit)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA2(1), + serdes_combphy_write(des, dev_id, base + DLANE_PARA2(1), T_HSPREPARE_D(t_hsprepare) | T_HSZERO_D(t_hszero) | T_HSTRAIL_D(t_hstrail) | T_HSEXIT_D(t_hsexit)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA2(2), + serdes_combphy_write(des, dev_id, base + DLANE_PARA2(2), T_HSPREPARE_D(t_hsprepare) | T_HSZERO_D(t_hszero) | T_HSTRAIL_D(t_hstrail) | T_HSEXIT_D(t_hsexit)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA2(3), + serdes_combphy_write(des, dev_id, base + DLANE_PARA2(3), T_HSPREPARE_D(t_hsprepare) | T_HSZERO_D(t_hszero) | T_HSTRAIL_D(t_hstrail) | T_HSEXIT_D(t_hsexit)); t_wakeup = DIV_ROUND_UP(cfg.wakeup, t_byte_clk) - 1; - serdes_combphy_write(des, remote_id, base + DLANE0_PARA3, T_WAKEUP_D(t_wakeup)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA3(1), T_WAKEUP_D(t_wakeup)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA3(2), T_WAKEUP_D(t_wakeup)); - serdes_combphy_write(des, remote_id, base + DLANE_PARA3(3), T_WAKEUP_D(t_wakeup)); - serdes_combphy_write(des, remote_id, base + CLANE_PARA4, T_WAKEUP_D(t_wakeup)); + serdes_combphy_write(des, dev_id, base + DLANE0_PARA3, T_WAKEUP_D(t_wakeup)); + serdes_combphy_write(des, dev_id, base + DLANE_PARA3(1), T_WAKEUP_D(t_wakeup)); + serdes_combphy_write(des, dev_id, base + DLANE_PARA3(2), T_WAKEUP_D(t_wakeup)); + serdes_combphy_write(des, dev_id, base + DLANE_PARA3(3), T_WAKEUP_D(t_wakeup)); + serdes_combphy_write(des, dev_id, base + CLANE_PARA4, T_WAKEUP_D(t_wakeup)); t_tago = DIV_ROUND_UP(cfg.ta_go, t_byte_clk) - 1; t_tasure = DIV_ROUND_UP(cfg.ta_sure, t_byte_clk) - 1; t_taget = DIV_ROUND_UP(cfg.ta_get, t_byte_clk) - 1; - serdes_combphy_write(des, remote_id, base + DLANE0_PARA4, + serdes_combphy_write(des, dev_id, base + DLANE0_PARA4, T_TAGO_D0(t_tago) | T_TASURE_D0(t_tasure) | T_TAGET_D0(t_taget)); } -static void rkx120_combtxphy_dsi_pll_set(struct rk_serdes *des, u8 remote_id) +static void rkx120_combtxphy_dsi_pll_set(struct rk_serdes *des, + struct rkx120_combtxphy *combtxphy, u8 dev_id) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; u32 base = RKX120_MIPI_LVDS_TX_PHY0_BASE; - serdes_combphy_update_bits(des, remote_id, base + PLL_CTRL_PARA0, + serdes_combphy_update_bits(des, dev_id, base + PLL_CTRL_PARA0, RATE_MASK | REFCLK_DIV_MASK | PLL_DIV_MASK, RATE(combtxphy->rate_factor) | REFCLK_DIV(combtxphy->ref_div - 1) | PLL_DIV(combtxphy->fb_div)); } -static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, u8 remote_id) +static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, + struct rkx120_combtxphy *combtxphy, + u8 dev_id) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; - struct i2c_client *client = des->chip[remote_id].client; + struct i2c_client *client = des->chip[dev_id].client; u32 grf_base = RKX120_GRF_MIPI0_BASE; u32 val; int ret; @@ -218,8 +220,8 @@ static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, u8 remote_id) PHY_MODE(COMBTX_PHY_MODE_VIDEO_MIPI)); serdes_combphy_get_default_config(combtxphy->rate, &combtxphy->mipi_dphy_cfg); - rkx120_combtxphy_dsi_timing_init(des, remote_id); - rkx120_combtxphy_dsi_pll_set(des, remote_id); + rkx120_combtxphy_dsi_timing_init(des, combtxphy, dev_id); + rkx120_combtxphy_dsi_pll_set(des, combtxphy, dev_id); des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0, PHYSHUTDWN(1)); des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1, PWON_PLL(1)); @@ -233,19 +235,20 @@ static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, u8 remote_id) dev_err(des->dev, "PLL is not locked\n"); } -static void rkx120_combtxphy_dsi_power_off(struct rk_serdes *des, u8 remote_id) +static void rkx120_combtxphy_dsi_power_off(struct rk_serdes *des, u8 dev_id) { - struct i2c_client *client = des->chip[remote_id].client; + struct i2c_client *client = des->chip[dev_id].client; u32 grf_base = RKX120_GRF_MIPI0_BASE; des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0, PHYSHUTDWN(0)); des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1, PWON_PLL(0)); } -static void rkx120_combtxphy_lvds_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id) +static void rkx120_combtxphy_lvds_power_on(struct rk_serdes *des, + struct rkx120_combtxphy *combtxphy, + u8 dev_id, u8 phy_id) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; - struct i2c_client *client = des->chip[remote_id].client; + struct i2c_client *client = des->chip[dev_id].client; u32 grf_base = (phy_id == 0) ? RKX120_GRF_MIPI0_BASE : RKX120_GRF_MIPI1_BASE; const struct { @@ -304,29 +307,27 @@ static void rkx120_combtxphy_lvds_power_on(struct rk_serdes *des, u8 remote_id, des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON13, TX_IDLE(0)); } -void rkx120_combtxphy_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id) +void rkx120_combtxphy_power_on(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy, + u8 dev_id, u8 phy_id) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; - switch (combtxphy->mode) { case COMBTX_PHY_MODE_VIDEO_MIPI: - rkx120_combtxphy_dsi_power_on(des, remote_id); + rkx120_combtxphy_dsi_power_on(des, combtxphy, dev_id); break; case COMBTX_PHY_MODE_VIDEO_LVDS: - rkx120_combtxphy_lvds_power_on(des, remote_id, phy_id); + rkx120_combtxphy_lvds_power_on(des, combtxphy, dev_id, phy_id); break; default: break; } } -void rkx120_combtxphy_power_off(struct rk_serdes *des, u8 remote_id) +void rkx120_combtxphy_power_off(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy, + u8 dev_id, u8 phy_id) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; - switch (combtxphy->mode) { case COMBTX_PHY_MODE_VIDEO_MIPI: - rkx120_combtxphy_dsi_power_off(des, remote_id); + rkx120_combtxphy_dsi_power_off(des, dev_id); break; case COMBTX_PHY_MODE_VIDEO_LVDS: break; @@ -385,10 +386,8 @@ static void rkx120_combtxphy_lvds_pll_calc_rate(struct rkx120_combtxphy *combtxp { } -void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate) +void rkx120_combtxphy_set_rate(struct rkx120_combtxphy *combtxphy, u64 rate) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; - switch (combtxphy->mode) { case COMBTX_PHY_MODE_VIDEO_MIPI: rkx120_combtxphy_dsi_pll_calc_rate(combtxphy, rate); @@ -403,14 +402,12 @@ void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate) combtxphy->rate = rate; } -u64 rkx120_combtxphy_get_rate(struct rk_serdes *des) +u64 rkx120_combtxphy_get_rate(struct rkx120_combtxphy *combtxphy) { - return des->combtxphy.rate; + return combtxphy->rate; } -void rkx120_combtxphy_set_mode(struct rk_serdes *des, enum combtx_phy_mode mode) +void rkx120_combtxphy_set_mode(struct rkx120_combtxphy *combtxphy, enum combtx_phy_mode mode) { - struct rkx120_combtxphy *combtxphy = &des->combtxphy; - combtxphy->mode = mode; } diff --git a/drivers/mfd/rkx110_x120/rkx120_dsi_tx.c b/drivers/mfd/rkx110_x120/rkx120_dsi_tx.c index 70a122ed3f3a..4e262c4ea1d9 100644 --- a/drivers/mfd/rkx110_x120/rkx120_dsi_tx.c +++ b/drivers/mfd/rkx110_x120/rkx120_dsi_tx.c @@ -751,10 +751,9 @@ static int rkx120_dsi_tx_transfer(struct rk_serdes *des, u8 remote_id, return msg->tx_len; } -static int rkx120_mipi_dsi_generic_write(struct rk_serdes *des, u8 remote_id, - const void *payload, size_t size) +static int rkx120_mipi_dsi_generic_write(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, + u8 remote_id, const void *payload, size_t size) { - const struct rkx120_dsi_tx *dsi = &des->dsi_tx; struct mipi_dsi_msg msg; memset(&msg, 0, sizeof(msg)); @@ -785,10 +784,9 @@ static int rkx120_mipi_dsi_generic_write(struct rk_serdes *des, u8 remote_id, return rkx120_dsi_tx_transfer(des, remote_id, dsi, &msg); } -static int rkx120_mipi_dsi_dcs_write_buffer(struct rk_serdes *des, u8 remote_id, - const void *data, size_t len) +static int rkx120_mipi_dsi_dcs_write_buffer(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, + u8 remote_id, const void *data, size_t len) { - const struct rkx120_dsi_tx *dsi = &des->dsi_tx; struct mipi_dsi_msg msg; memset(&msg, 0, sizeof(msg)); @@ -818,10 +816,9 @@ static int rkx120_mipi_dsi_dcs_write_buffer(struct rk_serdes *des, u8 remote_id, } static __maybe_unused int -rkx120_mipi_dsi_dcs_read(struct rk_serdes *des, u8 remote_id, +rkx120_mipi_dsi_dcs_read(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id, u8 cmd, void *data, size_t len) { - const struct rkx120_dsi_tx *dsi = &des->dsi_tx; struct mipi_dsi_msg msg; memset(&msg, 0, sizeof(msg)); @@ -835,7 +832,7 @@ rkx120_mipi_dsi_dcs_read(struct rk_serdes *des, u8 remote_id, return rkx120_dsi_tx_transfer(des, remote_id, dsi, &msg); } -int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, u8 remote_id, +int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id, struct panel_cmds *cmds) { u16 i; @@ -852,13 +849,13 @@ int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, u8 remote_id, case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: case MIPI_DSI_GENERIC_LONG_WRITE: - err = rkx120_mipi_dsi_generic_write(des, remote_id, cmd->payload, + err = rkx120_mipi_dsi_generic_write(des, dsi, remote_id, cmd->payload, cmd->dchdr.dlen); break; case MIPI_DSI_DCS_SHORT_WRITE: case MIPI_DSI_DCS_SHORT_WRITE_PARAM: case MIPI_DSI_DCS_LONG_WRITE: - err = rkx120_mipi_dsi_dcs_write_buffer(des, remote_id, cmd->payload, + err = rkx120_mipi_dsi_dcs_write_buffer(des, dsi, remote_id, cmd->payload, cmd->dchdr.dlen); break; default: @@ -901,7 +898,8 @@ static u64 rkx120_dsi_tx_get_lane_rate(const struct rkx120_dsi_tx *dsi) } static void -mipi_dphy_power_on(struct rk_serdes *des, const struct rkx120_dsi_tx *dsi, u8 remote_id) +mipi_dphy_power_on(struct rk_serdes *des, const struct rkx120_dsi_tx *dsi, + u8 remote_id) { struct i2c_client *client = des->chip[remote_id].client; u32 val, mask; @@ -920,7 +918,7 @@ mipi_dphy_power_on(struct rk_serdes *des, const struct rkx120_dsi_tx *dsi, u8 re dsi_update_bits(des, remote_id, DSI_PHY_RSTZ, PHY_RSTZ, PHY_RSTZ); usleep_range(1500, 2000); - rkx120_combtxphy_power_on(des, remote_id, 0); + rkx120_combtxphy_power_on(des, dsi->combtxphy, remote_id, 0); ret = read_poll_timeout(des->i2c_read_reg, ret, !(ret < 0) && (val & PHY_LOCK), @@ -954,9 +952,9 @@ static void rkx120_dsi_tx_reset_control_deassert(struct rk_serdes *des, u8 remot //dsi_i2c_write(des, remote_id, CRU_SOFTRST_CON02, 0x400000); } -static void rkx120_dsi_tx_bridge_pre_enable(struct rk_serdes *des, u8 remote_id) +static void rkx120_dsi_tx_bridge_pre_enable(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, + u8 remote_id) { - struct rkx120_dsi_tx *dsi = &des->dsi_tx; u32 val; dsi_write(des, remote_id, DSI_PWR_UP, RESET); @@ -1064,9 +1062,8 @@ static void rkx120_dsi_tx_set_cmd_mode(struct rk_serdes *des, u8 remote_id, } static void -rkx120_dsi_tx_bridge_enable(struct rk_serdes *des, u8 remote_id) +rkx120_dsi_tx_bridge_enable(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id) { - struct rkx120_dsi_tx *dsi = &des->dsi_tx; const struct videomode *vm = dsi->vm; u32 val; @@ -1117,15 +1114,16 @@ void rkx120_dsi_tx_pre_enable(struct rk_serdes *des, struct rk_serdes_route *route, u8 remote_id) { - struct rkx120_dsi_tx *dsi = &des->dsi_tx; + struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); + struct rkx120_dsi_tx *dsi = &sd_panel->dsi_tx; u64 rate; dsi->vm = &route->vm; rate = rkx120_dsi_tx_get_lane_rate(dsi); - rkx120_combtxphy_set_mode(des, COMBTX_PHY_MODE_VIDEO_MIPI); - rkx120_combtxphy_set_rate(des, rate); - lane_kbps = rkx120_combtxphy_get_rate(des) / MSEC_PER_SEC; + rkx120_combtxphy_set_mode(dsi->combtxphy, COMBTX_PHY_MODE_VIDEO_MIPI); + rkx120_combtxphy_set_rate(dsi->combtxphy, rate); + lane_kbps = rkx120_combtxphy_get_rate(dsi->combtxphy) / MSEC_PER_SEC; /* rst for dsi */ rkx120_dsi_tx_reset_control_assert(des, remote_id); @@ -1133,12 +1131,11 @@ void rkx120_dsi_tx_pre_enable(struct rk_serdes *des, rkx120_dsi_tx_reset_control_deassert(des, remote_id); usleep_range(20, 40); - rkx120_dsi_tx_bridge_pre_enable(des, remote_id); - + rkx120_dsi_tx_bridge_pre_enable(des, dsi, remote_id); #ifdef DSI_READ_POWER_MODE u8 mode; - rkx120_mipi_dsi_dcs_read(des, remote_id, MIPI_DCS_GET_POWER_MODE, + rkx120_mipi_dsi_dcs_read(des, dsi, remote_id, MIPI_DCS_GET_POWER_MODE, &mode, sizeof(mode)); dev_info(rkx120->dev, "dsi: mode: 0x%x\n", mode); @@ -1149,17 +1146,18 @@ void rkx120_dsi_tx_enable(struct rk_serdes *des, struct rk_serdes_route *route, u8 remote_id) { - struct rkx120_dsi_tx *dsi = &des->dsi_tx; + struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); + struct rkx120_dsi_tx *dsi = &sd_panel->dsi_tx; #ifdef DSI_READ_POWER_MODE u8 mode; - rkx120_mipi_dsi_dcs_read(des, remote_id, MIPI_DCS_GET_POWER_MODE, + rkx120_mipi_dsi_dcs_read(des, dsi, remote_id, MIPI_DCS_GET_POWER_MODE, &mode, sizeof(mode)); dev_info(rkx120->dev, "dsi: mode: 0x%x\n", mode); #endif - rkx120_dsi_tx_bridge_enable(des, remote_id); + rkx120_dsi_tx_bridge_enable(des, dsi, remote_id); dev_info(des->dev, "rkx120_dsi_tx final DSI-Link bandwidth: %llu Kbps x %d lanes\n", lane_kbps, dsi->lanes); @@ -1169,7 +1167,10 @@ void rkx120_dsi_tx_post_disable(struct rk_serdes *des, struct rk_serdes_route *route, u8 remote_id) { - rkx120_combtxphy_power_off(des, remote_id); + struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route); + struct rkx120_dsi_tx *dsi = &sd_panel->dsi_tx; + + rkx120_combtxphy_power_off(des, dsi->combtxphy, remote_id, 0); } void rkx120_dsi_tx_disable(struct rk_serdes *des, struct rk_serdes_route *route, u8 remote_id) diff --git a/drivers/mfd/rkx110_x120/rkx120_dsi_tx.h b/drivers/mfd/rkx110_x120/rkx120_dsi_tx.h index a7e95281adbc..1703766c3608 100644 --- a/drivers/mfd/rkx110_x120/rkx120_dsi_tx.h +++ b/drivers/mfd/rkx110_x120/rkx120_dsi_tx.h @@ -10,7 +10,7 @@ #include "rkx110_x120.h" -int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, u8 remote_id, +int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id, struct panel_cmds *cmds); void rkx120_dsi_tx_pre_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id); diff --git a/drivers/mfd/rkx110_x120/rkx120_linkrx.c b/drivers/mfd/rkx110_x120/rkx120_linkrx.c index f4a80a89fd75..29f338b4bfab 100644 --- a/drivers/mfd/rkx110_x120/rkx120_linkrx.c +++ b/drivers/mfd/rkx110_x120/rkx120_linkrx.c @@ -24,6 +24,7 @@ #define TRAIN_CLK_SEL_I2S UPDATE(2, 31, 30) #define DUAL_LVDS_CHANNEL_SWAP BIT(29) #define VIDEO_FREQ_AUTO_EN BIT(28) + #define ENGINE_CFG_MASK GENMASK(23, 20) #define ENGINE1_2_LANE BIT(23) #define ENGINE1_EN BIT(22) #define ENGINE0_2_LANE BIT(21) @@ -38,6 +39,7 @@ #define LANE0_DATA_WIDTH_32BIT UPDATE(3, 13, 12) #define LANE1_PKT_LOSE_NUM_CLR BIT(9) #define LANE0_PKT_LOSE_NUM_CLR BIT(8) + #define LANE_CFG_MASK GENMASK(5, 4) #define LANE0_EN BIT(4) #define LANE1_EN BIT(5) #define DES_EN BIT(0) @@ -79,6 +81,7 @@ #define ORDER_FIFO0_WR_ID(x) UPDATE(x, 2, 0) #define RKLINK_DES_SOURCE_CFG LINK_REG(0x0024) + #define E1_STREAM_CFG_MASK GENMASK(23, 20) #define E1_CAMERA_SRC_CSI UPDATE(0, 23, 21) #define E1_CAMERA_SRC_LVDS UPDATE(1, 23, 21) #define E1_CAMERA_SRC_DVP UPDATE(2, 23, 21) @@ -89,6 +92,7 @@ #define E1_DISPLAY_SRC_RGB UPDATE(5, 23, 21) #define E1_STREAM_CAMERA UPDATE(0, 20, 20) #define E1_STREAM_DISPLAY UPDATE(1, 20, 20) + #define E0_STREAM_CFG_MASK GENMASK(19, 16) #define E0_CAMERA_SRC_CSI UPDATE(0, 19, 17) #define E0_CAMERA_SRC_LVDS UPDATE(1, 19, 17) #define E0_CAMERA_SRC_DVP UPDATE(2, 19, 17) @@ -99,6 +103,7 @@ #define E0_DISPLAY_SRC_RGB UPDATE(5, 19, 17) #define E0_STREAM_CAMERA UPDATE(0, 16, 16) #define E0_STREAM_DISPLAY UPDATE(1, 16, 16) + #define LANE_ID_CFG_MASK GENMASK(7, 0) #define LANE1_ENGINE_ID(x) UPDATE(x, 7, 6) #define LANE1_LANE_ID(x) UPDATE(x, 5, 5) #define LNAE1_ID_SEL(x) UPDATE(x, 4, 4) @@ -464,9 +469,9 @@ static const struct rk_serdes_pt des_pt[] = { }, }; -static int rk_des_get_stream_source(struct rk_serdes_route *route, u32 port, u8 engine_id) +static int rk_des_get_stream_source(u32 stream_type, u32 port, u8 engine_id) { - if (route->stream_type == STREAM_DISPLAY) { + if (stream_type == STREAM_DISPLAY) { if (port & RK_SERDES_RGB_TX) return engine_id ? E1_DISPLAY_SRC_RGB : E0_DISPLAY_SRC_RGB; else if (port & RK_SERDES_LVDS_TX0) @@ -527,66 +532,252 @@ static void rk_serdes_link_rx_dsi_enable(struct rk_serdes *serdes, E1_FIRST_FRAME_DEL | E0_FIRST_FRAME_DEL); } -static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id) +static int rk120_linkrx_des_enable(struct rk_serdes *serdes, u8 dev_id, bool enable) { - struct hwclk *hwclk = serdes->chip[remote_id].hwclk; - struct i2c_client *client; - struct videomode *vm = &route->vm; - u32 stream_type; - u32 rx_src; - u32 ctrl_val, mask, val; - u32 lane0_dsource_id, lane1_dsource_id; - bool is_rx_dual_lanes; - bool is_rx_dual_channels; - u32 length; + struct i2c_client *client = serdes->chip[dev_id].client; - if (route->stream_type == STREAM_DISPLAY) { - client = serdes->chip[remote_id].client; - stream_type = E0_STREAM_DISPLAY; + serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_CFG, DES_EN, enable ? DES_EN : 0); + + return 0; +} + +static int rk120_linkrx_video_fm_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_DES_LANE_ENGINE_CFG, VIDEO_FREQ_AUTO_EN, + enable ? VIDEO_FREQ_AUTO_EN : 0); + + return 0; +} + +static int rk120_linkrx_engine_lane_enable(struct rk_serdes *serdes, u8 dev_id, + bool dual_channels, bool dual_lanes) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val = 0; + + /* + * config engine and lane as fallow: + * 1.linkrx receive 1 channel data in 1 lane, enable engine0 and engine0 use 1 lane. + * 2.linkrx receive 1 channel data in 2 lane, enable engine0 and engine0 user 2 lanes. + * 3.linkrx receive 2 channel data in 1 lane, enable engine0, enagine1. engine0 use + * 1 lane, engine1 use 1 lane. + * 4.linkrx receive 2 channel data in 2 lane, enable engine0, enagine1. engine0 use + * 1 lane, engine1 use 1 lane. + */ + if (dual_channels) { + val |= ENGINE0_EN | ENGINE1_EN; } else { - client = serdes->chip[DEVICE_LOCAL].client; - stream_type = E0_STREAM_CAMERA; + val |= ENGINE0_EN; + if (dual_lanes) + val |= ENGINE0_2_LANE; } - is_rx_dual_lanes = (serdes->route_flag & ROUTE_MULTI_LANE) && - !(serdes->route_flag & ROUTE_MULTI_REMOTE); - is_rx_dual_channels = (serdes->route_flag & ROUTE_MULTI_CHANNEL) && - !(serdes->route_flag & ROUTE_MULTI_REMOTE); + serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_CFG, ENGINE_CFG_MASK, val); - serdes->i2c_read_reg(client, RKLINK_DES_LANE_ENGINE_CFG, &ctrl_val); + return 0; +} - ctrl_val &= ~LANE1_EN; - ctrl_val |= LANE0_EN; - ctrl_val |= ENGINE0_EN; - if (is_rx_dual_lanes) { - ctrl_val |= LANE1_EN; - if (is_rx_dual_channels) - ctrl_val |= ENGINE1_EN; - else - ctrl_val |= ENGINE0_2_LANE; - } else { - if (is_rx_dual_channels) - ctrl_val |= ENGINE1_EN; - } - serdes->i2c_write_reg(client, RKLINK_DES_LANE_ENGINE_CFG, ctrl_val); +static int rk120_linkrx_lane_enable(struct rk_serdes *serdes, u8 dev_id, u32 lanes) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val; - mask = LANE0_ENGINE_CFG_MASK; - val = LANE0_ENGINE0; - if (is_rx_dual_lanes) { - if (is_rx_dual_channels) { - mask |= LANE1_ENGINE_CFG_MASK; - val |= LANE1_ENGINE1; + /* + * when 1 lane connect to linkrx, enable lane0; + * when 2 lane connect to linkrx, enable lane0 and lane1; + */ + + if (lanes == 1) + val = LANE0_EN; + else if (lanes == 2) + val = LANE0_EN | LANE1_EN; + else + val = 0; + + serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_CFG, LANE_CFG_MASK, val); + + return 0; +} + +static int rk120_linkrx_lane_engine_dst_cfg(struct rk_serdes *serdes, u8 dev_id, + bool dual_channels, bool dual_lanes) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 mask, val; + + /* + * config lane dst engine as fallow: + * 1. 1 channel 1 lane: lane0 data send to engine0 + * 2. 1 channel 2 lane: lane0 data send to engine0, lane1 data send to engine0 + * 3. 2 channel 1 lane: lane0 data send to engine0, lane0 data send to engine1 + * 4. 2 channel 2 lane: lane0 data send to engine0, lane1 data send to engine1 + */ + if (dual_channels) { + if (dual_lanes) { + mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK; + val = LANE0_ENGINE0 | LANE1_ENGINE1; } else { - mask |= LANE1_ENGINE_CFG_MASK; - val |= LANE1_ENGINE0; + mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK; + val = LANE0_ENGINE0 | LANE0_ENGINE1; } } else { - if (is_rx_dual_channels) - val |= LANE0_ENGINE1; - } + if (dual_lanes) { + mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK; + val = LANE0_ENGINE0 | LANE1_ENGINE0; + } else { + mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK; + val = LANE0_ENGINE0 | LANE1_ENGINE1; + } + } serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_DST, mask, val); + return 0; +} + +static int rk120_linkrx_config_pkt_length(struct rk_serdes *serdes, u8 dev_id, u32 length) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + + serdes->i2c_write_reg(client, DES_RKLINK_REC01_PKT_LENGTH, E0_REPKT_LENGTH(length) | + E1_REPKT_LENGTH(length)); + + return 0; +} + +static int rk120_linkrx_lane_id_cfg(struct rk_serdes *serdes, u8 dev_id, + bool dual_channels, bool dual_lanes) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val; + + if (dual_channels) { + if (dual_lanes) { + val = LANE0_ENGINE_ID(0) | LANE0_LANE_ID(0) | LNAE0_ID_SEL(1) | + LANE1_ENGINE_ID(1) | LANE1_LANE_ID(0) | LNAE1_ID_SEL(1); + } else { + val = LANE0_ENGINE_ID(0) | LANE0_LANE_ID(0) | LANE1_ENGINE_ID(1) | + LANE1_LANE_ID(0); + } + } else { + if (dual_lanes) { + val = LANE0_ENGINE_ID(0) | LANE0_LANE_ID(0) | LNAE0_ID_SEL(1) | + LANE1_ENGINE_ID(0) | LANE1_LANE_ID(1) | LNAE1_ID_SEL(1); + } else { + val = LNAE0_ID_SEL(1); + } + } + + serdes->i2c_update_bits(client, RKLINK_DES_SOURCE_CFG, LANE_ID_CFG_MASK, val); + + return 0; +} + +static int rk120_linkrx_stream_type_cfg(struct rk_serdes *serdes, u32 stream_type, + u8 dev_id, u32 port, u32 engine_id) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 val, mask, rx_src; + + mask = engine_id ? E1_STREAM_CFG_MASK : E0_STREAM_CFG_MASK; + if (stream_type == STREAM_DISPLAY) + val = engine_id ? E1_STREAM_DISPLAY : E0_STREAM_DISPLAY; + else + val = engine_id ? E1_STREAM_CAMERA : E0_STREAM_CAMERA; + + rx_src = rk_des_get_stream_source(stream_type, port, engine_id); + val |= rx_src; + serdes->i2c_update_bits(client, RKLINK_DES_SOURCE_CFG, mask, val); + + return 0; +} + +static int rk120_linkrx_data_and_order_id_cfg(struct rk_serdes *serdes, u8 dev_id, + bool dual_channels, bool dual_lanes) +{ + struct i2c_client *client = serdes->chip[dev_id].client; + u32 lane0_dsource_id, lane1_dsource_id; + u32 data_id_mask; + u32 order_id_mask; + u32 val; + + data_id_mask = DATA_FIFO0_WR_ID_MASK | DATA_FIFO1_WR_ID_MASK | + DATA_FIFO2_WR_ID_MASK | DATA_FIFO3_WR_ID_MASK | + DATA_FIFO0_RD_ID_MASK | DATA_FIFO1_RD_ID_MASK | + DATA_FIFO2_RD_ID_MASK | DATA_FIFO3_RD_ID_MASK; + order_id_mask = ORDER_FIFO0_WR_ID_MASK | ORDER_FIFO1_WR_ID_MASK | + ORDER_FIFO0_RD_ID_MASK | ORDER_FIFO1_RD_ID_MASK; + + if (dual_channels) { + lane0_dsource_id = (0 << 1) | 0; + lane1_dsource_id = (1 << 1) | 0; + } else { + if (dual_lanes) { + lane0_dsource_id = (0 << 1) | 0; + lane1_dsource_id = (0 << 1) | 1; + } else { + lane0_dsource_id = (0 << 1) | 0; + lane1_dsource_id = (1 << 1) | 0; + } + } + + val = DATA_FIFO0_WR_ID(lane0_dsource_id) | DATA_FIFO1_WR_ID(lane0_dsource_id) | + DATA_FIFO0_RD_ID(lane0_dsource_id) | DATA_FIFO1_RD_ID(lane0_dsource_id) | + DATA_FIFO2_WR_ID(lane1_dsource_id) | DATA_FIFO3_WR_ID(lane1_dsource_id) | + DATA_FIFO2_RD_ID(lane1_dsource_id) | DATA_FIFO3_RD_ID(lane1_dsource_id); + serdes->i2c_update_bits(client, RKLINK_DES_DATA_ID_CFG, data_id_mask, val); + + val = ORDER_FIFO0_WR_ID(lane0_dsource_id) | ORDER_FIFO1_WR_ID(lane1_dsource_id) | + ORDER_FIFO0_RD_ID(lane0_dsource_id) | ORDER_FIFO1_RD_ID(lane1_dsource_id); + + serdes->i2c_update_bits(client, RKLINK_DES_ORDER_ID_CFG, order_id_mask, val); + + return 0; +} + +static int rk120_display_linkrx_cfg(struct rk_serdes *serdes, + struct rk_serdes_route *route, u8 dev_id) +{ + struct hwclk *hwclk = serdes->chip[dev_id].hwclk; + bool is_rx_dual_lanes = false; + bool is_rx_dual_channels = false; + + if (serdes->route_nr == 1) { + is_rx_dual_lanes = (serdes->lane_nr == 2) && + !(route->route_flag & ROUTE_MULTI_REMOTE); + is_rx_dual_channels = (route->route_flag & ROUTE_MULTI_CHANNEL) && + !(route->route_flag & ROUTE_MULTI_REMOTE); + } else { + is_rx_dual_lanes = (serdes->lane_nr == 2) && (serdes->remote_nr == 1); + is_rx_dual_channels = (serdes->channel_nr == 2) && (serdes->remote_nr == 1); + } + + rk120_linkrx_video_fm_enable(serdes, dev_id, true); + rk120_linkrx_engine_lane_enable(serdes, dev_id, is_rx_dual_channels, is_rx_dual_lanes); + rk120_linkrx_lane_enable(serdes, dev_id, is_rx_dual_lanes ? 2 : 1); + + rk120_linkrx_lane_engine_dst_cfg(serdes, dev_id, is_rx_dual_channels, is_rx_dual_lanes); + rk120_linkrx_lane_id_cfg(serdes, dev_id, is_rx_dual_channels, is_rx_dual_lanes); + if (route->local_port0) { + if (dev_id == DEVICE_REMOTE0) { + rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id, + route->remote0_port0, 0); + if (is_rx_dual_channels) + rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id, + route->remote0_port1, 1); + } else { + rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id, + route->remote1_port0, 0); + } + } else { + rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id, + route->remote1_port0, 0); + } + + rk120_linkrx_data_and_order_id_cfg(serdes, dev_id, is_rx_dual_channels, + is_rx_dual_lanes); if (serdes->version == SERDES_V1) { /* * The serdes v1 have a bug when enable video suspend function, which @@ -594,87 +785,14 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r * reducing the video packet length: * length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16 */ - length = vm->hactive * 24 / 32 / 16; + u32 length; + + length = route->vm.hactive * 24 / 32 / 16; length = (length + 15) / 16 * 16; - serdes->i2c_write_reg(client, DES_RKLINK_REC01_PKT_LENGTH, E0_REPKT_LENGTH(length) | - E1_REPKT_LENGTH(length)); + rk120_linkrx_config_pkt_length(serdes, dev_id, length); } - serdes->i2c_read_reg(client, RKLINK_DES_SOURCE_CFG, &val); - - val &= ~(LANE0_ENGINE_ID(1) | LANE0_LANE_ID(1) | LANE1_ENGINE_ID(1) | - LANE1_LANE_ID(1) | LNAE0_ID_SEL(1) | LNAE1_ID_SEL(1)); - - if (is_rx_dual_lanes) { - if (is_rx_dual_channels) { - val |= LANE0_ENGINE_ID(0); - val |= LANE0_LANE_ID(0); - val |= LNAE0_ID_SEL(1); - val |= LANE1_ENGINE_ID(1); - val |= LANE1_LANE_ID(0); - val |= LNAE1_ID_SEL(1); - stream_type |= E1_STREAM_DISPLAY; - } else { - val |= LANE0_ENGINE_ID(0); - val |= LANE0_LANE_ID(0); - val |= LNAE0_ID_SEL(1); - val |= LANE1_ENGINE_ID(0); - val |= LANE1_LANE_ID(1); - val |= LNAE0_ID_SEL(1); - } - } else { - if (is_rx_dual_channels) { - val |= LANE0_ENGINE_ID(0); - val |= LANE0_LANE_ID(0); - val |= LANE1_ENGINE_ID(1); - val |= LANE1_LANE_ID(0); - stream_type |= E1_STREAM_DISPLAY; - } else { - val |= LNAE0_ID_SEL(1); - } - } - val |= stream_type; - if (remote_id == DEVICE_REMOTE0) - rx_src = rk_des_get_stream_source(route, route->remote0_port0, 0); - else - rx_src = rk_des_get_stream_source(route, route->remote1_port0, 0); - val |= rx_src; - if (is_rx_dual_channels) { - rx_src = rk_des_get_stream_source(route, route->remote0_port1, 1); - val |= rx_src; - } - serdes->i2c_write_reg(client, RKLINK_DES_SOURCE_CFG, val); - - if (is_rx_dual_lanes || is_rx_dual_channels) { - mask = DATA_FIFO0_WR_ID_MASK | DATA_FIFO1_WR_ID_MASK | DATA_FIFO2_WR_ID_MASK | - DATA_FIFO3_WR_ID_MASK; - mask |= DATA_FIFO0_RD_ID_MASK | DATA_FIFO1_RD_ID_MASK | DATA_FIFO2_RD_ID_MASK | - DATA_FIFO3_RD_ID_MASK; - if (is_rx_dual_channels) { - lane0_dsource_id = (0 << 1) | 0; - lane1_dsource_id = (1 << 1) | 0; - } else { - lane0_dsource_id = (0 << 1) | 0; - lane1_dsource_id = (0 << 1) | 1; - } - val = DATA_FIFO0_WR_ID(lane0_dsource_id) | DATA_FIFO1_WR_ID(lane0_dsource_id); - val |= DATA_FIFO0_RD_ID(lane0_dsource_id) | DATA_FIFO1_RD_ID(lane0_dsource_id); - - val |= DATA_FIFO2_WR_ID(lane1_dsource_id) | DATA_FIFO3_WR_ID(lane1_dsource_id); - val |= DATA_FIFO2_RD_ID(lane1_dsource_id) | DATA_FIFO3_RD_ID(lane1_dsource_id); - - serdes->i2c_update_bits(client, RKLINK_DES_DATA_ID_CFG, mask, val); - - mask = ORDER_FIFO0_WR_ID_MASK | ORDER_FIFO1_WR_ID_MASK | - ORDER_FIFO0_RD_ID_MASK | ORDER_FIFO1_RD_ID_MASK; - val = ORDER_FIFO0_WR_ID(lane0_dsource_id) | ORDER_FIFO1_WR_ID(lane1_dsource_id) | - ORDER_FIFO0_RD_ID(lane0_dsource_id) | ORDER_FIFO1_RD_ID(lane1_dsource_id); - - serdes->i2c_update_bits(client, RKLINK_DES_ORDER_ID_CFG, mask, val); - } - - ctrl_val |= DES_EN; - serdes->i2c_write_reg(client, RKLINK_DES_LANE_ENGINE_CFG, ctrl_val); + rk120_linkrx_des_enable(serdes, dev_id, true); hwclk_set_rate(hwclk, RKX120_CPS_E0_CLK_RKLINK_RX_PRE, route->vm.pixelclock); dev_info(serdes->dev, "RKX120_CPS_E0_CLK_RKLINK_RX_PRE:%d\n", @@ -686,17 +804,17 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r } if (route->remote0_port0 == RK_SERDES_RGB_TX || route->remote1_port0 == RK_SERDES_RGB_TX) - rk_serdes_link_rx_rgb_enable(serdes, route, remote_id); + rk_serdes_link_rx_rgb_enable(serdes, route, dev_id); if (route->remote0_port0 == RK_SERDES_LVDS_TX0 || route->remote1_port0 == RK_SERDES_LVDS_TX0 || route->remote0_port0 == RK_SERDES_LVDS_TX1 || route->remote1_port0 == RK_SERDES_LVDS_TX1 || route->remote0_port0 == RK_SERDES_DUAL_LVDS_TX) - rk_serdes_link_rx_lvds_enable(serdes, route, remote_id); + rk_serdes_link_rx_lvds_enable(serdes, route, dev_id); if (route->remote0_port0 == RK_SERDES_DSI_TX0 || route->remote1_port0 == RK_SERDES_DSI_TX0) - rk_serdes_link_rx_dsi_enable(serdes, route, remote_id); + rk_serdes_link_rx_dsi_enable(serdes, route, dev_id); return 0; } @@ -713,18 +831,19 @@ static int rk120_des_pma_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r return 0; } -int rkx120_linkrx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id) +int rkx120_display_linkrx_enable(struct rk_serdes *serdes, + struct rk_serdes_route *route, u8 dev_id) { - rk120_link_rx_cfg(serdes, route, remote_id); + rk120_display_linkrx_cfg(serdes, route, dev_id); - rk120_des_pcs_cfg(serdes, route, remote_id, 0); - rk120_des_pma_cfg(serdes, route, remote_id, 0); - if ((serdes->route_flag & ROUTE_MULTI_LANE) && - !(serdes->route_flag & ROUTE_MULTI_REMOTE)) { - rk120_des_pcs_cfg(serdes, route, remote_id, 1); - rk120_des_pma_cfg(serdes, route, remote_id, 1); + rk120_des_pcs_cfg(serdes, route, dev_id, 0); + rk120_des_pma_cfg(serdes, route, dev_id, 0); + if ((serdes->lane_nr == 2) && (serdes->remote_nr == 1)) { + rk120_des_pcs_cfg(serdes, route, dev_id, 1); + rk120_des_pma_cfg(serdes, route, dev_id, 1); } + return 0; } @@ -761,7 +880,7 @@ void rkx120_linkrx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32 } } -void rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id) +int rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id) { struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client; u32 val; @@ -781,6 +900,8 @@ void rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id) 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; } static void rkx120_pma_link_config(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id) diff --git a/drivers/mfd/rkx110_x120/serdes_combphy.h b/drivers/mfd/rkx110_x120/serdes_combphy.h index b5447fc82de7..d4526329b221 100644 --- a/drivers/mfd/rkx110_x120/serdes_combphy.h +++ b/drivers/mfd/rkx110_x120/serdes_combphy.h @@ -14,15 +14,20 @@ int serdes_combphy_update_bits(struct rk_serdes *serdes, u8 remote_id, void serdes_combphy_get_default_config(u64 hs_clk_rate, struct configure_opts_combphy *cfg); -void rkx110_combrxphy_set_mode(struct rk_serdes *ser, enum combrx_phy_mode mode); -void rkx110_combrxphy_set_rate(struct rk_serdes *ser, u64 rate); -void rkx110_combrxphy_power_on(struct rk_serdes *ser, enum comb_phy_id id); -void rkx110_combrxphy_power_off(struct rk_serdes *ser, enum comb_phy_id id); +void rkx110_combrxphy_set_mode(struct rkx110_combrxphy *combrxphy, enum combrx_phy_mode mode); +void rkx110_combrxphy_set_rate(struct rkx110_combrxphy *combrxphy, u64 rate); +void rkx110_combrxphy_set_lanes(struct rkx110_combrxphy *combrxphy, uint8_t lanes); +void rkx110_combrxphy_power_on(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id); +void rkx110_combrxphy_power_off(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy, + u8 dev_id, enum comb_phy_id id); -void rkx120_combtxphy_set_mode(struct rk_serdes *des, enum combtx_phy_mode mode); -void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate); -u64 rkx120_combtxphy_get_rate(struct rk_serdes *des); -void rkx120_combtxphy_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id); -void rkx120_combtxphy_power_off(struct rk_serdes *des, u8 remote_id); +void rkx120_combtxphy_set_mode(struct rkx120_combtxphy *combtxphy, enum combtx_phy_mode mode); +void rkx120_combtxphy_set_rate(struct rkx120_combtxphy *combtxphy, u64 rate); +u64 rkx120_combtxphy_get_rate(struct rkx120_combtxphy *combtxphy); +void rkx120_combtxphy_power_on(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy, + u8 dev_id, u8 phy_id); +void rkx120_combtxphy_power_off(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy, + u8 dev_id, u8 phy_id); #endif