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 protected]>
> 
> ---

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

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
> 

Attachment: signature.asc
Description: PGP signature

Reply via email to