mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 01:59:02 +00:00
ca5c695a45
Deleted following upstreamed patches: bcm27xx: 950-0006-drm-vc4-hdmi-Fix-HPD-GPIO-detection.patch bcm27xx: 950-0420-drm-vc4-Adopt-the-dma-configuration-from-the-HVS-or-.patch bcm27xx: 950-0425-drm-vc4-A-present-but-empty-dmas-disables-audio.patch bcm27xx: 950-0432-vc4-drm-Avoid-full-hdmi-audio-fifo-writes.patch bcm27xx: 950-0433-vc4-drm-vc4_plane-Remove-subpixel-positioning-check.patch bcm27xx: 950-0435-drm-vc4-Correct-pixel-order-for-DSI0.patch bcm27xx: 950-0436-drm-vc4-Register-dsi0-as-the-correct-vc4-encoder-typ.patch bcm27xx: 950-0437-drm-vc4-Fix-dsi0-interrupt-support.patch bcm27xx: 950-0438-drm-vc4-Add-correct-stop-condition-to-vc4_dsi_encode.patch bcm27xx: 950-0443-drm-vc4-Fix-timings-for-interlaced-modes.patch bcm27xx: 950-0445-drm-vc4-Fix-margin-calculations-for-the-right-bottom.patch bcm27xx: 950-0475-drm-vc4-Reset-HDMI-MISC_CONTROL-register.patch bcm27xx: 950-0476-drm-vc4-Release-workaround-buffer-and-DMA-in-error-p.patch bcm27xx: 950-0477-drm-vc4-Correct-DSI-divider-calculations.patch bcm27xx: 950-0664-drm-vc4-dsi-Correct-max-divider-to-255-not-7.patch bcm53xx: 072-next-ARM_dts_BCM53015-add-mr26.patch mediatek: 920-linux-next-dts-mt7622-bpi-r64-fix-wps-button.patch Manually rebased following patches: bcm27xx: 950-0004-drm-vc4-hdmi-Remove-the-DDC-probing-for-status-detec.patch bcm27xx: 950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch bcm27xx: 950-0711-drm-vc4-Rename-bridge-to-out_bridge.patch bcm27xx: 950-0713-drm-vc4-Remove-splitting-the-bridge-chain-from-the-d.patch bcm27xx: 950-0715-drm-vc4-Convert-vc4_dsi-to-using-a-bridge-instead-of.patch bcm27xx: 950-0787-vc4-drm-vc4_plane-Keep-fractional-source-coords-insi.patch bcm27xx: 950-0914-mmc-block-Don-t-do-single-sector-reads-during-recove.patch Runtime tested on turris-omnia and glinet-b1300. Tested-by: John Audia <therealgraysky@proton.me> [bcm2711/RPi4B, mt7622/RT3200] Signed-off-by: Petr Štetiar <ynezz@true.cz>
309 lines
9.5 KiB
Diff
309 lines
9.5 KiB
Diff
From 2c8b6954e6168d56cc6d35f5f6d075c826a9b8e1 Mon Sep 17 00:00:00 2001
|
|
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
|
Date: Thu, 16 Dec 2021 15:25:35 +0000
|
|
Subject: [PATCH] drm/bridge: Introduce pre_enable_upstream_first to
|
|
alter bridge init order
|
|
|
|
DSI sink devices typically want the DSI host powered up and configured
|
|
before they are powered up. pre_enable is the place this would normally
|
|
happen, but they are called in reverse order from panel/connector towards
|
|
the encoder, which is the "wrong" order.
|
|
|
|
Add a new flag pre_enable_upstream_first that any bridge can set
|
|
to swap the order of pre_enable (and post_disable) for that and the
|
|
immediately upstream bridge.
|
|
Should the immediately upstream bridge also set the
|
|
pre_enable_upstream_first flag, the bridge upstream of that will be called
|
|
before either of those which requested pre_enable_upstream_first.
|
|
|
|
eg:
|
|
- Panel
|
|
- Bridge 1
|
|
- Bridge 2 pre_enable_upstream_first
|
|
- Bridge 3
|
|
- Bridge 4 pre_enable_upstream_first
|
|
- Bridge 5 pre_enable_upstream_first
|
|
- Bridge 6
|
|
- Encoder
|
|
Would result in pre_enable's being called as Panel, Bridge 1, Bridge 3,
|
|
Bridge 2, Bridge 6, Bridge 5, Bridge 4, Encoder.
|
|
|
|
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
|
---
|
|
drivers/gpu/drm/drm_bridge.c | 177 +++++++++++++++++++++++++----------
|
|
include/drm/drm_bridge.h | 8 ++
|
|
2 files changed, 137 insertions(+), 48 deletions(-)
|
|
|
|
--- a/drivers/gpu/drm/drm_bridge.c
|
|
+++ b/drivers/gpu/drm/drm_bridge.c
|
|
@@ -462,20 +462,15 @@ EXPORT_SYMBOL(drm_bridge_chain_disable);
|
|
* encoder chain, starting from the first bridge to the last. These are called
|
|
* after completing the encoder's prepare op.
|
|
*
|
|
+ * If a bridge sets @pre_enable_upstream_first, then the @post_disable for that
|
|
+ * bridge will be called before the previous one to reverse the @pre_enable
|
|
+ * calling direction.
|
|
+ *
|
|
* Note: the bridge passed should be the one closest to the encoder
|
|
*/
|
|
void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
|
|
{
|
|
- struct drm_encoder *encoder;
|
|
-
|
|
- if (!bridge)
|
|
- return;
|
|
-
|
|
- encoder = bridge->encoder;
|
|
- list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
|
|
- if (bridge->funcs->post_disable)
|
|
- bridge->funcs->post_disable(bridge);
|
|
- }
|
|
+ drm_atomic_bridge_chain_post_disable(bridge, NULL);
|
|
}
|
|
EXPORT_SYMBOL(drm_bridge_chain_post_disable);
|
|
|
|
@@ -517,24 +512,14 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set)
|
|
* chain, starting from the last bridge to the first. These are called
|
|
* before calling the encoder's commit op.
|
|
*
|
|
+ * If a bridge sets @pre_enable_upstream_first, then the @pre_enable for the
|
|
+ * previous bridge will be called before @pre_enable of this bridge.
|
|
+ *
|
|
* Note: the bridge passed should be the one closest to the encoder
|
|
*/
|
|
void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
|
|
{
|
|
- struct drm_encoder *encoder;
|
|
- struct drm_bridge *iter;
|
|
-
|
|
- if (!bridge)
|
|
- return;
|
|
-
|
|
- encoder = bridge->encoder;
|
|
- list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
|
- if (iter->funcs->pre_enable)
|
|
- iter->funcs->pre_enable(iter);
|
|
-
|
|
- if (iter == bridge)
|
|
- break;
|
|
- }
|
|
+ drm_atomic_bridge_chain_pre_enable(bridge, NULL);
|
|
}
|
|
EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
|
|
|
|
@@ -606,6 +591,25 @@ void drm_atomic_bridge_chain_disable(str
|
|
}
|
|
EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
|
|
|
|
+static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
|
|
+ struct drm_atomic_state *old_state)
|
|
+{
|
|
+ if (old_state && bridge->funcs->atomic_post_disable) {
|
|
+ struct drm_bridge_state *old_bridge_state;
|
|
+
|
|
+ old_bridge_state =
|
|
+ drm_atomic_get_old_bridge_state(old_state,
|
|
+ bridge);
|
|
+ if (WARN_ON(!old_bridge_state))
|
|
+ return;
|
|
+
|
|
+ bridge->funcs->atomic_post_disable(bridge,
|
|
+ old_bridge_state);
|
|
+ } else if (bridge->funcs->post_disable) {
|
|
+ bridge->funcs->post_disable(bridge);
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
|
|
* in the encoder chain
|
|
@@ -616,6 +620,9 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_di
|
|
* &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
|
|
* starting from the first bridge to the last. These are called after completing
|
|
* &drm_encoder_helper_funcs.atomic_disable
|
|
+ * If a bridge sets @pre_enable_upstream_first, then the @post_disable for that
|
|
+ * bridge will be called before the previous one to reverse the @pre_enable
|
|
+ * calling direction.
|
|
*
|
|
* Note: the bridge passed should be the one closest to the encoder
|
|
*/
|
|
@@ -623,30 +630,75 @@ void drm_atomic_bridge_chain_post_disabl
|
|
struct drm_atomic_state *old_state)
|
|
{
|
|
struct drm_encoder *encoder;
|
|
+ struct drm_bridge *next, *limit;
|
|
|
|
if (!bridge)
|
|
return;
|
|
|
|
encoder = bridge->encoder;
|
|
+
|
|
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
|
|
- if (bridge->funcs->atomic_post_disable) {
|
|
- struct drm_bridge_state *old_bridge_state;
|
|
+ limit = NULL;
|
|
|
|
- old_bridge_state =
|
|
- drm_atomic_get_old_bridge_state(old_state,
|
|
- bridge);
|
|
- if (WARN_ON(!old_bridge_state))
|
|
- return;
|
|
+ if (!list_is_last(&bridge->chain_node, &encoder->bridge_chain)) {
|
|
+ next = list_next_entry(bridge, chain_node);
|
|
|
|
- bridge->funcs->atomic_post_disable(bridge,
|
|
- old_bridge_state);
|
|
- } else if (bridge->funcs->post_disable) {
|
|
- bridge->funcs->post_disable(bridge);
|
|
+ if (next->pre_enable_upstream_first) {
|
|
+ /* Downstream bridge had requested that upstream
|
|
+ * was enabled first, so disabled last
|
|
+ */
|
|
+ limit = next;
|
|
+
|
|
+ /* Find the next bridge that has NOT requested
|
|
+ * upstream to be enabled first / disabled last
|
|
+ */
|
|
+ list_for_each_entry_from(next, &encoder->bridge_chain,
|
|
+ chain_node) {
|
|
+ if (next->pre_enable_upstream_first) {
|
|
+ next = list_prev_entry(next, chain_node);
|
|
+ limit = next;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Call these bridges in reverse order */
|
|
+ list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
|
|
+ chain_node) {
|
|
+ if (next == bridge)
|
|
+ break;
|
|
+
|
|
+ drm_atomic_bridge_call_post_disable(next,
|
|
+ old_state);
|
|
+ }
|
|
+ }
|
|
}
|
|
+
|
|
+ drm_atomic_bridge_call_post_disable(bridge, old_state);
|
|
+
|
|
+ if (limit)
|
|
+ bridge = limit;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
|
|
|
|
+static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
|
|
+ struct drm_atomic_state *old_state)
|
|
+{
|
|
+ if (old_state && bridge->funcs->atomic_pre_enable) {
|
|
+ struct drm_bridge_state *old_bridge_state;
|
|
+
|
|
+ old_bridge_state =
|
|
+ drm_atomic_get_old_bridge_state(old_state,
|
|
+ bridge);
|
|
+ if (WARN_ON(!old_bridge_state))
|
|
+ return;
|
|
+
|
|
+ bridge->funcs->atomic_pre_enable(bridge, old_bridge_state);
|
|
+ } else if (bridge->funcs->pre_enable) {
|
|
+ bridge->funcs->pre_enable(bridge);
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
|
|
* the encoder chain
|
|
@@ -658,33 +710,62 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_po
|
|
* starting from the last bridge to the first. These are called before calling
|
|
* &drm_encoder_helper_funcs.atomic_enable
|
|
*
|
|
+ * If a bridge sets @pre_enable_upstream_first, then the pre_enable for the
|
|
+ * upstream bridge will be called before pre_enable of this bridge.
|
|
+ *
|
|
* Note: the bridge passed should be the one closest to the encoder
|
|
*/
|
|
void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
|
|
struct drm_atomic_state *old_state)
|
|
{
|
|
struct drm_encoder *encoder;
|
|
- struct drm_bridge *iter;
|
|
+ struct drm_bridge *iter, *next, *limit;
|
|
|
|
if (!bridge)
|
|
return;
|
|
|
|
encoder = bridge->encoder;
|
|
- list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
|
- if (iter->funcs->atomic_pre_enable) {
|
|
- struct drm_bridge_state *old_bridge_state;
|
|
|
|
- old_bridge_state =
|
|
- drm_atomic_get_old_bridge_state(old_state,
|
|
- iter);
|
|
- if (WARN_ON(!old_bridge_state))
|
|
- return;
|
|
+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
|
+ if (iter->pre_enable_upstream_first) {
|
|
+ next = iter;
|
|
+ limit = bridge;
|
|
+ list_for_each_entry_from_reverse(next,
|
|
+ &encoder->bridge_chain,
|
|
+ chain_node) {
|
|
+ if (next == bridge)
|
|
+ break;
|
|
+
|
|
+ if (!next->pre_enable_upstream_first) {
|
|
+ /* Found first bridge that does NOT
|
|
+ * request upstream to be enabled first
|
|
+ */
|
|
+ limit = list_prev_entry(next, chain_node);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ list_for_each_entry_from(next, &encoder->bridge_chain, chain_node) {
|
|
+ /* Call requested upstream bridge pre_enable
|
|
+ * in order.
|
|
+ */
|
|
+ if (next == iter)
|
|
+ /* At the first bridgge to request upstream
|
|
+ * bridges called first.
|
|
+ */
|
|
+ break;
|
|
|
|
- iter->funcs->atomic_pre_enable(iter, old_bridge_state);
|
|
- } else if (iter->funcs->pre_enable) {
|
|
- iter->funcs->pre_enable(iter);
|
|
+ drm_atomic_bridge_call_pre_enable(next, old_state);
|
|
+ }
|
|
}
|
|
|
|
+ drm_atomic_bridge_call_pre_enable(iter, old_state);
|
|
+
|
|
+ if (iter->pre_enable_upstream_first)
|
|
+ /* Jump all bridges that we have already pre_enabled
|
|
+ */
|
|
+ iter = limit;
|
|
+
|
|
if (iter == bridge)
|
|
break;
|
|
}
|
|
--- a/include/drm/drm_bridge.h
|
|
+++ b/include/drm/drm_bridge.h
|
|
@@ -762,6 +762,14 @@ struct drm_bridge {
|
|
*/
|
|
bool interlace_allowed;
|
|
/**
|
|
+ * @pre_enable_upstream_first: The bridge requires that the upstream
|
|
+ * bridge @pre_enable function is called before its @pre_enable,
|
|
+ * and conversely for post_disable. This is most frequently a
|
|
+ * requirement for DSI devices which need the host to be initialised
|
|
+ * before the peripheral.
|
|
+ */
|
|
+ bool pre_enable_upstream_first;
|
|
+ /**
|
|
* @ddc: Associated I2C adapter for DDC access, if any.
|
|
*/
|
|
struct i2c_adapter *ddc;
|