2019-06-18 08:11:07

by James Qian Wang

[permalink] [raw]
Subject: [PATCH 0/2] drm/komeda: Enable dual-link support

Komeda HW can support dual-link which splits display frame to two halves
(left/link0, right/link1) and output them by two output links.
Due to the halved pixel rate of each link, the pxlclk of dual-link can be
reduced two times compare with single-link.

For enabling dual-link:
- The DT need to configure two output-links for the pipeline node.
- Komeda enable dual-link when both link0 and link1 have been connected.

Example of how the pipeline node will look like for dual-link setup

pipe0: pipeline@0 {
clocks = <&fpgaosc2>;
clock-names = "pxclk";
reg = <0>;

#address-cells = <1>;
#size-cells = <0>;

port@0 {
reg = <0>;

#address-cells = <1>;
#size-cells = <0>;
dp0_pipe0_link0: endpoint@0 {
reg = <0>;
remote-endpoint = <&dlink_connector_in0>;

};
dp0_pipe0_link1: endpoint@1 {
reg = <1>;
remote-endpoint = <&dlink_connector_in1>;
};
};
};

James Qian Wang (Arm Technology China) (2):
drm/komeda: Use drm_display_mode "crtc_" prefixed hardware timings
drm/komeda: Enable dual-link support

.../arm/display/komeda/d71/d71_component.c | 42 +++++----
.../gpu/drm/arm/display/komeda/komeda_crtc.c | 89 +++++++++++++------
.../gpu/drm/arm/display/komeda/komeda_dev.c | 5 +-
.../gpu/drm/arm/display/komeda/komeda_drv.c | 8 +-
.../gpu/drm/arm/display/komeda/komeda_kms.h | 4 +-
.../drm/arm/display/komeda/komeda_pipeline.c | 19 +++-
.../drm/arm/display/komeda/komeda_pipeline.h | 6 +-
.../display/komeda/komeda_pipeline_state.c | 2 +-
8 files changed, 118 insertions(+), 57 deletions(-)

--
2.17.1


2019-06-18 08:11:20

by James Qian Wang

[permalink] [raw]
Subject: [PATCH 1/2] drm/komeda: Use drm_display_mode "crtc_" prefixed hardware timings

struct drm_display_mode contains two copies of timings.
- plain timings.
- hardware timings, the ones with "crtc_" prefix.
According to the definition, update komeda to use the hardware timing.

Signed-off-by: James Qian Wang (Arm Technology China) <[email protected]>
---
.../arm/display/komeda/d71/d71_component.c | 36 ++++++++++++-------
.../gpu/drm/arm/display/komeda/komeda_crtc.c | 20 ++++++-----
.../gpu/drm/arm/display/komeda/komeda_kms.h | 2 --
3 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
index 87248babca1f..049e8bfac27b 100644
--- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
@@ -937,7 +937,7 @@ static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
denominator = (mode->htotal - 1) * v_out - 2 * v_in;
}

- return aclk_rate * denominator >= mode->clock * 1000 * fraction ?
+ return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?
0 : -EINVAL;
}

@@ -1056,21 +1056,31 @@ static void d71_timing_ctrlr_update(struct komeda_component *c,
struct komeda_component_state *state)
{
struct drm_crtc_state *crtc_st = state->crtc->state;
+ struct drm_display_mode *mode = &crtc_st->adjusted_mode;
u32 __iomem *reg = c->reg;
- struct videomode vm;
+ u32 hactive, hfront_porch, hback_porch, hsync_len;
+ u32 vactive, vfront_porch, vback_porch, vsync_len;
u32 value;

- drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm);
-
- malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive));
- malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch,
- vm.hback_porch));
- malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch,
- vm.vback_porch));
-
- value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len);
- value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0;
- value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0;
+ hactive = mode->crtc_hdisplay;
+ hfront_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;
+ hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+ hback_porch = mode->crtc_htotal - mode->crtc_hsync_end;
+
+ vactive = mode->crtc_vdisplay;
+ vfront_porch = mode->crtc_vsync_start - mode->crtc_vdisplay;
+ vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ vback_porch = mode->crtc_vtotal - mode->crtc_vsync_end;
+
+ malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(hactive, vactive));
+ malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(hfront_porch,
+ hback_porch));
+ malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vfront_porch,
+ vback_porch));
+
+ value = BS_SYNC_VSW(vsync_len) | BS_SYNC_HSW(hsync_len);
+ value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BS_SYNC_VSP : 0;
+ value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BS_SYNC_HSP : 0;
malidp_write32(reg, BS_SYNC, value);

malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index 1b4ea8ab41fa..98e36e1fb2ad 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -27,7 +27,7 @@ static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st)
return;
}

- pxlclk = kcrtc_st->base.adjusted_mode.clock * 1000;
+ pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000;
aclk = komeda_calc_aclk(kcrtc_st) << 32;

do_div(aclk, pxlclk);
@@ -78,9 +78,9 @@ komeda_crtc_atomic_check(struct drm_crtc *crtc,
unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st)
{
struct komeda_dev *mdev = kcrtc_st->base.crtc->dev->dev_private;
- unsigned long pxlclk = kcrtc_st->base.adjusted_mode.clock;
+ unsigned long aclk = kcrtc_st->base.adjusted_mode.crtc_clock;

- return clk_round_rate(mdev->aclk, pxlclk * 1000);
+ return clk_round_rate(mdev->aclk, aclk * 1000);
}

/* For active a crtc, mainly need two parts of preparation
@@ -93,7 +93,7 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
struct komeda_pipeline *master = kcrtc->master;
struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(kcrtc->base.state);
- unsigned long pxlclk_rate = kcrtc_st->base.adjusted_mode.clock * 1000;
+ struct drm_display_mode *mode = &kcrtc_st->base.adjusted_mode;
u32 new_mode;
int err;

@@ -127,7 +127,7 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
DRM_ERROR("failed to enable aclk.\n");
}

- err = clk_set_rate(master->pxlclk, pxlclk_rate);
+ err = clk_set_rate(master->pxlclk, mode->crtc_clock * 1000);
if (err)
DRM_ERROR("failed to set pxlclk for pipe%d\n", master->id);
err = clk_prepare_enable(master->pxlclk);
@@ -380,10 +380,14 @@ static bool komeda_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode)
{
struct komeda_crtc *kcrtc = to_kcrtc(crtc);
- struct komeda_pipeline *master = kcrtc->master;
- long mode_clk = m->clock * 1000;
+ unsigned long clk_rate;
+
+ drm_mode_set_crtcinfo(adjusted_mode, 0);

- adjusted_mode->clock = clk_round_rate(master->pxlclk, mode_clk) / 1000;
+ clk_rate = adjusted_mode->crtc_clock * 1000;
+ /* crtc_clock will be used as the komeda output pixel clock */
+ adjusted_mode->crtc_clock = clk_round_rate(kcrtc->master->pxlclk,
+ clk_rate) / 1000;

return true;
}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
index 219fa3f0c336..af6af1d55643 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -14,8 +14,6 @@
#include <drm/drm_device.h>
#include <drm/drm_writeback.h>
#include <drm/drm_print.h>
-#include <video/videomode.h>
-#include <video/display_timing.h>

/**
* struct komeda_plane - komeda instance of drm_plane
--
2.17.1

2019-06-18 08:13:15

by James Qian Wang

[permalink] [raw]
Subject: [PATCH 2/2] drm/komeda: Enable dual-link support

Komeda HW can support dual-link which splits display frame to two halves
(left/link0, right/link1) and output them by two output links.
Due to the halved pixel rate of each link, the pxlclk of dual-link can be
reduced two times compare with single-link.

For enabling dual-link:
- The DT need to configure two output-links for the pipeline node.
- Komeda enable dual-link when both link0 and link1 have been connected.

Example of how the pipeline node will look like for dual-link setup

pipe0: pipeline@0 {
clocks = <&fpgaosc2>;
clock-names = "pxclk";
reg = <0>;

#address-cells = <1>;
#size-cells = <0>;

port@0 {
reg = <0>;

#address-cells = <1>;
#size-cells = <0>;
dp0_pipe0_link0: endpoint@0 {
reg = <0>;
remote-endpoint = <&dlink_connector_in0>;

};
dp0_pipe0_link1: endpoint@1 {
reg = <1>;
remote-endpoint = <&dlink_connector_in1>;
};
};
};

Signed-off-by: James Qian Wang (Arm Technology China) <[email protected]>
---
.../arm/display/komeda/d71/d71_component.c | 6 +-
.../gpu/drm/arm/display/komeda/komeda_crtc.c | 73 +++++++++++++------
.../gpu/drm/arm/display/komeda/komeda_dev.c | 5 +-
.../gpu/drm/arm/display/komeda/komeda_drv.c | 8 +-
.../gpu/drm/arm/display/komeda/komeda_kms.h | 2 +-
.../drm/arm/display/komeda/komeda_pipeline.c | 19 ++++-
.../drm/arm/display/komeda/komeda_pipeline.h | 6 +-
.../display/komeda/komeda_pipeline_state.c | 2 +-
8 files changed, 85 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
index 049e8bfac27b..8e9d44d01e91 100644
--- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
@@ -4,8 +4,6 @@
* Author: James.Qian.Wang <[email protected]>
*
*/
-
-#include <drm/drm_print.h>
#include "d71_dev.h"
#include "komeda_kms.h"
#include "malidp_io.h"
@@ -1088,6 +1086,10 @@ static void d71_timing_ctrlr_update(struct komeda_component *c,

/* configure bs control register */
value = BS_CTRL_EN | BS_CTRL_VM;
+ if (c->pipeline->dual_link) {
+ malidp_write32(reg, BS_DRIFT_TO, hfront_porch + 16);
+ value |= BS_CTRL_DL;
+ }

malidp_write32(reg, BLK_CONTROL, value);
}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index 98e36e1fb2ad..ec43032f3c2c 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -28,7 +28,7 @@ static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st)
}

pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000;
- aclk = komeda_calc_aclk(kcrtc_st) << 32;
+ aclk = komeda_crtc_get_aclk(kcrtc_st) << 32;

do_div(aclk, pxlclk);
kcrtc_st->clock_ratio = aclk;
@@ -75,14 +75,6 @@ komeda_crtc_atomic_check(struct drm_crtc *crtc,
return 0;
}

-unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st)
-{
- struct komeda_dev *mdev = kcrtc_st->base.crtc->dev->dev_private;
- unsigned long aclk = kcrtc_st->base.adjusted_mode.crtc_clock;
-
- return clk_round_rate(mdev->aclk, aclk * 1000);
-}
-
/* For active a crtc, mainly need two parts of preparation
* 1. adjust display operation mode.
* 2. enable needed clk
@@ -119,7 +111,7 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
* to enable it again.
*/
if (new_mode != KOMEDA_MODE_DUAL_DISP) {
- err = clk_set_rate(mdev->aclk, komeda_calc_aclk(kcrtc_st));
+ err = clk_set_rate(mdev->aclk, komeda_crtc_get_aclk(kcrtc_st));
if (err)
DRM_ERROR("failed to set aclk.\n");
err = clk_prepare_enable(mdev->aclk);
@@ -345,29 +337,58 @@ komeda_crtc_atomic_flush(struct drm_crtc *crtc,
komeda_crtc_do_flush(crtc, old);
}

+/* Returns the minimum frequency of the aclk rate (main engine clock) in Hz */
+static unsigned long
+komeda_calc_min_aclk_rate(struct komeda_crtc *kcrtc,
+ unsigned long pxlclk)
+{
+ /* Once dual-link one display pipeline drives two display outputs,
+ * the aclk needs run on the double rate of pxlclk
+ */
+ if (kcrtc->master->dual_link)
+ return pxlclk * 2;
+ else
+ return pxlclk;
+}
+
+/* Get current aclk rate that specified by state */
+unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st)
+{
+ struct drm_crtc *crtc = kcrtc_st->base.crtc;
+ struct komeda_dev *mdev = crtc->dev->dev_private;
+ unsigned long pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000;
+ unsigned long min_aclk;
+
+ min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), pxlclk);
+
+ return clk_round_rate(mdev->aclk, min_aclk);
+}
+
static enum drm_mode_status
komeda_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *m)
{
struct komeda_dev *mdev = crtc->dev->dev_private;
struct komeda_crtc *kcrtc = to_kcrtc(crtc);
struct komeda_pipeline *master = kcrtc->master;
- long mode_clk, pxlclk;
+ unsigned long min_pxlclk, min_aclk;

if (m->flags & DRM_MODE_FLAG_INTERLACE)
return MODE_NO_INTERLACE;

- mode_clk = m->clock * 1000;
- pxlclk = clk_round_rate(master->pxlclk, mode_clk);
- if (pxlclk != mode_clk) {
- DRM_DEBUG_ATOMIC("pxlclk doesn't support %ld Hz\n", mode_clk);
+ min_pxlclk = m->clock * 1000;
+ if (master->dual_link)
+ min_pxlclk /= 2;
+
+ if (min_pxlclk != clk_round_rate(master->pxlclk, min_pxlclk)) {
+ DRM_DEBUG_ATOMIC("pxlclk doesn't support %lu Hz\n", min_pxlclk);

return MODE_NOCLOCK;
}

- /* main engine clock must be faster than pxlclk*/
- if (clk_round_rate(mdev->aclk, mode_clk) < pxlclk) {
- DRM_DEBUG_ATOMIC("engine clk can't satisfy the requirement of %s-clk: %ld.\n",
- m->name, pxlclk);
+ min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), min_pxlclk);
+ if (clk_round_rate(mdev->aclk, min_aclk) < min_aclk) {
+ DRM_DEBUG_ATOMIC("engine clk can't satisfy the requirement of %s-clk: %lu.\n",
+ m->name, min_pxlclk);

return MODE_CLOCK_HIGH;
}
@@ -383,6 +404,14 @@ static bool komeda_crtc_mode_fixup(struct drm_crtc *crtc,
unsigned long clk_rate;

drm_mode_set_crtcinfo(adjusted_mode, 0);
+ /* In dual link half the horizontal settings */
+ if (kcrtc->master->dual_link) {
+ adjusted_mode->crtc_clock /= 2;
+ adjusted_mode->crtc_hdisplay /= 2;
+ adjusted_mode->crtc_hsync_start /= 2;
+ adjusted_mode->crtc_hsync_end /= 2;
+ adjusted_mode->crtc_htotal /= 2;
+ }

clk_rate = adjusted_mode->crtc_clock * 1000;
/* crtc_clock will be used as the komeda output pixel clock */
@@ -514,10 +543,8 @@ int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
else
sprintf(str, "None");

- DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
- kms->n_crtcs, master->id, str,
- master->of_output_dev ?
- master->of_output_dev->full_name : "None");
+ DRM_INFO("CRTC-%d: master(pipe-%d) slave(%s).\n",
+ kms->n_crtcs, master->id, str);

kms->n_crtcs++;
}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
index edd09435f35d..591da1ef7894 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -123,11 +123,14 @@ static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
pipe->pxlclk = clk;

/* enum ports */
- pipe->of_output_dev =
+ pipe->of_output_links[0] =
of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
+ pipe->of_output_links[1] =
+ of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 1);
pipe->of_output_port =
of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);

+ pipe->dual_link = pipe->of_output_links[0] && pipe->of_output_links[1];
pipe->of_node = np;

return 0;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
index aa4cef1fe84e..66e4ce8abd67 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -89,11 +89,12 @@ static int compare_of(struct device *dev, void *data)

static void komeda_add_slave(struct device *master,
struct component_match **match,
- struct device_node *np, int port)
+ struct device_node *np,
+ u32 port, u32 endpoint)
{
struct device_node *remote;

- remote = of_graph_get_remote_node(np, port, 0);
+ remote = of_graph_get_remote_node(np, port, endpoint);
if (remote) {
drm_of_component_match_add(master, match, compare_of, remote);
of_node_put(remote);
@@ -114,7 +115,8 @@ static int komeda_platform_probe(struct platform_device *pdev)
continue;

/* add connector */
- komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
+ komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT, 0);
+ komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT, 1);
}

return component_master_add_with_match(dev, &komeda_master_ops, match);
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
index af6af1d55643..cf2122be2740 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -180,7 +180,7 @@ static inline bool has_flip_h(u32 rot)
return !!(rotation & DRM_MODE_REFLECT_X);
}

-unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st);
+unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st);

int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index 78e44d9e1520..452e505a1fd3 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -54,7 +54,8 @@ void komeda_pipeline_destroy(struct komeda_dev *mdev,

clk_put(pipe->pxlclk);

- of_node_put(pipe->of_output_dev);
+ of_node_put(pipe->of_output_links[0]);
+ of_node_put(pipe->of_output_links[1]);
of_node_put(pipe->of_output_port);
of_node_put(pipe->of_node);

@@ -246,9 +247,15 @@ static void komeda_pipeline_dump(struct komeda_pipeline *pipe)
struct komeda_component *c;
int id;

- DRM_INFO("Pipeline-%d: n_layers: %d, n_scalers: %d, output: %s\n",
+ DRM_INFO("Pipeline-%d: n_layers: %d, n_scalers: %d, output: %s.\n",
pipe->id, pipe->n_layers, pipe->n_scalers,
- pipe->of_output_dev ? pipe->of_output_dev->full_name : "none");
+ pipe->dual_link ? "dual-link" : "single-link");
+ DRM_INFO(" output_link[0]: %s.\n",
+ pipe->of_output_links[0] ?
+ pipe->of_output_links[0]->full_name : "none");
+ DRM_INFO(" output_link[1]: %s.\n",
+ pipe->of_output_links[1] ?
+ pipe->of_output_links[1]->full_name : "none");

dp_for_each_set_bit(id, pipe->avail_comps) {
c = komeda_pipeline_get_component(pipe, id);
@@ -305,6 +312,12 @@ static void komeda_pipeline_assemble(struct komeda_pipeline *pipe)

layer->right = komeda_get_layer_split_right_layer(pipe, layer);
}
+
+ if (pipe->dual_link && !pipe->ctrlr->supports_dual_link) {
+ pipe->dual_link = false;
+ DRM_WARN("PIPE-%d doesn't support dual-link, ignore DT dual-link configuration.\n",
+ pipe->id);
+ }
}

/* if pipeline_A accept another pipeline_B's component as input, treat
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 7af3e266bdff..059d76fc405d 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -419,8 +419,10 @@ struct komeda_pipeline {
struct device_node *of_node;
/** @of_output_port: pipeline output port */
struct device_node *of_output_port;
- /** @of_output_dev: output connector device node */
- struct device_node *of_output_dev;
+ /** @of_output_links: output connector device nodes */
+ struct device_node *of_output_links[2];
+ /** @dual_link: true if of_output_links[0] and [1] are both valid */
+ bool dual_link;
};

/**
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
index 257f0aedd11d..796cae61ffb3 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -473,7 +473,7 @@ komeda_scaler_check_cfg(struct komeda_scaler *scaler,

err = pipe->funcs->downscaling_clk_check(pipe,
&kcrtc_st->base.adjusted_mode,
- komeda_calc_aclk(kcrtc_st), dflow);
+ komeda_crtc_get_aclk(kcrtc_st), dflow);
if (err) {
DRM_DEBUG_ATOMIC("aclk can't satisfy the clock requirement of the downscaling\n");
return err;
--
2.17.1

2019-07-29 19:24:54

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH 1/2] drm/komeda: Use drm_display_mode "crtc_" prefixed hardware timings

On Tue, Jun 18, 2019 at 09:10:40AM +0100, james qian wang (Arm Technology China) wrote:
> struct drm_display_mode contains two copies of timings.
> - plain timings.
> - hardware timings, the ones with "crtc_" prefix.
> According to the definition, update komeda to use the hardware timing.
>
> Signed-off-by: James Qian Wang (Arm Technology China) <[email protected]>

Reviewed-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> .../arm/display/komeda/d71/d71_component.c | 36 ++++++++++++-------
> .../gpu/drm/arm/display/komeda/komeda_crtc.c | 20 ++++++-----
> .../gpu/drm/arm/display/komeda/komeda_kms.h | 2 --
> 3 files changed, 35 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
> index 87248babca1f..049e8bfac27b 100644
> --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
> +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
> @@ -937,7 +937,7 @@ static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
> denominator = (mode->htotal - 1) * v_out - 2 * v_in;
> }
>
> - return aclk_rate * denominator >= mode->clock * 1000 * fraction ?
> + return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?
> 0 : -EINVAL;
> }
>
> @@ -1056,21 +1056,31 @@ static void d71_timing_ctrlr_update(struct komeda_component *c,
> struct komeda_component_state *state)
> {
> struct drm_crtc_state *crtc_st = state->crtc->state;
> + struct drm_display_mode *mode = &crtc_st->adjusted_mode;
> u32 __iomem *reg = c->reg;
> - struct videomode vm;
> + u32 hactive, hfront_porch, hback_porch, hsync_len;
> + u32 vactive, vfront_porch, vback_porch, vsync_len;
> u32 value;
>
> - drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm);
> -
> - malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive));
> - malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch,
> - vm.hback_porch));
> - malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch,
> - vm.vback_porch));
> -
> - value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len);
> - value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0;
> - value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0;
> + hactive = mode->crtc_hdisplay;
> + hfront_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;
> + hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
> + hback_porch = mode->crtc_htotal - mode->crtc_hsync_end;
> +
> + vactive = mode->crtc_vdisplay;
> + vfront_porch = mode->crtc_vsync_start - mode->crtc_vdisplay;
> + vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
> + vback_porch = mode->crtc_vtotal - mode->crtc_vsync_end;
> +
> + malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(hactive, vactive));
> + malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(hfront_porch,
> + hback_porch));
> + malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vfront_porch,
> + vback_porch));
> +
> + value = BS_SYNC_VSW(vsync_len) | BS_SYNC_HSW(hsync_len);
> + value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BS_SYNC_VSP : 0;
> + value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BS_SYNC_HSP : 0;
> malidp_write32(reg, BS_SYNC, value);
>
> malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> index 1b4ea8ab41fa..98e36e1fb2ad 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> @@ -27,7 +27,7 @@ static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st)
> return;
> }
>
> - pxlclk = kcrtc_st->base.adjusted_mode.clock * 1000;
> + pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000;
> aclk = komeda_calc_aclk(kcrtc_st) << 32;
>
> do_div(aclk, pxlclk);
> @@ -78,9 +78,9 @@ komeda_crtc_atomic_check(struct drm_crtc *crtc,
> unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st)
> {
> struct komeda_dev *mdev = kcrtc_st->base.crtc->dev->dev_private;
> - unsigned long pxlclk = kcrtc_st->base.adjusted_mode.clock;
> + unsigned long aclk = kcrtc_st->base.adjusted_mode.crtc_clock;
>
> - return clk_round_rate(mdev->aclk, pxlclk * 1000);
> + return clk_round_rate(mdev->aclk, aclk * 1000);
> }
>
> /* For active a crtc, mainly need two parts of preparation
> @@ -93,7 +93,7 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
> struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
> struct komeda_pipeline *master = kcrtc->master;
> struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(kcrtc->base.state);
> - unsigned long pxlclk_rate = kcrtc_st->base.adjusted_mode.clock * 1000;
> + struct drm_display_mode *mode = &kcrtc_st->base.adjusted_mode;
> u32 new_mode;
> int err;
>
> @@ -127,7 +127,7 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
> DRM_ERROR("failed to enable aclk.\n");
> }
>
> - err = clk_set_rate(master->pxlclk, pxlclk_rate);
> + err = clk_set_rate(master->pxlclk, mode->crtc_clock * 1000);
> if (err)
> DRM_ERROR("failed to set pxlclk for pipe%d\n", master->id);
> err = clk_prepare_enable(master->pxlclk);
> @@ -380,10 +380,14 @@ static bool komeda_crtc_mode_fixup(struct drm_crtc *crtc,
> struct drm_display_mode *adjusted_mode)
> {
> struct komeda_crtc *kcrtc = to_kcrtc(crtc);
> - struct komeda_pipeline *master = kcrtc->master;
> - long mode_clk = m->clock * 1000;
> + unsigned long clk_rate;
> +
> + drm_mode_set_crtcinfo(adjusted_mode, 0);
>
> - adjusted_mode->clock = clk_round_rate(master->pxlclk, mode_clk) / 1000;
> + clk_rate = adjusted_mode->crtc_clock * 1000;
> + /* crtc_clock will be used as the komeda output pixel clock */
> + adjusted_mode->crtc_clock = clk_round_rate(kcrtc->master->pxlclk,
> + clk_rate) / 1000;
>
> return true;
> }
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> index 219fa3f0c336..af6af1d55643 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> @@ -14,8 +14,6 @@
> #include <drm/drm_device.h>
> #include <drm/drm_writeback.h>
> #include <drm/drm_print.h>
> -#include <video/videomode.h>
> -#include <video/display_timing.h>
>
> /**
> * struct komeda_plane - komeda instance of drm_plane
> --
> 2.17.1

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2019-07-29 19:24:58

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH 2/2] drm/komeda: Enable dual-link support

On Tue, Jun 18, 2019 at 09:10:49AM +0100, james qian wang (Arm Technology China) wrote:
> Komeda HW can support dual-link which splits display frame to two halves
> (left/link0, right/link1) and output them by two output links.
> Due to the halved pixel rate of each link, the pxlclk of dual-link can be
> reduced two times compare with single-link.
>
> For enabling dual-link:
> - The DT need to configure two output-links for the pipeline node.
> - Komeda enable dual-link when both link0 and link1 have been connected.
>
> Example of how the pipeline node will look like for dual-link setup
>
> pipe0: pipeline@0 {
> clocks = <&fpgaosc2>;
> clock-names = "pxclk";
> reg = <0>;
>
> #address-cells = <1>;
> #size-cells = <0>;
>
> port@0 {
> reg = <0>;
>
> #address-cells = <1>;
> #size-cells = <0>;
> dp0_pipe0_link0: endpoint@0 {
> reg = <0>;
> remote-endpoint = <&dlink_connector_in0>;
>
> };
> dp0_pipe0_link1: endpoint@1 {
> reg = <1>;
> remote-endpoint = <&dlink_connector_in1>;
> };
> };
> };
>
> Signed-off-by: James Qian Wang (Arm Technology China) <[email protected]>

Reviewed-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> .../arm/display/komeda/d71/d71_component.c | 6 +-
> .../gpu/drm/arm/display/komeda/komeda_crtc.c | 73 +++++++++++++------
> .../gpu/drm/arm/display/komeda/komeda_dev.c | 5 +-
> .../gpu/drm/arm/display/komeda/komeda_drv.c | 8 +-
> .../gpu/drm/arm/display/komeda/komeda_kms.h | 2 +-
> .../drm/arm/display/komeda/komeda_pipeline.c | 19 ++++-
> .../drm/arm/display/komeda/komeda_pipeline.h | 6 +-
> .../display/komeda/komeda_pipeline_state.c | 2 +-
> 8 files changed, 85 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
> index 049e8bfac27b..8e9d44d01e91 100644
> --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
> +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
> @@ -4,8 +4,6 @@
> * Author: James.Qian.Wang <[email protected]>
> *
> */
> -
> -#include <drm/drm_print.h>
> #include "d71_dev.h"
> #include "komeda_kms.h"
> #include "malidp_io.h"
> @@ -1088,6 +1086,10 @@ static void d71_timing_ctrlr_update(struct komeda_component *c,
>
> /* configure bs control register */
> value = BS_CTRL_EN | BS_CTRL_VM;
> + if (c->pipeline->dual_link) {
> + malidp_write32(reg, BS_DRIFT_TO, hfront_porch + 16);
> + value |= BS_CTRL_DL;
> + }
>
> malidp_write32(reg, BLK_CONTROL, value);
> }
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> index 98e36e1fb2ad..ec43032f3c2c 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> @@ -28,7 +28,7 @@ static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st)
> }
>
> pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000;
> - aclk = komeda_calc_aclk(kcrtc_st) << 32;
> + aclk = komeda_crtc_get_aclk(kcrtc_st) << 32;
>
> do_div(aclk, pxlclk);
> kcrtc_st->clock_ratio = aclk;
> @@ -75,14 +75,6 @@ komeda_crtc_atomic_check(struct drm_crtc *crtc,
> return 0;
> }
>
> -unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st)
> -{
> - struct komeda_dev *mdev = kcrtc_st->base.crtc->dev->dev_private;
> - unsigned long aclk = kcrtc_st->base.adjusted_mode.crtc_clock;
> -
> - return clk_round_rate(mdev->aclk, aclk * 1000);
> -}
> -
> /* For active a crtc, mainly need two parts of preparation
> * 1. adjust display operation mode.
> * 2. enable needed clk
> @@ -119,7 +111,7 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
> * to enable it again.
> */
> if (new_mode != KOMEDA_MODE_DUAL_DISP) {
> - err = clk_set_rate(mdev->aclk, komeda_calc_aclk(kcrtc_st));
> + err = clk_set_rate(mdev->aclk, komeda_crtc_get_aclk(kcrtc_st));
> if (err)
> DRM_ERROR("failed to set aclk.\n");
> err = clk_prepare_enable(mdev->aclk);
> @@ -345,29 +337,58 @@ komeda_crtc_atomic_flush(struct drm_crtc *crtc,
> komeda_crtc_do_flush(crtc, old);
> }
>
> +/* Returns the minimum frequency of the aclk rate (main engine clock) in Hz */
> +static unsigned long
> +komeda_calc_min_aclk_rate(struct komeda_crtc *kcrtc,
> + unsigned long pxlclk)
> +{
> + /* Once dual-link one display pipeline drives two display outputs,
> + * the aclk needs run on the double rate of pxlclk
> + */
> + if (kcrtc->master->dual_link)
> + return pxlclk * 2;
> + else
> + return pxlclk;
> +}
> +
> +/* Get current aclk rate that specified by state */
> +unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st)
> +{
> + struct drm_crtc *crtc = kcrtc_st->base.crtc;
> + struct komeda_dev *mdev = crtc->dev->dev_private;
> + unsigned long pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000;
> + unsigned long min_aclk;
> +
> + min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), pxlclk);
> +
> + return clk_round_rate(mdev->aclk, min_aclk);
> +}
> +
> static enum drm_mode_status
> komeda_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *m)
> {
> struct komeda_dev *mdev = crtc->dev->dev_private;
> struct komeda_crtc *kcrtc = to_kcrtc(crtc);
> struct komeda_pipeline *master = kcrtc->master;
> - long mode_clk, pxlclk;
> + unsigned long min_pxlclk, min_aclk;
>
> if (m->flags & DRM_MODE_FLAG_INTERLACE)
> return MODE_NO_INTERLACE;
>
> - mode_clk = m->clock * 1000;
> - pxlclk = clk_round_rate(master->pxlclk, mode_clk);
> - if (pxlclk != mode_clk) {
> - DRM_DEBUG_ATOMIC("pxlclk doesn't support %ld Hz\n", mode_clk);
> + min_pxlclk = m->clock * 1000;
> + if (master->dual_link)
> + min_pxlclk /= 2;
> +
> + if (min_pxlclk != clk_round_rate(master->pxlclk, min_pxlclk)) {
> + DRM_DEBUG_ATOMIC("pxlclk doesn't support %lu Hz\n", min_pxlclk);
>
> return MODE_NOCLOCK;
> }
>
> - /* main engine clock must be faster than pxlclk*/
> - if (clk_round_rate(mdev->aclk, mode_clk) < pxlclk) {
> - DRM_DEBUG_ATOMIC("engine clk can't satisfy the requirement of %s-clk: %ld.\n",
> - m->name, pxlclk);
> + min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), min_pxlclk);
> + if (clk_round_rate(mdev->aclk, min_aclk) < min_aclk) {
> + DRM_DEBUG_ATOMIC("engine clk can't satisfy the requirement of %s-clk: %lu.\n",
> + m->name, min_pxlclk);
>
> return MODE_CLOCK_HIGH;
> }
> @@ -383,6 +404,14 @@ static bool komeda_crtc_mode_fixup(struct drm_crtc *crtc,
> unsigned long clk_rate;
>
> drm_mode_set_crtcinfo(adjusted_mode, 0);
> + /* In dual link half the horizontal settings */
> + if (kcrtc->master->dual_link) {
> + adjusted_mode->crtc_clock /= 2;
> + adjusted_mode->crtc_hdisplay /= 2;
> + adjusted_mode->crtc_hsync_start /= 2;
> + adjusted_mode->crtc_hsync_end /= 2;
> + adjusted_mode->crtc_htotal /= 2;
> + }
>
> clk_rate = adjusted_mode->crtc_clock * 1000;
> /* crtc_clock will be used as the komeda output pixel clock */
> @@ -514,10 +543,8 @@ int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
> else
> sprintf(str, "None");
>
> - DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
> - kms->n_crtcs, master->id, str,
> - master->of_output_dev ?
> - master->of_output_dev->full_name : "None");
> + DRM_INFO("CRTC-%d: master(pipe-%d) slave(%s).\n",
> + kms->n_crtcs, master->id, str);
>
> kms->n_crtcs++;
> }
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> index edd09435f35d..591da1ef7894 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> @@ -123,11 +123,14 @@ static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
> pipe->pxlclk = clk;
>
> /* enum ports */
> - pipe->of_output_dev =
> + pipe->of_output_links[0] =
> of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
> + pipe->of_output_links[1] =
> + of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 1);
> pipe->of_output_port =
> of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
>
> + pipe->dual_link = pipe->of_output_links[0] && pipe->of_output_links[1];
> pipe->of_node = np;
>
> return 0;
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> index aa4cef1fe84e..66e4ce8abd67 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> @@ -89,11 +89,12 @@ static int compare_of(struct device *dev, void *data)
>
> static void komeda_add_slave(struct device *master,
> struct component_match **match,
> - struct device_node *np, int port)
> + struct device_node *np,
> + u32 port, u32 endpoint)
> {
> struct device_node *remote;
>
> - remote = of_graph_get_remote_node(np, port, 0);
> + remote = of_graph_get_remote_node(np, port, endpoint);
> if (remote) {
> drm_of_component_match_add(master, match, compare_of, remote);
> of_node_put(remote);
> @@ -114,7 +115,8 @@ static int komeda_platform_probe(struct platform_device *pdev)
> continue;
>
> /* add connector */
> - komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
> + komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT, 0);
> + komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT, 1);
> }
>
> return component_master_add_with_match(dev, &komeda_master_ops, match);
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> index af6af1d55643..cf2122be2740 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> @@ -180,7 +180,7 @@ static inline bool has_flip_h(u32 rot)
> return !!(rotation & DRM_MODE_REFLECT_X);
> }
>
> -unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st);
> +unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st);
>
> int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> index 78e44d9e1520..452e505a1fd3 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> @@ -54,7 +54,8 @@ void komeda_pipeline_destroy(struct komeda_dev *mdev,
>
> clk_put(pipe->pxlclk);
>
> - of_node_put(pipe->of_output_dev);
> + of_node_put(pipe->of_output_links[0]);
> + of_node_put(pipe->of_output_links[1]);
> of_node_put(pipe->of_output_port);
> of_node_put(pipe->of_node);
>
> @@ -246,9 +247,15 @@ static void komeda_pipeline_dump(struct komeda_pipeline *pipe)
> struct komeda_component *c;
> int id;
>
> - DRM_INFO("Pipeline-%d: n_layers: %d, n_scalers: %d, output: %s\n",
> + DRM_INFO("Pipeline-%d: n_layers: %d, n_scalers: %d, output: %s.\n",
> pipe->id, pipe->n_layers, pipe->n_scalers,
> - pipe->of_output_dev ? pipe->of_output_dev->full_name : "none");
> + pipe->dual_link ? "dual-link" : "single-link");
> + DRM_INFO(" output_link[0]: %s.\n",
> + pipe->of_output_links[0] ?
> + pipe->of_output_links[0]->full_name : "none");
> + DRM_INFO(" output_link[1]: %s.\n",
> + pipe->of_output_links[1] ?
> + pipe->of_output_links[1]->full_name : "none");
>
> dp_for_each_set_bit(id, pipe->avail_comps) {
> c = komeda_pipeline_get_component(pipe, id);
> @@ -305,6 +312,12 @@ static void komeda_pipeline_assemble(struct komeda_pipeline *pipe)
>
> layer->right = komeda_get_layer_split_right_layer(pipe, layer);
> }
> +
> + if (pipe->dual_link && !pipe->ctrlr->supports_dual_link) {
> + pipe->dual_link = false;
> + DRM_WARN("PIPE-%d doesn't support dual-link, ignore DT dual-link configuration.\n",
> + pipe->id);
> + }
> }
>
> /* if pipeline_A accept another pipeline_B's component as input, treat
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> index 7af3e266bdff..059d76fc405d 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> @@ -419,8 +419,10 @@ struct komeda_pipeline {
> struct device_node *of_node;
> /** @of_output_port: pipeline output port */
> struct device_node *of_output_port;
> - /** @of_output_dev: output connector device node */
> - struct device_node *of_output_dev;
> + /** @of_output_links: output connector device nodes */
> + struct device_node *of_output_links[2];
> + /** @dual_link: true if of_output_links[0] and [1] are both valid */
> + bool dual_link;
> };
>
> /**
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
> index 257f0aedd11d..796cae61ffb3 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
> @@ -473,7 +473,7 @@ komeda_scaler_check_cfg(struct komeda_scaler *scaler,
>
> err = pipe->funcs->downscaling_clk_check(pipe,
> &kcrtc_st->base.adjusted_mode,
> - komeda_calc_aclk(kcrtc_st), dflow);
> + komeda_crtc_get_aclk(kcrtc_st), dflow);
> if (err) {
> DRM_DEBUG_ATOMIC("aclk can't satisfy the clock requirement of the downscaling\n");
> return err;
> --
> 2.17.1

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯