Subject: Re: [PATCH v4 3/3] drm/bridge: analogix_dp: Add support for optional data-lanes mapping

From: Sebastian Reichel <[email-masked]>
Date: Mon, 1 Jun 2026 13:59:29 +0200

Hi,

On Fri, May 29, 2026 at 12:05:30PM +0800, Damon Ding wrote:
> Parse the optional 'data-lanes' device tree property to support
> custom physical lane mapping configuration.
> 
> If no valid configuration is found, fall back to the default
> lane map (0, 1, 2, 3) automatically and keep the driver running.
> 
> Lane mapping is mainly used for below scenarios:
> 1. Correct PCB lane swap and differential line routing crossover
>    without hardware changes;
> 2. Adapt mismatched lane pin definitions between SoC and eDP panel;
> 3. Support multiple panel hardware variants on the same board
>    by configuring data-lanes in device tree only.
> 
> Signed-off-by: Damon Ding <[email-masked]>
> 
> ---

Reviewed-by: Sebastian Reichel <[email-masked]>

Greetings,

-- Sebastian

> 
> Changes in v2:
> - Add lane mapping application scenarios in commit message.
> ---
>  .../drm/bridge/analogix/analogix_dp_core.c    | 56 +++++++++++++++++++
>  .../drm/bridge/analogix/analogix_dp_core.h    |  4 +-
>  .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 +++--
>  .../gpu/drm/bridge/analogix/analogix_dp_reg.h |  4 ++
>  4 files changed, 70 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 699a7f380c56..b2e729850391 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1234,6 +1234,59 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
>  	.detect = analogix_dp_bridge_detect,
>  };
>  
> +static int analogix_dp_dt_parse_lanes_map(struct analogix_dp_device *dp)
> +{
> +	struct video_info *video_info = &dp->video_info;
> +	struct device_node *endpoint;
> +	u32 tmp[LANE_COUNT4];
> +	u32 map[LANE_COUNT4] = {0, 1, 2, 3};
> +	bool used[LANE_COUNT4] = {false};
> +	int num_lanes;
> +	int ret, i;
> +
> +	memcpy(video_info->lane_map, map, sizeof(map));
> +
> +	num_lanes = drm_of_get_data_lanes_count_ep(dp->dev->of_node, 1, 0, 1,
> +						   video_info->max_lane_count);
> +	if (num_lanes < 0)
> +		return -EINVAL;
> +
> +	endpoint = of_graph_get_endpoint_by_regs(dp->dev->of_node, 1, -1);
> +	if (!endpoint)
> +		return -EINVAL;
> +
> +	ret = of_property_read_u32_array(endpoint, "data-lanes", tmp, num_lanes);
> +	of_node_put(endpoint);
> +	if (ret)
> +		return -EINVAL;
> +
> +	for (i = 0; i < num_lanes; i++) {
> +		if (tmp[i] >= LANE_COUNT4) {
> +			dev_dbg(dp->dev, "data-lanes[%d] = %u is out of range\n", i, tmp[i]);
> +			return -EINVAL;
> +		}
> +
> +		if (used[tmp[i]]) {
> +			dev_dbg(dp->dev, "data-lanes[%d] = %u is duplicate\n", i, tmp[i]);
> +			return -EINVAL;
> +		}
> +
> +		used[tmp[i]] = true;
> +		map[i] = tmp[i];
> +	}
> +
> +	for (i = 0; i < LANE_COUNT4 && num_lanes < LANE_COUNT4; i++) {
> +		if (!used[i])
> +			map[num_lanes++] = i;
> +	}
> +
> +	dev_dbg(dp->dev, "Using parsed lane map: <%u %u %u %u>\n", map[0], map[1], map[2], map[3]);
> +
> +	memcpy(video_info->lane_map, map, sizeof(map));
> +
> +	return 0;
> +}
> +
>  static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
>  {
>  	struct device_node *dp_node = dp->dev->of_node;
> @@ -1274,6 +1327,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
>  		break;
>  	}
>  
> +	if (analogix_dp_dt_parse_lanes_map(dp))
> +		dev_dbg(dp->dev, "No valid data-lanes found, using default lane map\n");
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> index 17347448c6b0..634fad241e69 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> @@ -137,6 +137,8 @@ struct video_info {
>  
>  	int max_link_rate;
>  	enum link_lane_count_type max_lane_count;
> +
> +	u32 lane_map[LANE_COUNT4];
>  };
>  
>  struct link_train {
> @@ -175,7 +177,7 @@ struct analogix_dp_device {
>  /* analogix_dp_reg.c */
>  void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable);
>  void analogix_dp_stop_video(struct analogix_dp_device *dp);
> -void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable);
> +void analogix_dp_lane_mapping(struct analogix_dp_device *dp);
>  void analogix_dp_init_analog_param(struct analogix_dp_device *dp);
>  void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
>  void analogix_dp_reset(struct analogix_dp_device *dp);
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> index 38fd8d5014d2..45c7652645a1 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> @@ -48,16 +48,15 @@ void analogix_dp_stop_video(struct analogix_dp_device *dp)
>  	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
>  }
>  
> -void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)
> +void analogix_dp_lane_mapping(struct analogix_dp_device *dp)
>  {
> +	u32 *lane_map = dp->video_info.lane_map;
>  	u32 reg;
>  
> -	if (enable)
> -		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
> -		      LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
> -	else
> -		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
> -		      LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
> +	reg = lane_map[0] << LANE0_MAP_SHIFT;
> +	reg |= lane_map[1] << LANE1_MAP_SHIFT;
> +	reg |= lane_map[2] << LANE2_MAP_SHIFT;
> +	reg |= lane_map[3] << LANE3_MAP_SHIFT;
>  
>  	writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP);
>  }
> @@ -140,7 +139,7 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
>  
>  	usleep_range(20, 30);
>  
> -	analogix_dp_lane_swap(dp, 0);
> +	analogix_dp_lane_mapping(dp);
>  
>  	writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
>  	writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> index 12735139046c..ac914e37089b 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> @@ -209,6 +209,10 @@
>  #define LANE0_MAP_LOGIC_LANE_1			(0x1 << 0)
>  #define LANE0_MAP_LOGIC_LANE_2			(0x2 << 0)
>  #define LANE0_MAP_LOGIC_LANE_3			(0x3 << 0)
> +#define LANE3_MAP_SHIFT				(6)
> +#define LANE2_MAP_SHIFT				(4)
> +#define LANE1_MAP_SHIFT				(2)
> +#define LANE0_MAP_SHIFT				(0)
>  
>  /* ANALOGIX_DP_ANALOG_CTL_1 */
>  #define TX_TERMINAL_CTRL_50_OHM			(0x1 << 4)
> -- 
> 2.34.1
>