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 >
signature.asc
Description: PGP signature
