From: Peterson Guo <peterson.guo(a)amd.com>
[WHY]
On some cards when odm is used, the monitor will have 2 separate pipes
split vertically. When compression is used on the YCbCr colour space on
the second pipe to have correct colours, we need to read a pixel from the
end of first pipe to accurately display colours. Hardware was programmed
properly to account for this extra pixel but it was not calculated
properly in software causing a split screen on some monitors.
[HOW]
The fix adjusts the second pipe's viewport and timings if the pixel
encoding is YCbCr422 or YCbCr420.
Cc: Mario Limonciello <mario.limonciello(a)amd.com>
Cc: Alex Deucher <alexander.deucher(a)amd.com>
Cc: stable(a)vger.kernel.org
Reviewed-by: George Shen <george.shen(a)amd.com>
Signed-off-by: Peterson Guo <peterson.guo(a)amd.com>
Signed-off-by: Alex Hung <alex.hung(a)amd.com>
---
.../dc/resource/dcn20/dcn20_resource.c | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
index 189d0c85872e..7a5b9aa5292c 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
@@ -1510,6 +1510,7 @@ bool dcn20_split_stream_for_odm(
if (prev_odm_pipe->plane_state) {
struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data;
+ struct output_pixel_processor *opp = next_odm_pipe->stream_res.opp;
int new_width;
/* HACTIVE halved for odm combine */
@@ -1543,7 +1544,28 @@ bool dcn20_split_stream_for_odm(
sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz_c, sd->h_active - sd->recout.x));
sd->recout.x = 0;
+
+ /*
+ * When odm is used in YcbCr422 or 420 colour space, a split screen
+ * will be seen with the previous calculations since the extra left
+ * edge pixel is accounted for in fmt but not in viewport.
+ *
+ * Below are calculations which fix the split by fixing the calculations
+ * if there is an extra left edge pixel.
+ */
+ if (opp && opp->funcs->opp_get_left_edge_extra_pixel_count
+ && opp->funcs->opp_get_left_edge_extra_pixel_count(
+ opp, next_odm_pipe->stream->timing.pixel_encoding,
+ resource_is_pipe_type(next_odm_pipe, OTG_MASTER)) == 1) {
+ sd->h_active += 1;
+ sd->recout.width += 1;
+ sd->viewport.x -= dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1));
+ sd->viewport_c.x -= dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1));
+ sd->viewport_c.width += dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1));
+ sd->viewport.width += dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1));
+ }
}
+
if (!next_odm_pipe->top_pipe)
next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx];
else
@@ -2132,6 +2154,7 @@ bool dcn20_fast_validate_bw(
ASSERT(0);
}
}
+
/* Actual dsc count per stream dsc validation*/
if (!dcn20_validate_dsc(dc, context)) {
context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] =
--
2.43.0
As per [1] and [2], ADV7535/7533 supports only 2-, 3-, or 4-lane. Drop
unsupported 1-lane.
[1] https://www.analog.com/media/en/technical-documentation/data-sheets/ADV7535…
[2] https://www.analog.com/media/en/technical-documentation/data-sheets/ADV7533…
Fixes: 1e4d58cd7f88 ("drm/bridge: adv7533: Create a MIPI DSI device")
Reported-by: Hien Huynh <hien.huynh.px(a)renesas.com>
Cc: stable(a)vger.kernel.org
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas(a)ideasonboard.com>
Reviewed-by: Adam Ford <aford173(a)gmail.com>
Signed-off-by: Biju Das <biju.das.jz(a)bp.renesas.com>
---
Changes in v7:
- No change.
Changes in v6:
- Added Rb tag from Adam.
Changes in v5:
- No change.
Changes in v4:
- Added link to ADV7533 data sheet.
- Collected tags
Changes in v3:
- Updated commit header and description
- Updated fixes tag
- Dropped single lane support
Changes in v2:
- Added the tag "Cc: stable(a)vger.kernel.org" in the sign-off area.
- Dropped Archit Taneja invalid Mail address
---
drivers/gpu/drm/bridge/adv7511/adv7533.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index 5f195e91b3e6..122ad91e8a32 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -172,7 +172,7 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
- if (num_lanes < 1 || num_lanes > 4)
+ if (num_lanes < 2 || num_lanes > 4)
return -EINVAL;
adv->num_dsi_lanes = num_lanes;
--
2.43.0
The host_node pointer was assigned and freed in adv7533_parse_dt(), and
later, adv7533_attach_dsi() uses the same. Fix this use-after-free issue
by dropping of_node_put() in adv7533_parse_dt() and calling of_node_put()
in error path of probe() and also in the remove().
Fixes: 1e4d58cd7f88 ("drm/bridge: adv7533: Create a MIPI DSI device")
Cc: stable(a)vger.kernel.org
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas(a)ideasonboard.com>
Signed-off-by: Biju Das <biju.das.jz(a)bp.renesas.com>
---
Changes in v7:
- Dropped check for host_node as of_node_put() is a no-op when called
with a NULL pointer.
- Added Rb tag from Laurent.
Changes in v6:
- Fixed memory leak by adding goto stattement in error path of
adv7511_init_regulators().
Changes in v5:
- Updated commit description.
- restored host_node in struct adv7511.
- Dropped of_node_put() in adv7533_parse_dt() and calling of_node_put()
in error path of probe() and also in the remove().
Changes in v4:
- Updated commit description.
- Dropped host_node from struct adv7511 and instead used a local pointer
in probe(). Also freeing of host_node pointer after use is done in
probe().
Changes in v3:
- Replace __free construct with readable of_node_put().
Changes in v2:
- Added the tag "Cc: stable(a)vger.kernel.org" in the sign-off area.
- Dropped Archit Taneja invalid Mail address
---
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 10 ++++++++--
drivers/gpu/drm/bridge/adv7511/adv7533.c | 2 --
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index eb5919b38263..a13b3d8ab6ac 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1241,8 +1241,10 @@ static int adv7511_probe(struct i2c_client *i2c)
return ret;
ret = adv7511_init_regulators(adv7511);
- if (ret)
- return dev_err_probe(dev, ret, "failed to init regulators\n");
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to init regulators\n");
+ goto err_of_node_put;
+ }
/*
* The power down GPIO is optional. If present, toggle it from active to
@@ -1363,6 +1365,8 @@ static int adv7511_probe(struct i2c_client *i2c)
i2c_unregister_device(adv7511->i2c_edid);
uninit_regulators:
adv7511_uninit_regulators(adv7511);
+err_of_node_put:
+ of_node_put(adv7511->host_node);
return ret;
}
@@ -1371,6 +1375,8 @@ static void adv7511_remove(struct i2c_client *i2c)
{
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
+ of_node_put(adv7511->host_node);
+
adv7511_uninit_regulators(adv7511);
drm_bridge_remove(&adv7511->bridge);
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index 4481489aaf5e..5f195e91b3e6 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -181,8 +181,6 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
if (!adv->host_node)
return -ENODEV;
- of_node_put(adv->host_node);
-
adv->use_timing_gen = !of_property_read_bool(np,
"adi,disable-timing-generator");
--
2.43.0
The host_node pointer was assigned and freed in adv7533_parse_dt(), and
later, adv7533_attach_dsi() uses the same. Fix this use-after-free issue
by dropping of_node_put() in adv7533_parse_dt() and calling of_node_put()
in error path of probe() and also in the remove().
Fixes: 1e4d58cd7f88 ("drm/bridge: adv7533: Create a MIPI DSI device")
Cc: stable(a)vger.kernel.org
Signed-off-by: Biju Das <biju.das.jz(a)bp.renesas.com>
---
Changes in v6:
- Fixed memory leak by adding goto stattement in error path of
adv7511_init_regulators().
Changes in v5:
- Updated commit description.
- restored host_node in struct adv7511.
- Dropped of_node_put() in adv7533_parse_dt() and calling of_node_put()
in error path of probe() and also in the remove().
Changes in v4:
- Updated commit description.
- Dropped host_node from struct adv7511 and instead used a local pointer
in probe(). Also freeing of host_node pointer after use is done in
probe().
Changes in v3:
- Replace __free construct with readable of_node_put().
Changes in v2:
- Added the tag "Cc: stable(a)vger.kernel.org" in the sign-off area.
- Dropped Archit Taneja invalid Mail address
---
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 12 ++++++++++--
drivers/gpu/drm/bridge/adv7511/adv7533.c | 2 --
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index eb5919b38263..f5525c12f0cd 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1241,8 +1241,10 @@ static int adv7511_probe(struct i2c_client *i2c)
return ret;
ret = adv7511_init_regulators(adv7511);
- if (ret)
- return dev_err_probe(dev, ret, "failed to init regulators\n");
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to init regulators\n");
+ goto err_of_node_put;
+ }
/*
* The power down GPIO is optional. If present, toggle it from active to
@@ -1363,6 +1365,9 @@ static int adv7511_probe(struct i2c_client *i2c)
i2c_unregister_device(adv7511->i2c_edid);
uninit_regulators:
adv7511_uninit_regulators(adv7511);
+err_of_node_put:
+ if (adv7511->host_node)
+ of_node_put(adv7511->host_node);
return ret;
}
@@ -1371,6 +1376,9 @@ static void adv7511_remove(struct i2c_client *i2c)
{
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
+ if (adv7511->host_node)
+ of_node_put(adv7511->host_node);
+
adv7511_uninit_regulators(adv7511);
drm_bridge_remove(&adv7511->bridge);
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index 4481489aaf5e..5f195e91b3e6 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -181,8 +181,6 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
if (!adv->host_node)
return -ENODEV;
- of_node_put(adv->host_node);
-
adv->use_timing_gen = !of_property_read_bool(np,
"adi,disable-timing-generator");
--
2.43.0
As per [1] and [2], ADV7535/7533 supports only 2-, 3-, or 4-lane. Drop
unsupported 1-lane.
[1] https://www.analog.com/media/en/technical-documentation/data-sheets/ADV7535…
[2] https://www.analog.com/media/en/technical-documentation/data-sheets/ADV7533…
Fixes: 1e4d58cd7f88 ("drm/bridge: adv7533: Create a MIPI DSI device")
Reported-by: Hien Huynh <hien.huynh.px(a)renesas.com>
Cc: stable(a)vger.kernel.org
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas(a)ideasonboard.com>
Reviewed-by: Adam Ford <aford173(a)gmail.com>
Signed-off-by: Biju Das <biju.das.jz(a)bp.renesas.com>
---
Changes in v6:
- Added Rb tag from Adam.
Changes in v5:
- No change.
Changes in v4:
- Added link to ADV7533 data sheet.
- Collected tags
Changes in v3:
- Updated commit header and description
- Updated fixes tag
- Dropped single lane support
Changes in v2:
- Added the tag "Cc: stable(a)vger.kernel.org" in the sign-off area.
- Dropped Archit Taneja invalid Mail address
---
drivers/gpu/drm/bridge/adv7511/adv7533.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index 5f195e91b3e6..122ad91e8a32 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -172,7 +172,7 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
- if (num_lanes < 1 || num_lanes > 4)
+ if (num_lanes < 2 || num_lanes > 4)
return -EINVAL;
adv->num_dsi_lanes = num_lanes;
--
2.43.0
The host_node pointer was assigned and freed in adv7533_parse_dt(), and
later, adv7533_attach_dsi() uses the same. Fix this use-after-free issue
by dropping of_node_put() in adv7533_parse_dt() and calling of_node_put()
in error path of probe() and also in the remove().
Fixes: 1e4d58cd7f88 ("drm/bridge: adv7533: Create a MIPI DSI device")
Cc: stable(a)vger.kernel.org
Signed-off-by: Biju Das <biju.das.jz(a)bp.renesas.com>
---
Changes in v5:
- Updated commit description.
- restored host_node in struct adv7511.
- Dropped of_node_put() in adv7533_parse_dt() and calling of_node_put()
in error path of probe() and also in the remove().
Changes in v4:
- Updated commit description.
- Dropped host_node from struct adv7511 and instead used a local pointer
in probe(). Also freeing of host_node pointer after use is done in
probe().
Changes in v3:
- Replace __free construct with readable of_node_put().
Changes in v2:
- Added the tag "Cc: stable(a)vger.kernel.org" in the sign-off area.
- Dropped Archit Taneja invalid Mail address
---
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 5 +++++
drivers/gpu/drm/bridge/adv7511/adv7533.c | 2 --
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index eb5919b38263..6cfdda04f52f 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1363,6 +1363,8 @@ static int adv7511_probe(struct i2c_client *i2c)
i2c_unregister_device(adv7511->i2c_edid);
uninit_regulators:
adv7511_uninit_regulators(adv7511);
+ if (adv7511->host_node)
+ of_node_put(adv7511->host_node);
return ret;
}
@@ -1371,6 +1373,9 @@ static void adv7511_remove(struct i2c_client *i2c)
{
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
+ if (adv7511->host_node)
+ of_node_put(adv7511->host_node);
+
adv7511_uninit_regulators(adv7511);
drm_bridge_remove(&adv7511->bridge);
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index 4481489aaf5e..5f195e91b3e6 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -181,8 +181,6 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
if (!adv->host_node)
return -ENODEV;
- of_node_put(adv->host_node);
-
adv->use_timing_gen = !of_property_read_bool(np,
"adi,disable-timing-generator");
--
2.43.0