Skip to contentSkip to conversation

drm/bridge: tc358767: Add DSI-to-DPI mode support

PATCH Applied Marek Vasut 2 participants 13 messages Mar 31, 2022

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

v6 cover drm/bridge: tc358767: Add DSI-to-DPI mode support

The TC358767/TC358867/TC9595 are all capable of operating in multiple modes, DPI-to-(e)DP, DSI-to-(e)DP, DSI-to-DPI. Clean up the driver, switch to atomic ops, and add support for the DSI-to-DPI mode in addition to already supported DPI-to-(e)DP mode.

Cc: Jonas Karlman <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Maxime Ripard <[email protected]>
Cc: Neil Armstrong <[email protected]>
Cc: Sam Ravnborg <[email protected]>
To: [email protected]

Marek Vasut (11):
dt-bindings: display: bridge: tc358867: Document DPI output support
dt-bindings: display: bridge: tc358867: Document DSI data-lanes
property
drm/bridge: tc358767: Change tc_ prefix to tc_edp_ for (e)DP specific
functions
drm/bridge: tc358767: Convert to atomic ops
drm/bridge: tc358767: Implement atomic_check callback drm/bridge: tc358767: Move (e)DP bridge endpoint parsing into
dedicated function
drm/bridge: tc358767: Wrap (e)DP aux I2C registration into

    tc_aux_link_setup()

drm/bridge: tc358767: Move bridge ops setup into
tc_probe_edp_bridge_endpoint()
drm/bridge: tc358767: Detect bridge mode from connected endpoints in
DT
drm/bridge: tc358767: Split tc_set_video_mode() into common and (e)DP
part
drm/bridge: tc358767: Add DSI-to-DPI mode support

 .../display/bridge/toshiba,tc358767.yaml      |  22 +-
 drivers/gpu/drm/bridge/Kconfig                |   1 +
 drivers/gpu/drm/bridge/tc358767.c             | 583 +++++++++++++++---
 3 files changed, 530 insertions(+), 76 deletions(-)
Signature · 1 line
2.35.1
#1 lore raw

PATCH v6 1/11 dt-bindings: display: bridge: tc358867: Document DPI output support

The TC358767/TC358867/TC9595 are all capable of operating in multiple modes, DPI-to-(e)DP, DSI-to-(e)DP, DSI-to-DPI. Document support for the DPI output port, which can now be connected both as input and output.

To: [email protected]
---
V2: - Rebase on next-20220217
V3: - No change
V4: - Add AB by Rob, RB/TB by Lucas
V5: - No change
V6: - No change

---
 .../devicetree/bindings/display/bridge/toshiba,tc358767.yaml  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml +2 -2
index f1541cc05297..5cfda6f2ba69 100644
@@ -61,8 +61,8 @@ properties:
       port@1:
         $ref: /schemas/graph.yaml#/properties/port
         description: |
-            DPI input port. The remote endpoint phandle should be a
-            reference to a valid DPI output endpoint node
+            DPI input/output port. The remote endpoint phandle should be a
+            reference to a valid DPI output or input endpoint node.
 
       port@2:
         $ref: /schemas/graph.yaml#/properties/port
Signature · 1 line
2.35.1
#2 lore raw

PATCH v6 2/11 dt-bindings: display: bridge: tc358867: Document DSI data-lanes property

In reply to Marek Vasut

It is necessary to specify the number of connected/used DSI data lanes when using the DSI input port of this bridge. Document the 'data-lanes' property of the DSI input port.

To: [email protected]
---
V3: - New patch
V4: - Add RB by Rob, AB/TB by Lucas
V5: - No change
V6: - No change

---
 .../display/bridge/toshiba,tc358767.yaml       | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/display/bridge/toshiba,tc358767.yaml +17 -1
index 5cfda6f2ba69..ed280053ec62 100644
@@ -53,11 +53,27 @@ properties:
 
     properties:
       port@0:
-        $ref: /schemas/graph.yaml#/properties/port
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
         description: |
             DSI input port. The remote endpoint phandle should be a
             reference to a valid DSI output endpoint node
 
+        properties:
+          endpoint:
+            $ref: /schemas/media/video-interfaces.yaml#
+            unevaluatedProperties: false
+
+            properties:
+              data-lanes:
+                description: array of physical DSI data lane indexes.
+                minItems: 1
+                items:
+                  - const: 1
+                  - const: 2
+                  - const: 3
+                  - const: 4
+
       port@1:
         $ref: /schemas/graph.yaml#/properties/port
         description: |
Signature · 1 line
2.35.1
#3 lore raw

PATCH v6 3/11 drm/bridge: tc358767: Change tc_ prefix to tc_edp_ for (e)DP specific functions

In reply to Marek Vasut

These functions are specific to (e)DP output initialization and operation, add specific tc_edp_ prefix to those functions to discern them from DPI output functions that will be added later in this series. No functional change.

---
V2: - New patch
V3: - Add RB from Lucas
- Rename tc_bridge_funcs to tc_edp_bridge_funcs
V4: - Add TB from Lucas
V5: - No change
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 39 ++++++++++++++++---------------
 1 file changed, 20 insertions(+), 19 deletions(-)
drivers/gpu/drm/bridge/tc358767.c +20 -19
index c23e0abc65e8..23e0280f484d 100644
@@ -1164,7 +1164,7 @@ static int tc_main_link_disable(struct tc_data *tc)
 	return regmap_write(tc->regmap, DP0CTL, 0);
 }
 
-static int tc_stream_enable(struct tc_data *tc)
+static int tc_edp_stream_enable(struct tc_data *tc)
 {
 	int ret;
 	u32 value;
@@ -1219,7 +1219,7 @@ static int tc_stream_enable(struct tc_data *tc)
 	return 0;
 }
 
-static int tc_stream_disable(struct tc_data *tc)
+static int tc_edp_stream_disable(struct tc_data *tc)
 {
 	int ret;
 
@@ -1234,7 +1234,7 @@ static int tc_stream_disable(struct tc_data *tc)
 	return 0;
 }
 
-static void tc_bridge_enable(struct drm_bridge *bridge)
+static void tc_edp_bridge_enable(struct drm_bridge *bridge)
 {
 	struct tc_data *tc = bridge_to_tc(bridge);
 	int ret;
@@ -1251,7 +1251,7 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
 		return;
 	}
 
-	ret = tc_stream_enable(tc);
+	ret = tc_edp_stream_enable(tc);
 	if (ret < 0) {
 		dev_err(tc->dev, "main link stream start error: %d\n", ret);
 		tc_main_link_disable(tc);
@@ -1259,12 +1259,12 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
 	}
 }
 
-static void tc_bridge_disable(struct drm_bridge *bridge)
+static void tc_edp_bridge_disable(struct drm_bridge *bridge)
 {
 	struct tc_data *tc = bridge_to_tc(bridge);
 	int ret;
 
-	ret = tc_stream_disable(tc);
+	ret = tc_edp_stream_disable(tc);
 	if (ret < 0)
 		dev_err(tc->dev, "main link stream stop error: %d\n", ret);
 
@@ -1285,9 +1285,10 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
 	return true;
 }
 
-static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge,
-					  const struct drm_display_info *info,
-					  const struct drm_display_mode *mode)
+static enum drm_mode_status
+tc_edp_mode_valid(struct drm_bridge *bridge,
+		  const struct drm_display_info *info,
+		  const struct drm_display_mode *mode)
 {
 	struct tc_data *tc = bridge_to_tc(bridge);
 	u32 req, avail;
@@ -1395,8 +1396,8 @@ static const struct drm_connector_funcs tc_connector_funcs = {
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
-static int tc_bridge_attach(struct drm_bridge *bridge,
-			    enum drm_bridge_attach_flags flags)
+static int tc_edp_bridge_attach(struct drm_bridge *bridge,
+				enum drm_bridge_attach_flags flags)
 {
 	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 	struct tc_data *tc = bridge_to_tc(bridge);
@@ -1448,18 +1449,18 @@ static int tc_bridge_attach(struct drm_bridge *bridge,
 	return ret;
 }
 
-static void tc_bridge_detach(struct drm_bridge *bridge)
+static void tc_edp_bridge_detach(struct drm_bridge *bridge)
 {
 	drm_dp_aux_unregister(&bridge_to_tc(bridge)->aux);
 }
 
-static const struct drm_bridge_funcs tc_bridge_funcs = {
-	.attach = tc_bridge_attach,
-	.detach = tc_bridge_detach,
-	.mode_valid = tc_mode_valid,
+static const struct drm_bridge_funcs tc_edp_bridge_funcs = {
+	.attach = tc_edp_bridge_attach,
+	.detach = tc_edp_bridge_detach,
+	.mode_valid = tc_edp_mode_valid,
 	.mode_set = tc_bridge_mode_set,
-	.enable = tc_bridge_enable,
-	.disable = tc_bridge_disable,
+	.enable = tc_edp_bridge_enable,
+	.disable = tc_edp_bridge_disable,
 	.mode_fixup = tc_bridge_mode_fixup,
 	.detect = tc_bridge_detect,
 	.get_edid = tc_get_edid,
@@ -1696,7 +1697,7 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	tc->aux.transfer = tc_aux_transfer;
 	drm_dp_aux_init(&tc->aux);
 
-	tc->bridge.funcs = &tc_bridge_funcs;
+	tc->bridge.funcs = &tc_edp_bridge_funcs;
 	if (tc->hpd_pin >= 0)
 		tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
 	tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
Signature · 1 line
2.35.1
#4 lore raw

PATCH v6 4/11 drm/bridge: tc358767: Convert to atomic ops

In reply to Marek Vasut

Use the atomic version of the enable/disable operations to continue the transition to the atomic API. This will be needed to access the mode from the atomic state.

---
V2: - New patch
V3: - Add RB from Lucas
V4: - Add TB from Lucas
V5: - No change
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/gpu/drm/bridge/tc358767.c +11 -4
index 23e0280f484d..f88d8e616f7f 100644
@@ -1234,7 +1234,9 @@ static int tc_edp_stream_disable(struct tc_data *tc)
 	return 0;
 }
 
-static void tc_edp_bridge_enable(struct drm_bridge *bridge)
+static void
+tc_edp_bridge_atomic_enable(struct drm_bridge *bridge,
+			    struct drm_bridge_state *old_bridge_state)
 {
 	struct tc_data *tc = bridge_to_tc(bridge);
 	int ret;
@@ -1259,7 +1261,9 @@ static void tc_edp_bridge_enable(struct drm_bridge *bridge)
 	}
 }
 
-static void tc_edp_bridge_disable(struct drm_bridge *bridge)
+static void
+tc_edp_bridge_atomic_disable(struct drm_bridge *bridge,
+			     struct drm_bridge_state *old_bridge_state)
 {
 	struct tc_data *tc = bridge_to_tc(bridge);
 	int ret;
@@ -1459,11 +1463,14 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = {
 	.detach = tc_edp_bridge_detach,
 	.mode_valid = tc_edp_mode_valid,
 	.mode_set = tc_bridge_mode_set,
-	.enable = tc_edp_bridge_enable,
-	.disable = tc_edp_bridge_disable,
+	.atomic_enable = tc_edp_bridge_atomic_enable,
+	.atomic_disable = tc_edp_bridge_atomic_disable,
 	.mode_fixup = tc_bridge_mode_fixup,
 	.detect = tc_bridge_detect,
 	.get_edid = tc_get_edid,
+	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+	.atomic_reset = drm_atomic_helper_bridge_reset,
 };
 
 static bool tc_readable_reg(struct device *dev, unsigned int reg)
Signature · 1 line
2.35.1
#5 lore raw

PATCH v6 5/11 drm/bridge: tc358767: Implement atomic_check callback

In reply to Marek Vasut

Implement .atomic_check callback which prevents user space from setting unsupported mode. The tc_edp_common_atomic_check() variant is already prepared for DSI-to-DPI mode addition, which has different frequency limits.

---
V2: - New patch
V3: - Drop edp from tc_edp_common_atomic_check,
s@\<tc_edp_common_atomic_check\>@tc_common_atomic_check@g
- Return -EINVAL in case clock frequency is too high
V4: - Add RB/TB by Lucas
V5: - No change
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
drivers/gpu/drm/bridge/tc358767.c +26 -0
index f88d8e616f7f..e95153d9c149 100644
@@ -1289,6 +1289,31 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
 	return true;
 }
 
+static int tc_common_atomic_check(struct drm_bridge *bridge,
+				  struct drm_bridge_state *bridge_state,
+				  struct drm_crtc_state *crtc_state,
+				  struct drm_connector_state *conn_state,
+				  const unsigned int max_khz)
+{
+	tc_bridge_mode_fixup(bridge, &crtc_state->mode,
+			     &crtc_state->adjusted_mode);
+
+	if (crtc_state->adjusted_mode.clock > max_khz)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int tc_edp_atomic_check(struct drm_bridge *bridge,
+			       struct drm_bridge_state *bridge_state,
+			       struct drm_crtc_state *crtc_state,
+			       struct drm_connector_state *conn_state)
+{
+	/* DPI->(e)DP interface clock limitation: upto 154 MHz */
+	return tc_common_atomic_check(bridge, bridge_state, crtc_state,
+				      conn_state, 154000);
+}
+
 static enum drm_mode_status
 tc_edp_mode_valid(struct drm_bridge *bridge,
 		  const struct drm_display_info *info,
@@ -1463,6 +1488,7 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = {
 	.detach = tc_edp_bridge_detach,
 	.mode_valid = tc_edp_mode_valid,
 	.mode_set = tc_bridge_mode_set,
+	.atomic_check = tc_edp_atomic_check,
 	.atomic_enable = tc_edp_bridge_atomic_enable,
 	.atomic_disable = tc_edp_bridge_atomic_disable,
 	.mode_fixup = tc_bridge_mode_fixup,
Signature · 1 line
2.35.1
#6 lore raw

PATCH v6 6/11 drm/bridge: tc358767: Move (e)DP bridge endpoint parsing into dedicated function

In reply to Marek Vasut

The TC358767/TC358867/TC9595 are all capable of operating in multiple modes, DPI-to-(e)DP, DSI-to-(e)DP, DSI-to-DPI. Only the first mode is currently supported. In order to support the rest of the modes without making the tc_probe() overly long, split the bridge endpoint parsing into dedicated function, where the necessary logic to detect the bridge mode based on which endpoints are connected, can be implemented.

---
V2: - Rename tc_probe_bridge_mode() to tc_probe_edp_bridge_endpoint()
to better reflect that it parses the (e)DP output endpoint
V3: - Add RB from Lucas
V4: - Add TB from Lucas
V5: - No change
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)
drivers/gpu/drm/bridge/tc358767.c +21 -9
index e95153d9c149..0f24156543ba 100644
@@ -1583,19 +1583,12 @@ static irqreturn_t tc_irq_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
 {
-	struct device *dev = &client->dev;
+	struct device *dev = tc->dev;
 	struct drm_panel *panel;
-	struct tc_data *tc;
 	int ret;
 
-	tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
-	if (!tc)
-		return -ENOMEM;
-
-	tc->dev = dev;
-
 	/* port@2 is the output port */
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL);
 	if (ret && ret != -ENODEV)
@@ -1614,6 +1607,25 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
 	}
 
+	return ret;
+}
+
+static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct tc_data *tc;
+	int ret;
+
+	tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
+	if (!tc)
+		return -ENOMEM;
+
+	tc->dev = dev;
+
+	ret = tc_probe_edp_bridge_endpoint(tc);
+	if (ret)
+		return ret;
+
 	/* Shut down GPIO is optional */
 	tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
 	if (IS_ERR(tc->sd_gpio))
Signature · 1 line
2.35.1
#7 lore raw

PATCH v6 7/11 drm/bridge: tc358767: Wrap (e)DP aux I2C registration into tc_aux_link_setup()

In reply to Marek Vasut

This bit of code is (e)DP and aux I2C link specific, move it into tc_aux_link_setup() to permit cleaner addition of DSI-to-DPI mode. No functional change.

---
V2: - New patch
V3: - Add RB from Lucas
V4: - Add TB from Lucas
V5: - No change
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/gpu/drm/bridge/tc358767.c +6 -6
index 0f24156543ba..8a8b495aa0ad 100644
@@ -656,6 +656,12 @@ static int tc_aux_link_setup(struct tc_data *tc)
 	if (ret)
 		goto err;
 
+	/* Register DP AUX channel */
+	tc->aux.name = "TC358767 AUX i2c adapter";
+	tc->aux.dev = tc->dev;
+	tc->aux.transfer = tc_aux_transfer;
+	drm_dp_aux_init(&tc->aux);
+
 	return 0;
 err:
 	dev_err(tc->dev, "tc_aux_link_setup failed: %d\n", ret);
@@ -1736,12 +1742,6 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (ret)
 		return ret;
 
-	/* Register DP AUX channel */
-	tc->aux.name = "TC358767 AUX i2c adapter";
-	tc->aux.dev = tc->dev;
-	tc->aux.transfer = tc_aux_transfer;
-	drm_dp_aux_init(&tc->aux);
-
 	tc->bridge.funcs = &tc_edp_bridge_funcs;
 	if (tc->hpd_pin >= 0)
 		tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
Signature · 1 line
2.35.1
#8 lore raw

PATCH v6 8/11 drm/bridge: tc358767: Move bridge ops setup into tc_probe_edp_bridge_endpoint()

In reply to Marek Vasut

The bridge ops are specific to the bridge configuration, move them into tc_probe_edp_bridge_endpoint() to permit cleaner addition of DSI-to-DPI mode. No functional change.

---
V2: - New patch
V3: - No change
V4: - Add RB/TB from Lucas
V5: - No change
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/bridge/tc358767.c +5 -5
index 8a8b495aa0ad..8c468f77618d 100644
@@ -1613,6 +1613,11 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
 		tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
 	}
 
+	tc->bridge.funcs = &tc_edp_bridge_funcs;
+	if (tc->hpd_pin >= 0)
+		tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
+	tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
+
 	return ret;
 }
 
@@ -1742,11 +1747,6 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (ret)
 		return ret;
 
-	tc->bridge.funcs = &tc_edp_bridge_funcs;
-	if (tc->hpd_pin >= 0)
-		tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
-	tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
-
 	tc->bridge.of_node = dev->of_node;
 	drm_bridge_add(&tc->bridge);
 
Signature · 1 line
2.35.1
#9 lore raw

PATCH v6 9/11 drm/bridge: tc358767: Detect bridge mode from connected endpoints in DT

In reply to Marek Vasut

The TC358767/TC358867/TC9595 are all capable of operating in multiple modes, DPI-to-(e)DP, DSI-to-(e)DP, DSI-to-DPI. Only the first mode is currently supported. It is possible to find out the mode in which the bridge should be operated by testing connected endpoints in DT.

Port allocation:
port@0 - DSI input
port@1 - DPI input/output
port@2 - eDP output

Possible connections:
DPI -> port@1 -> port@2 -> eDP :: [port@0 is not connected] DSI -> port@0 -> port@2 -> eDP :: [port@1 is not connected] DSI -> port@0 -> port@1 -> DPI :: [port@2 is not connected]

Add function to determine the bridge mode based on connected endpoints.

---
V2: - New patch
V3: - Add RB from Lucas
V4: - Add TB from Lucas
V5: - No change
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 46 ++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)
drivers/gpu/drm/bridge/tc358767.c +45 -1
index 8c468f77618d..dd324cf16e4d 100644
@@ -1621,6 +1621,50 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
 	return ret;
 }
 
+static int tc_probe_bridge_endpoint(struct tc_data *tc)
+{
+	struct device *dev = tc->dev;
+	struct of_endpoint endpoint;
+	struct device_node *node = NULL;
+	const u8 mode_dpi_to_edp = BIT(1) | BIT(2);
+	const u8 mode_dsi_to_edp = BIT(0) | BIT(2);
+	const u8 mode_dsi_to_dpi = BIT(0) | BIT(1);
+	u8 mode = 0;
+
+	/*
+	 * Determine bridge configuration.
+	 *
+	 * Port allocation:
+	 * port@0 - DSI input
+	 * port@1 - DPI input/output
+	 * port@2 - eDP output
+	 *
+	 * Possible connections:
+	 * DPI -> port@1 -> port@2 -> eDP :: [port@0 is not connected]
+	 * DSI -> port@0 -> port@2 -> eDP :: [port@1 is not connected]
+	 * DSI -> port@0 -> port@1 -> DPI :: [port@2 is not connected]
+	 */
+
+	for_each_endpoint_of_node(dev->of_node, node) {
+		of_graph_parse_endpoint(node, &endpoint);
+		if (endpoint.port > 2)
+			return -EINVAL;
+
+		mode |= BIT(endpoint.port);
+	}
+
+	if (mode == mode_dpi_to_edp)
+		return tc_probe_edp_bridge_endpoint(tc);
+	else if (mode == mode_dsi_to_dpi)
+		dev_warn(dev, "The mode DSI-to-DPI is not supported!\n");
+	else if (mode == mode_dsi_to_edp)
+		dev_warn(dev, "The mode DSI-to-(e)DP is not supported!\n");
+	else
+		dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode);
+
+	return -EINVAL;
+}
+
 static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	struct device *dev = &client->dev;
@@ -1633,7 +1677,7 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 	tc->dev = dev;
 
-	ret = tc_probe_edp_bridge_endpoint(tc);
+	ret = tc_probe_bridge_endpoint(tc);
 	if (ret)
 		return ret;
 
Signature · 1 line
2.35.1
#10 lore raw

PATCH v6 10/11 drm/bridge: tc358767: Split tc_set_video_mode() into common and (e)DP part

In reply to Marek Vasut

The tc_set_video_mode() sets up both common and (e)DP video mode settings of the bridge chip. Split the function into tc_set_common_video_mode() to set the common settings and tc_set_edp_video_mode() to set the (e)DP specific settings. No functional change.

---
V2: - New patch
V3: - Add RB from Lucas
V4: - Add TB from Lucas
V5: Drop unused variables from tc_set_common_video_mode()
V6: - No change

---
 drivers/gpu/drm/bridge/tc358767.c | 65 ++++++++++++++++++-------------
 1 file changed, 38 insertions(+), 27 deletions(-)
drivers/gpu/drm/bridge/tc358767.c +38 -27
index dd324cf16e4d..02f9cea738d2 100644
@@ -734,33 +734,16 @@ static int tc_get_display_props(struct tc_data *tc)
 	return ret;
 }
 
-static int tc_set_video_mode(struct tc_data *tc,
-			     const struct drm_display_mode *mode)
+static int tc_set_common_video_mode(struct tc_data *tc,
+				    const struct drm_display_mode *mode)
 {
-	int ret;
-	int vid_sync_dly;
-	int max_tu_symbol;
-
 	int left_margin = mode->htotal - mode->hsync_end;
 	int right_margin = mode->hsync_start - mode->hdisplay;
 	int hsync_len = mode->hsync_end - mode->hsync_start;
 	int upper_margin = mode->vtotal - mode->vsync_end;
 	int lower_margin = mode->vsync_start - mode->vdisplay;
 	int vsync_len = mode->vsync_end - mode->vsync_start;
-	u32 dp0_syncval;
-	u32 bits_per_pixel = 24;
-	u32 in_bw, out_bw;
-
-	/*
-	 * Recommended maximum number of symbols transferred in a transfer unit:
-	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
-	 *              (output active video bandwidth in bytes))
-	 * Must be less than tu_size.
-	 */
-
-	in_bw = mode->clock * bits_per_pixel / 8;
-	out_bw = tc->link.num_lanes * tc->link.rate;
-	max_tu_symbol = DIV_ROUND_UP(in_bw * TU_SIZE_RECOMMENDED, out_bw);
+	int ret;
 
 	dev_dbg(tc->dev, "set mode %dx%d\n",
 		mode->hdisplay, mode->vdisplay);
@@ -818,8 +801,35 @@ static int tc_set_video_mode(struct tc_data *tc,
 			   FIELD_PREP(COLOR_B, 99) |
 			   ENI2CFILTER |
 			   FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
-	if (ret)
-		return ret;
+
+	return ret;
+}
+
+static int tc_set_edp_video_mode(struct tc_data *tc,
+				 const struct drm_display_mode *mode)
+{
+	int ret;
+	int vid_sync_dly;
+	int max_tu_symbol;
+
+	int left_margin = mode->htotal - mode->hsync_end;
+	int hsync_len = mode->hsync_end - mode->hsync_start;
+	int upper_margin = mode->vtotal - mode->vsync_end;
+	int vsync_len = mode->vsync_end - mode->vsync_start;
+	u32 dp0_syncval;
+	u32 bits_per_pixel = 24;
+	u32 in_bw, out_bw;
+
+	/*
+	 * Recommended maximum number of symbols transferred in a transfer unit:
+	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
+	 *              (output active video bandwidth in bytes))
+	 * Must be less than tu_size.
+	 */
+
+	in_bw = mode->clock * bits_per_pixel / 8;
+	out_bw = tc->link.num_lanes * tc->link.rate;
+	max_tu_symbol = DIV_ROUND_UP(in_bw * TU_SIZE_RECOMMENDED, out_bw);
 
 	/* DP Main Stream Attributes */
 	vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
@@ -869,10 +879,7 @@ static int tc_set_video_mode(struct tc_data *tc,
 			   FIELD_PREP(MAX_TU_SYMBOL, max_tu_symbol) |
 			   FIELD_PREP(TU_SIZE, TU_SIZE_RECOMMENDED) |
 			   BPC_8);
-	if (ret)
-		return ret;
-
-	return 0;
+	return ret;
 }
 
 static int tc_wait_link_training(struct tc_data *tc)
@@ -1185,7 +1192,11 @@ static int tc_edp_stream_enable(struct tc_data *tc)
 			return ret;
 	}
 
-	ret = tc_set_video_mode(tc, &tc->mode);
+	ret = tc_set_common_video_mode(tc, &tc->mode);
+	if (ret)
+		return ret;
+
+	ret = tc_set_edp_video_mode(tc, &tc->mode);
 	if (ret)
 		return ret;
 
Signature · 1 line
2.35.1
#11 lore raw

PATCH v6 11/11 drm/bridge: tc358767: Add DSI-to-DPI mode support

In reply to Marek Vasut

The TC358767/TC358867/TC9595 are all capable of operating in multiple modes, DPI-to-(e)DP, DSI-to-(e)DP, DSI-to-DPI. Add support for the DSI-to-DPI mode.

This requires skipping most of the (e)DP initialization code, which is currently a large part of this driver, hence it is better to have far simpler separate tc_dpi_bridge_funcs and their implementation.

The configuration of DPI output is also much simpler. The configuration of the DSI input is rather similar to the other TC bridge chips.

The Pixel PLL in DPI output mode does not have the 65..150 MHz limitation imposed on the (e)DP output mode, so this limitation is skipped to permit operating panels with far slower pixel clock, even below 9 MHz. This mode of operation of the PLL is valid and tested.

The detection of bridge mode is now added into tc_probe_bridge_mode(), where in case a DPI panel is found on port@1 endpoint@1, the mode is assumed to be DSI-to-DPI. If (e)DP is detected on port@2, the mode is assumed to be DPI-to-(e)DP.

The DSI-to-(e)DP mode is not supported due to lack of proper hardware, but this would be some sort of mix between the two aforementioned modes.

---
V2: - Rebase on next-20220217 and new patches in this series
V3: - Drop edp from tc_edp_common_atomic_check,
s@\<tc_edp_common_atomic_check\>@tc_common_atomic_check@g
- Limit Pixel PLL output to 0-100 MHz for DPI and 150-650 MHz for eDP
- Drop VID_EN write from tc_dpi_stream_disable()
- Reduce PLL stabilization delay to 120..150us in tc_dpi_stream_enable()
- Call drm_bridge_remove() in case tc_mipi_dsi_host_attach() fails
- Check of_property_count_u32_elems() return code as int instead of u8
- Enable DP0/DP1 PLL for DSI-to-DPI mode too, they clock the internal framebuffer and it is too slow if those PLLs are in bypass
V4: - Rebase on top of dropped drm/bridge: tc358767: Move hardware init to enable callback
- Use -1 in of_graph_get_endpoint_by_regs(.., .., -1) third param
- Select DRM_MIPI_DSI
- Add RB from Lucas
V5: - No change
V6: - Fix checkpatch strict CHECK: Unnecessary parentheses around 'clk < clk_min'
- Fix checkpatch strict CHECK: Alignment should match open parenthesis
- Add DSI-to-DPI mode TB from Lucas

---
 drivers/gpu/drm/bridge/Kconfig    |   1 +
 drivers/gpu/drm/bridge/tc358767.c | 358 +++++++++++++++++++++++++++++-
 2 files changed, 348 insertions(+), 11 deletions(-)
drivers/gpu/drm/bridge/Kconfig +1 -0
index ee7610c2c1a4..a2e8a0fb13ea 100644
@@ -293,6 +293,7 @@ config DRM_TOSHIBA_TC358767
 	select DRM_DP_HELPER
 	select DRM_KMS_HELPER
 	select REGMAP_I2C
+	select DRM_MIPI_DSI
 	select DRM_PANEL
 	help
 	  Toshiba TC358767 eDP bridge chip driver.
drivers/gpu/drm/bridge/tc358767.c +347 -11

469 lines not on this page · raw message

Signature · 1 line
2.35.1
Applied
#12 lore raw
In reply to Marek Vasut
Quoted 33 lines · Marek Vasut

The TC358767/TC358867/TC9595 are all capable of operating in multiple modes, DPI-to-(e)DP, DSI-to-(e)DP, DSI-to-DPI. Clean up the driver, switch to atomic ops, and add support for the DSI-to-DPI mode in addition to already supported DPI-to-(e)DP mode.

Cc: Jonas Karlman <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Maxime Ripard <[email protected]>
Cc: Neil Armstrong <[email protected]>
Cc: Sam Ravnborg <[email protected]>
To: [email protected]

Marek Vasut (11):
dt-bindings: display: bridge: tc358867: Document DPI output support
dt-bindings: display: bridge: tc358867: Document DSI data-lanes
property
drm/bridge: tc358767: Change tc_ prefix to tc_edp_ for (e)DP specific
functions
drm/bridge: tc358767: Convert to atomic ops
drm/bridge: tc358767: Implement atomic_check callback drm/bridge: tc358767: Move (e)DP bridge endpoint parsing into
dedicated function
drm/bridge: tc358767: Wrap (e)DP aux I2C registration into

    tc_aux_link_setup()

drm/bridge: tc358767: Move bridge ops setup into
tc_probe_edp_bridge_endpoint()
drm/bridge: tc358767: Detect bridge mode from connected endpoints in
DT
drm/bridge: tc358767: Split tc_set_video_mode() into common and (e)DP
part
drm/bridge: tc358767: Add DSI-to-DPI mode support

Quoted 8 lines
 .../display/bridge/toshiba,tc358767.yaml      |  22 +-
 drivers/gpu/drm/bridge/Kconfig                |   1 +
 drivers/gpu/drm/bridge/tc358767.c             | 583 +++++++++++++++---
 3 files changed, 530 insertions(+), 76 deletions(-)

--
2.35.1

Applied to drm-misc-next.