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

From: Sebastian Reichel

Date: Mon Jun 01 2026 - 08:02:23 EST


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 <damon.ding@xxxxxxxxxxxxxx>
>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxx>

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