[Freedreno] [PATCH v14 00/14] Add PSR support for eDP

2023-03-02 Thread Vinod Polimera
Changes in v2:
  - Use dp bridge to set psr entry/exit instead of dpu_enocder.
  - Don't modify whitespaces.
  - Set self refresh aware from atomic_check.
  - Set self refresh aware only if psr is supported.
  - Provide a stub for msm_dp_display_set_psr.
  - Move dp functions to bridge code.

Changes in v3:
  - Change callback names to reflect atomic interfaces.
  - Move bridge callback change to separate patch as suggested by Dmitry.
  - Remove psr function declaration from msm_drv.h.
  - Set self_refresh_aware flag only if psr is supported.
  - Modify the variable names to simpler form.
  - Define bit fields for PSR settings.
  - Add comments explaining the steps to enter/exit psr.
  - Change DRM_INFO to drm_dbg_db. 

Changes in v4:
  - Move the get crtc functions to drm_atomic.
  - Add atomic functions for DP bridge too.
  - Add ternary operator to choose eDP or DP ops.
  - Return true/false instead of 1/0.
  - mode_valid missing in the eDP bridge ops.
  - Move the functions to get crtc into drm_atomic.c.
  - Fix compilation issues.
  - Remove dpu_assign_crtc and get crtc from drm_enc instead of dpu_enc.
  - Check for crtc state enable while reserving resources.

Changes in v5:
  - Move the mode_valid changes into a different patch.
  - Complete psr_op_comp only when isr is set.
  - Move the DP atomic callback changes to a different patch.
  - Get crtc from drm connector state crtc.
  - Move to separate patch for check for crtc state enable while
reserving resources.

Changes in v6:
  - Remove crtc from dpu_encoder_virt struct.
  - fix crtc check during vblank toggle crtc.
  - Misc changes. 

Changes in v7:
  - Add fix for underrun issue on kasan build.

Changes in v8:
  - Drop the enc spinlock as it won't serve any purpose in
protetcing conn state.(Dmitry/Doug)

Changes in v9:
  - Update commit message and fix alignment using spaces.(Marijn)
  - Misc changes.(Marijn)

Changes in v10:
  - Get crtc cached in dpu_enc during obj init.(Dmitry)

Changes in v11:
  - Remove crtc cached in dpu_enc during obj init.
  - Update dpu_enc crtc state on crtc enable/disable during self refresh.

Changes in v12:
  - Update sc7180 intf mask to get intf timing gen status
based on DPU_INTF_STATUS_SUPPORTED bit.(Dmitry)
  - Remove "clear active interface in the datapath cleanup" change
as it is already included.

Changes in v13:
  - Move core changes to top of the series.(Dmitry)
  - Drop self refresh aware disable change after psr entry.(Dmitry)

Changes in v14:
  - Set self_refresh_aware for the PSR to kick in.

Vinod Polimera (14):
  drm: add helper functions to retrieve old and new crtc
  drm/bridge: use atomic enable/disable callbacks for panel bridge
  drm/bridge: add psr support for panel bridge callbacks
  drm/msm/disp/dpu: check for crtc enable rather than crtc active to
release shared resources
  drm/msm/disp/dpu: get timing engine status from intf status register
  drm/msm/disp/dpu: wait for extra vsync till timing engine status is
disabled
  drm/msm/disp/dpu: reset the datapath after timing engine disable
  drm/msm/dp: use atomic callbacks for DP bridge ops
  drm/msm/dp: Add basic PSR support for eDP
  drm/msm/dp: use the eDP bridge ops to validate eDP modes
  drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder
functions
  drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver
  drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable
during self refresh
  drm/msm/dp: set self refresh aware based on psr support

 drivers/gpu/drm/bridge/panel.c |  68 +++-
 drivers/gpu/drm/drm_atomic.c   |  60 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |  40 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  26 +++-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  22 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |   3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|   8 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c|   2 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h|   4 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   3 +
 drivers/gpu/drm/msm/dp/dp_display.c|  36 +++--
 drivers/gpu/drm/msm/dp/dp_display.h|   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c| 173 -
 drivers/gpu/drm/msm/dp/dp_drm.h|   9 +-
 drivers/gpu/drm/msm/dp/dp_link.c   |  36 +
 drivers/gpu/drm/msm/dp/dp_panel.c  |  22 +++
 drivers/gpu/drm/msm/dp/dp_panel.h  |   6 +
 drivers/gpu/drm/msm/dp/dp_reg.h|  27 
 include/drm/drm_atomic.h   |   7 +
 22 files changed, 683 insertions(+), 43 deletions(-)

-- 
2.7.4



[Freedreno] [PATCH v14 02/14] drm/bridge: use atomic enable/disable callbacks for panel bridge

2023-03-02 Thread Vinod Polimera
Use atomic variants for panel bridge callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index e8aae3c..04e9fb0 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -109,28 +109,32 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
drm_connector_cleanup(connector);
 }
 
-static void panel_bridge_pre_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_prepare(panel_bridge->panel);
 }
 
-static void panel_bridge_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_enable(panel_bridge->panel);
 }
 
-static void panel_bridge_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_disable(panel_bridge->panel);
 }
 
-static void panel_bridge_post_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
@@ -159,10 +163,10 @@ static void panel_bridge_debugfs_init(struct drm_bridge 
*bridge,
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
-   .pre_enable = panel_bridge_pre_enable,
-   .enable = panel_bridge_enable,
-   .disable = panel_bridge_disable,
-   .post_disable = panel_bridge_post_disable,
+   .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+   .atomic_enable = panel_bridge_atomic_enable,
+   .atomic_disable = panel_bridge_atomic_disable,
+   .atomic_post_disable = panel_bridge_atomic_post_disable,
.get_modes = panel_bridge_get_modes,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-- 
2.7.4



[Freedreno] [PATCH v14 01/14] drm: add helper functions to retrieve old and new crtc

2023-03-02 Thread Vinod Polimera
Add new helper functions, drm_atomic_get_old_crtc_for_encoder
and drm_atomic_get_new_crtc_for_encoder to retrieve the
corresponding crtc for the encoder.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Douglas Anderson 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_atomic.c | 60 
 include/drm/drm_atomic.h |  7 ++
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5457c02..7cc39f6 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,6 +985,66 @@ drm_atomic_get_new_connector_for_encoder(const struct 
drm_atomic_state *state,
 EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
 
 /**
+ * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that was connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The old crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_old_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
+
+/**
+ * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that will be connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The new crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_new_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
+
+/**
  * drm_atomic_get_connector_state - get connector state
  * @state: global atomic state object
  * @connector: connector to get state object for
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 92586ab..9a022ca 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -528,6 +528,13 @@ struct drm_connector *
 drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
 struct drm_encoder *encoder);
 
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+
 /**
  * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists
  * @state: global atomic state object
-- 
2.7.4



[Freedreno] [PATCH v14 03/14] drm/bridge: add psr support for panel bridge callbacks

2023-03-02 Thread Vinod Polimera
This change will handle the psr entry exit cases in the panel
bridge atomic callback functions. For example, the panel power
should not turn off if the panel is entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 48 ++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 04e9fb0..a2c6f30 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -113,6 +113,18 @@ static void panel_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_prepare(panel_bridge->panel);
 }
@@ -121,6 +133,18 @@ static void panel_bridge_atomic_enable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_enable(panel_bridge->panel);
 }
@@ -129,6 +153,18 @@ static void panel_bridge_atomic_disable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_disable(panel_bridge->panel);
 }
@@ -137,6 +173,18 @@ static void panel_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_unprepare(panel_bridge->panel);
 }
-- 
2.7.4



[Freedreno] [PATCH v14 05/14] drm/msm/disp/dpu: get timing engine status from intf status register

2023-03-02 Thread Vinod Polimera
Recommended way of reading the interface timing gen status is via
status register. Timing gen status register will give a reliable status
of the interface especially during ON/OFF transitions. This support was
added from DPU version 5.0.0.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  3 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 12 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  8 +++-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index cf053e8..85b29d6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -78,7 +78,8 @@
 
 #define INTF_SDM845_MASK (0)
 
-#define INTF_SC7180_MASK BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE)
+#define INTF_SC7180_MASK \
+   (BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE) | 
BIT(DPU_INTF_STATUS_SUPPORTED))
 
 #define INTF_SC7280_MASK INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN)
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index ddab9ca..08cd1a1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -213,17 +213,19 @@ enum {
 
 /**
  * INTF sub-blocks
- * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
- *  pixel data arrives to this INTF
- * @DPU_INTF_TE INTF block has TE configuration support
- * @DPU_DATA_HCTL_ENAllows data to be transferred at different rate
-than video timing
+ * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
+ *  pixel data arrives to this INTF
+ * @DPU_INTF_TE INTF block has TE configuration support
+ * @DPU_DATA_HCTL_ENAllows data to be transferred at different 
rate
+ *  than video timing
+ * @DPU_INTF_STATUS_SUPPORTED   INTF block has INTF_STATUS register
  * @DPU_INTF_MAX
  */
 enum {
DPU_INTF_INPUT_CTRL = 0x1,
DPU_INTF_TE,
DPU_DATA_HCTL_EN,
+   DPU_INTF_STATUS_SUPPORTED,
DPU_INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..84ee2ef 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -62,6 +62,7 @@
 #define   INTF_LINE_COUNT   0x0B0
 
 #define   INTF_MUX  0x25C
+#define   INTF_STATUS   0x26C
 
 #define INTF_CFG_ACTIVE_H_EN   BIT(29)
 #define INTF_CFG_ACTIVE_V_EN   BIT(30)
@@ -297,8 +298,13 @@ static void dpu_hw_intf_get_status(
struct intf_status *s)
 {
struct dpu_hw_blk_reg_map *c = &intf->hw;
+   unsigned long cap = intf->cap->features;
+
+   if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+   s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
+   else
+   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 
-   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
if (s->is_en) {
s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
-- 
2.7.4



[Freedreno] [PATCH v14 04/14] drm/msm/disp/dpu: check for crtc enable rather than crtc active to release shared resources

2023-03-02 Thread Vinod Polimera
According to KMS documentation, The driver must not release any shared
resources if active is set to false but enable still true.

Fixes: ccc862b957c6 ("drm/msm/dpu: Fix reservation failures in modeset")
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 758261e..c237003 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -652,7 +652,7 @@ static int dpu_encoder_virt_atomic_check(
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
dpu_rm_release(global_state, drm_enc);
 
-   if (!crtc_state->active_changed || crtc_state->active)
+   if (!crtc_state->active_changed || crtc_state->enable)
ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
drm_enc, crtc_state, topology);
}
-- 
2.7.4



[Freedreno] [PATCH v14 06/14] drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled

2023-03-02 Thread Vinod Polimera
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c| 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 48c4810..0396084 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -523,6 +523,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 {
unsigned long lock_flags;
int ret;
+   struct intf_status intf_status = {0};
 
if (!phys_enc->parent || !phys_enc->parent->dev) {
DPU_ERROR("invalid encoder/device\n");
@@ -567,6 +568,26 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+   phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, 
&intf_status);
+
+   /*
+* Wait for a vsync if timing en status is on after timing engine
+* is disabled.
+*/
+   if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+   spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+   dpu_encoder_phys_inc_pending(phys_enc);
+   spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   if (ret) {
+   atomic_set(&phys_enc->pending_kickoff_cnt, 0);
+   DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+ DRMID(phys_enc->parent),
+ phys_enc->hw_intf->idx - INTF_0, ret);
+   }
+   }
+
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v14 07/14] drm/msm/disp/dpu: reset the datapath after timing engine disable

2023-03-02 Thread Vinod Polimera
Reset the datapath after disabling the timing gen, such that
it can start on a clean slate when the intf is enabled back.
This was a recommended sequence from the DPU HW programming guide.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0396084..3a37429 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -588,6 +588,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   dpu_encoder_helper_phys_cleanup(phys_enc);
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v14 08/14] drm/msm/dp: use atomic callbacks for DP bridge ops

2023-03-02 Thread Vinod Polimera
Use atomic variants for DP bridge callback functions so that
the atomic state can be accessed in the interface drivers.
The atomic state will help the driver find out if the display
is in self refresh state.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 9 ++---
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +++---
 drivers/gpu/drm/msm/dp/dp_drm.h | 9 ++---
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index bde1a7c..985287e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1652,7 +1652,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return 0;
 }
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1707,7 +1708,8 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
mutex_unlock(&dp_display->event_mutex);
 }
 
-void dp_bridge_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1718,7 +1720,8 @@ void dp_bridge_disable(struct drm_bridge *drm_bridge)
dp_ctrl_push_idle(dp_display->ctrl);
 }
 
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 275370f..3252d50 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -94,9 +94,9 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
.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,
-   .enable   = dp_bridge_enable,
-   .disable  = dp_bridge_disable,
-   .post_disable = dp_bridge_post_disable,
+   .atomic_enable  = dp_bridge_atomic_enable,
+   .atomic_disable = dp_bridge_atomic_disable,
+   .atomic_post_disable= dp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
.mode_valid   = dp_bridge_mode_valid,
.get_modes= dp_bridge_get_modes,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 250f7c6..afe79b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -23,9 +23,12 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device 
*dev,
struct drm_encoder *encoder);
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge);
-void dp_bridge_disable(struct drm_bridge *drm_bridge);
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state);
 enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
  const struct drm_display_info *info,
  const struct drm_display_mode *mode);
-- 
2.7.4



[Freedreno] [PATCH v14 10/14] drm/msm/dp: use the eDP bridge ops to validate eDP modes

2023-03-02 Thread Vinod Polimera
The eDP and DP interfaces shared the bridge operations and
the eDP specific changes were implemented under is_edp check.
To add psr support for eDP, we started using a new set of eDP
bridge ops. We are moving the eDP specific code in the
dp_bridge_mode_valid function to a new eDP function,
edp_bridge_mode_valid under the eDP bridge ops.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  8 
 drivers/gpu/drm/msm/dp/dp_drm.c | 34 +-
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 86ed80c..ffb21a6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -996,14 +996,6 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
return -EINVAL;
}
 
-   /*
-* The eDP controller currently does not have a reliable way of
-* enabling panel power to read sink capabilities. So, we rely
-* on the panel driver to populate only supported modes for now.
-*/
-   if (dp->is_edp)
-   return MODE_OK;
-
if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
return MODE_CLOCK_HIGH;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 3b38bd9..029e08c 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -226,12 +226,44 @@ static void edp_bridge_atomic_post_disable(struct 
drm_bridge *drm_bridge,
dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state);
 }
 
+/**
+ * edp_bridge_mode_valid - callback to determine if specified mode is valid
+ * @bridge: Pointer to drm bridge structure
+ * @info: display info
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+   struct msm_dp *dp;
+   int mode_pclk_khz = mode->clock;
+
+   dp = to_dp_bridge(bridge)->dp_display;
+
+   if (!dp || !mode_pclk_khz || !dp->connector) {
+   DRM_ERROR("invalid params\n");
+   return -EINVAL;
+   }
+
+   if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+   return MODE_CLOCK_HIGH;
+
+   /*
+* The eDP controller currently does not have a reliable way of
+* enabling panel power to read sink capabilities. So, we rely
+* on the panel driver to populate only supported modes for now.
+*/
+   return MODE_OK;
+}
+
 static const struct drm_bridge_funcs edp_bridge_ops = {
.atomic_enable = edp_bridge_atomic_enable,
.atomic_disable = edp_bridge_atomic_disable,
.atomic_post_disable = edp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
-   .mode_valid = dp_bridge_mode_valid,
+   .mode_valid = edp_bridge_mode_valid,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-- 
2.7.4



[Freedreno] [PATCH v14 09/14] drm/msm/dp: Add basic PSR support for eDP

2023-03-02 Thread Vinod Polimera
Add support for basic panel self refresh (PSR) feature for eDP.
Add a new interface to set PSR state in the sink from DPU.
Program the eDP controller to issue PSR enter and exit SDP to
the sink.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c |  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h |   4 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|   3 +
 drivers/gpu/drm/msm/dp/dp_display.c |  19 ++
 drivers/gpu/drm/msm/dp/dp_display.h |   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c | 133 +++-
 drivers/gpu/drm/msm/dp/dp_link.c|  36 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  22 ++
 drivers/gpu/drm/msm/dp/dp_panel.h   |   6 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |  27 
 11 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 676279d..c12a5d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -47,6 +47,14 @@
 #define DP_INTERRUPT_STATUS2_MASK \
(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
 
+#define DP_INTERRUPT_STATUS4 \
+   (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \
+   PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT)
+
+#define DP_INTERRUPT_MASK4 \
+   (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
+   PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
+
 struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -359,6 +367,23 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog 
*dp_catalog)
ln_mapping);
 }
 
+void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog,
+   bool enable)
+{
+   u32 val;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   if (enable)
+   val |= DP_MAINLINK_CTRL_ENABLE;
+   else
+   val &= ~DP_MAINLINK_CTRL_ENABLE;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val);
+}
+
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
bool enable)
 {
@@ -610,6 +635,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog 
*dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
 }
 
+static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog)
+{
+   /* trigger sdp */
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0);
+}
+
+void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 config;
+
+   /* enable PSR1 function */
+   config = dp_read_link(catalog, REG_PSR_CONFIG);
+   config |= PSR1_SUPPORTED;
+   dp_write_link(catalog, REG_PSR_CONFIG, config);
+
+   dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
+   dp_catalog_enable_sdp(catalog);
+}
+
+void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 cmd;
+
+   cmd = dp_read_link(catalog, REG_PSR_CMD);
+
+   cmd &= ~(PSR_ENTER | PSR_EXIT);
+
+   if (enter)
+   cmd |= PSR_ENTER;
+   else
+   cmd |= PSR_EXIT;
+
+   dp_catalog_enable_sdp(catalog);
+   dp_write_link(catalog, REG_PSR_CMD, cmd);
+}
+
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -645,6 +711,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog 
*dp_catalog)
return isr & (mask | ~DP_DP_HPD_INT_MASK);
 }
 
+u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 intr, intr_ack;
+
+   intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4);
+   intr_ack = (intr & DP_INTERRUPT_STATUS4)
+   << DP_INTERRUPT_STATUS_ACK_SHIFT;
+   dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack);
+
+   return intr;
+}
+
 int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1f717f4..2174bb5 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalo

[Freedreno] [PATCH v14 12/14] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2023-03-02 Thread Vinod Polimera
Enable PSR on eDP interface using drm self-refresh librabry.
This patch uses a trigger from self-refresh library to enter/exit
into PSR, when there are no updates from framework.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index f29a339..60e5984 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dpu_kms.h"
 #include "dpu_hw_lm.h"
@@ -1021,6 +1022,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
+   if (old_crtc_state->self_refresh_active)
+   return;
+
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
 
@@ -1577,7 +1581,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
 {
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
-   int i;
+   int i, ret;
 
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1614,6 +1618,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
/* initialize event handling */
spin_lock_init(&dpu_crtc->event_lock);
 
+   ret = drm_self_refresh_helper_init(crtc);
+   if (ret) {
+   DPU_ERROR("Failed to initialize %s with self-refresh helpers 
%d\n",
+   crtc->name, ret);
+   return ERR_PTR(ret);
+   }
+
DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name);
return crtc;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 01b7509..450abb1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -1212,11 +1213,24 @@ static void dpu_encoder_virt_atomic_disable(struct 
drm_encoder *drm_enc,
struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_state = NULL;
int i = 0;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
+   crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
+   if (crtc)
+   old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+   /*
+* The encoder is already disabled if self refresh mode was set earlier,
+* in the old_state for the corresponding crtc.
+*/
+   if (old_state && old_state->self_refresh_active)
+   return;
+
mutex_lock(&dpu_enc->enc_lock);
dpu_enc->enabled = false;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index a683bd9..681dd2e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -491,7 +491,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms 
*kms,
return;
}
 
-   if (!crtc->state->active) {
+   if (!drm_atomic_crtc_effectively_active(crtc->state)) {
DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);
return;
}
-- 
2.7.4



[Freedreno] [PATCH v14 11/14] drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder functions

2023-03-02 Thread Vinod Polimera
Use atomic variants for encoder callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index c237003..01b7509 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1171,7 +1171,8 @@ void dpu_encoder_virt_runtime_resume(struct drm_encoder 
*drm_enc)
mutex_unlock(&dpu_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
@@ -1207,7 +1208,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
mutex_unlock(&dpu_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int i = 0;
@@ -2388,8 +2390,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
-   .disable = dpu_encoder_virt_disable,
-   .enable = dpu_encoder_virt_enable,
+   .atomic_disable = dpu_encoder_virt_atomic_disable,
+   .atomic_enable = dpu_encoder_virt_atomic_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
 };
 
-- 
2.7.4



[Freedreno] [PATCH v14 13/14] drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable during self refresh

2023-03-02 Thread Vinod Polimera
Populate the enocder software structure to reflect the updated
crtc appropriately during crtc enable/disable for a new commit
while taking care of the self refresh transitions when crtc
disable is triggered from the drm self refresh library.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 29 +
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 60e5984..b1ec0c3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1022,8 +1022,17 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
-   if (old_crtc_state->self_refresh_active)
+   /* If disable is triggered while in self refresh mode,
+* reset the encoder software state so that in enable
+* it won't trigger a warn while assigning crtc.
+*/
+   if (old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev,
+   old_crtc_state->encoder_mask) {
+   dpu_encoder_assign_crtc(encoder, NULL);
+   }
return;
+   }
 
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
@@ -1036,7 +1045,14 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 */
if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
release_bandwidth = true;
-   dpu_encoder_assign_crtc(encoder, NULL);
+
+   /*
+* If disable is triggered during psr active(e.g: screen dim in 
PSR),
+* we will need encoder->crtc connection to process the device 
sleep &
+* preserve it during psr sequence.
+*/
+   if (!crtc->state->self_refresh_active)
+   dpu_encoder_assign_crtc(encoder, NULL);
}
 
/* wait for frame_event_done completion */
@@ -1084,6 +1100,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct drm_encoder *encoder;
bool request_bandwidth = false;
+   struct drm_crtc_state *old_crtc_state;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 
pm_runtime_get_sync(crtc->dev->dev);
 
@@ -1106,8 +1125,10 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
dpu_crtc->enabled = true;
 
-   drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
-   dpu_encoder_assign_crtc(encoder, crtc);
+   if (!old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev, 
crtc->state->encoder_mask)
+   dpu_encoder_assign_crtc(encoder, crtc);
+   }
 
/* Enable/restore vblank irq handling */
drm_crtc_vblank_on(crtc);
-- 
2.7.4



[Freedreno] [PATCH v14 14/14] drm/msm/dp: set self refresh aware based on PSR support

2023-03-02 Thread Vinod Polimera
For the PSR to kick in, self_refresh_aware has to be set.
Initialize it based on the PSR support for the eDP interface.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/dp/dp_drm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 029e08c..785d766 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -117,6 +117,8 @@ static int edp_bridge_atomic_check(struct drm_bridge 
*drm_bridge,
if (WARN_ON(!conn_state))
return -ENODEV;
 
+   conn_state->self_refresh_aware = dp->psr_supported;
+
if (!conn_state->crtc || !crtc_state)
return 0;
 
-- 
2.7.4



Re: [Freedreno] [PATCH v13 00/13] Add PSR support for eDP

2023-03-02 Thread Vinod Polimera


> -Original Message-
> From: Doug Anderson 
> Sent: Thursday, March 2, 2023 2:02 AM
> To: Vinod Polimera (QUIC) 
> Cc: dri-de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org; linux-
> ker...@vger.kernel.org; robdcl...@gmail.com; swb...@chromium.org;
> Kalyan Thota (QUIC) ;
> dmitry.barysh...@linaro.org; Kuogee Hsieh (QUIC)
> ; Vishnuvardhan Prodduturi (QUIC)
> ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> ; Sankeerth Billakanti (QUIC)
> 
> Subject: Re: [PATCH v13 00/13] Add PSR support for eDP
> 
> Hi,
> 
> On Wed, Mar 1, 2023 at 11:06 AM Doug Anderson
>  wrote:
> >
> > Hi,
> >
> > On Sun, Feb 12, 2023 at 8:29 AM Vinod Polimera
> >  wrote:
> > >
> > > Changes in v2:
> > >   - Use dp bridge to set psr entry/exit instead of dpu_enocder.
> > >   - Don't modify whitespaces.
> > >   - Set self refresh aware from atomic_check.
> > >   - Set self refresh aware only if psr is supported.
> > >   - Provide a stub for msm_dp_display_set_psr.
> > >   - Move dp functions to bridge code.
> > >
> > > Changes in v3:
> > >   - Change callback names to reflect atomic interfaces.
> > >   - Move bridge callback change to separate patch as suggested by Dmitry.
> > >   - Remove psr function declaration from msm_drv.h.
> > >   - Set self_refresh_aware flag only if psr is supported.
> > >   - Modify the variable names to simpler form.
> > >   - Define bit fields for PSR settings.
> > >   - Add comments explaining the steps to enter/exit psr.
> > >   - Change DRM_INFO to drm_dbg_db.
> > >
> > > Changes in v4:
> > >   - Move the get crtc functions to drm_atomic.
> > >   - Add atomic functions for DP bridge too.
> > >   - Add ternary operator to choose eDP or DP ops.
> > >   - Return true/false instead of 1/0.
> > >   - mode_valid missing in the eDP bridge ops.
> > >   - Move the functions to get crtc into drm_atomic.c.
> > >   - Fix compilation issues.
> > >   - Remove dpu_assign_crtc and get crtc from drm_enc instead of
> dpu_enc.
> > >   - Check for crtc state enable while reserving resources.
> > >
> > > Changes in v5:
> > >   - Move the mode_valid changes into a different patch.
> > >   - Complete psr_op_comp only when isr is set.
> > >   - Move the DP atomic callback changes to a different patch.
> > >   - Get crtc from drm connector state crtc.
> > >   - Move to separate patch for check for crtc state enable while
> > > reserving resources.
> > >
> > > Changes in v6:
> > >   - Remove crtc from dpu_encoder_virt struct.
> > >   - fix crtc check during vblank toggle crtc.
> > >   - Misc changes.
> > >
> > > Changes in v7:
> > >   - Add fix for underrun issue on kasan build.
> > >
> > > Changes in v8:
> > >   - Drop the enc spinlock as it won't serve any purpose in
> > > protetcing conn state.(Dmitry/Doug)
> > >
> > > Changes in v9:
> > >   - Update commit message and fix alignment using spaces.(Marijn)
> > >   - Misc changes.(Marijn)
> > >
> > > Changes in v10:
> > >   - Get crtc cached in dpu_enc during obj init.(Dmitry)
> > >
> > > Changes in v11:
> > >   - Remove crtc cached in dpu_enc during obj init.
> > >   - Update dpu_enc crtc state on crtc enable/disable during self refresh.
> > >
> > > Changes in v12:
> > >   - Update sc7180 intf mask to get intf timing gen status
> > > based on DPU_INTF_STATUS_SUPPORTED bit.(Dmitry)
> > >   - Remove "clear active interface in the datapath cleanup" change
> > > as it is already included.
> > >
> > > Changes in v13:
> > >   - Move core changes to top of the series.(Dmitry)
> > >   - Drop self refresh aware disable change after psr entry.(Dmitry)
> > >
> > > Vinod Polimera (13):
> > >   drm: add helper functions to retrieve old and new crtc
> > >   drm/bridge: use atomic enable/disable callbacks for panel bridge
> > >   drm/bridge: add psr support for panel bridge callbacks
> > >   drm/msm/disp/dpu: check for crtc enable rather than crtc active to
> > > release shared resources
> > >   drm/msm/disp/dpu: get timing engine status from intf status register
> > >   drm/msm/disp/dpu: wait for extra vsync till timing engine status is
> > > disabled
> > >   drm/msm/disp/dpu: reset the datapath after timing engine disable
> > >   drm/msm/dp: use atomic callbacks for DP bridge ops
> > >   drm/msm/dp: Add basic PSR support for eDP
> > >   drm/msm/dp: use the eDP bridge ops to validate eDP modes
> > >   drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder
> > > functions
> > >   drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver
> > >   drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable
> > > during self refresh
> >
> > I'm curious what the plan is for landing this series. I could land the
> > first two in drm-misc if you want, but I'm a lowly committer and so I
> > couldn't make an immutable branch for you nor can I officially Ack the
> > changes to land in your branch. That means you'd be blocked for an
> > extra version. Do you already have a plan? If

Re: [Freedreno] [PATCH v14 14/14] drm/msm/dp: set self refresh aware based on PSR support

2023-03-02 Thread Dmitry Baryshkov

On 02/03/2023 18:33, Vinod Polimera wrote:

For the PSR to kick in, self_refresh_aware has to be set.
Initialize it based on the PSR support for the eDP interface.

Signed-off-by: Vinod Polimera 


Reviewed-by: Dmitry Baryshkov 

--
With best wishes
Dmitry



Re: [Freedreno] [RFT PATCH v2 1/3] drm/bridge: tc358762: Set pre_enable_prev_first

2023-03-02 Thread Doug Anderson
Hi,

On Mon, Feb 27, 2023 at 5:24 PM Dmitry Baryshkov
 wrote:
>
> On 28/02/2023 02:26, Doug Anderson wrote:
> > Hi,
> >
> > On Wed, Feb 1, 2023 at 1:51 AM Dave Stevenson
> >  wrote:
> >>
> >> On Tue, 31 Jan 2023 at 22:22, Douglas Anderson  
> >> wrote:
> >>>
> >>> Set the "pre_enable_prev_first" as provided by commit 4fb912e5e190
> >>> ("drm/bridge: Introduce pre_enable_prev_first to alter bridge init
> >>> order"). This should allow us to revert commit ec7981e6c614
> >>> ("drm/msm/dsi: don't powerup at modeset time for parade-ps8640") and
> >>> commit 7d8e9a90509f ("drm/msm/dsi: move DSI host powerup to modeset
> >>> time").
> >>
> >> I see no reference in the TC358762 datasheet to requiring the DSI
> >> interface to be in any particular state.
> >> However, setting this flag does mean that the DSI host doesn't need to
> >> power up and down for each host_transfer request from
> >> tc358762_pre_enable/tc358762_init, so on that basis I'm good with it.
> >>
> >> Reviewed-by: Dave Stevenson 
> >>
> >>> Cc: Dave Stevenson 
> >>> Cc: Dmitry Baryshkov 
> >>> Cc: Abhinav Kumar 
> >>> Signed-off-by: Douglas Anderson 
> >>> ---
> >>>
> >>> (no changes since v1)
> >>>
> >>>   drivers/gpu/drm/bridge/tc358762.c | 1 +
> >>>   1 file changed, 1 insertion(+)
> >>>
> >>> diff --git a/drivers/gpu/drm/bridge/tc358762.c 
> >>> b/drivers/gpu/drm/bridge/tc358762.c
> >>> index 0b6a28436885..77f7f7f54757 100644
> >>> --- a/drivers/gpu/drm/bridge/tc358762.c
> >>> +++ b/drivers/gpu/drm/bridge/tc358762.c
> >>> @@ -229,6 +229,7 @@ static int tc358762_probe(struct mipi_dsi_device *dsi)
> >>>  ctx->bridge.funcs = &tc358762_bridge_funcs;
> >>>  ctx->bridge.type = DRM_MODE_CONNECTOR_DPI;
> >>>  ctx->bridge.of_node = dev->of_node;
> >>> +   ctx->bridge.pre_enable_prev_first = true;
> >>>
> >>>  drm_bridge_add(&ctx->bridge);
> >
> > Abhinav asked what the plan was for landing this [1]. Since this isn't
> > urgent, I guess the plan is to land patch #1 in drm-misc-next. Then we
> > sit and wait until it percolates into mainline and, once it does, then
> > patch #2 and #3 can land.
> >
> > Since I have Dave's review I can commit this to drm-misc-next myself.
> > My plan will be to wait until Thursday or Friday of this week (to give
> > people a bit of time to object) and then land patch #1. Then I'll
> > snooze things for a while and poke Abhinav and Dmitry to land patch #2
> > / #3 when I notice it in mainline. If, at any point, someone comes out
> > of the woodwork and yells that this is breaking them then, worst case,
> > we can revert.
>
> This plan sounds good to me.

Pushed to drm-misc-next:

55cac10739d5 drm/bridge: tc358762: Set pre_enable_prev_first

If my math is right then I'd expect that to get into mainline for
6.4-rc1. I guess that means it'll be in Linus's tree mid-May. I'll
schedule a reminder to suggest landing at patches #2 and #3 again in
late May.

-Doug


Re: [Freedreno] [RFT PATCH v2 1/3] drm/bridge: tc358762: Set pre_enable_prev_first

2023-03-02 Thread Dmitry Baryshkov
On Thu, 2 Mar 2023 at 19:26, Doug Anderson  wrote:
>
> Hi,
>
> On Mon, Feb 27, 2023 at 5:24 PM Dmitry Baryshkov
>  wrote:
> >
> > On 28/02/2023 02:26, Doug Anderson wrote:
> > > Hi,
> > >
> > > On Wed, Feb 1, 2023 at 1:51 AM Dave Stevenson
> > >  wrote:
> > >>
> > >> On Tue, 31 Jan 2023 at 22:22, Douglas Anderson  
> > >> wrote:
> > >>>
> > >>> Set the "pre_enable_prev_first" as provided by commit 4fb912e5e190
> > >>> ("drm/bridge: Introduce pre_enable_prev_first to alter bridge init
> > >>> order"). This should allow us to revert commit ec7981e6c614
> > >>> ("drm/msm/dsi: don't powerup at modeset time for parade-ps8640") and
> > >>> commit 7d8e9a90509f ("drm/msm/dsi: move DSI host powerup to modeset
> > >>> time").
> > >>
> > >> I see no reference in the TC358762 datasheet to requiring the DSI
> > >> interface to be in any particular state.
> > >> However, setting this flag does mean that the DSI host doesn't need to
> > >> power up and down for each host_transfer request from
> > >> tc358762_pre_enable/tc358762_init, so on that basis I'm good with it.
> > >>
> > >> Reviewed-by: Dave Stevenson 
> > >>
> > >>> Cc: Dave Stevenson 
> > >>> Cc: Dmitry Baryshkov 
> > >>> Cc: Abhinav Kumar 
> > >>> Signed-off-by: Douglas Anderson 
> > >>> ---
> > >>>
> > >>> (no changes since v1)
> > >>>
> > >>>   drivers/gpu/drm/bridge/tc358762.c | 1 +
> > >>>   1 file changed, 1 insertion(+)
> > >>>
> > >>> diff --git a/drivers/gpu/drm/bridge/tc358762.c 
> > >>> b/drivers/gpu/drm/bridge/tc358762.c
> > >>> index 0b6a28436885..77f7f7f54757 100644
> > >>> --- a/drivers/gpu/drm/bridge/tc358762.c
> > >>> +++ b/drivers/gpu/drm/bridge/tc358762.c
> > >>> @@ -229,6 +229,7 @@ static int tc358762_probe(struct mipi_dsi_device 
> > >>> *dsi)
> > >>>  ctx->bridge.funcs = &tc358762_bridge_funcs;
> > >>>  ctx->bridge.type = DRM_MODE_CONNECTOR_DPI;
> > >>>  ctx->bridge.of_node = dev->of_node;
> > >>> +   ctx->bridge.pre_enable_prev_first = true;
> > >>>
> > >>>  drm_bridge_add(&ctx->bridge);
> > >
> > > Abhinav asked what the plan was for landing this [1]. Since this isn't
> > > urgent, I guess the plan is to land patch #1 in drm-misc-next. Then we
> > > sit and wait until it percolates into mainline and, once it does, then
> > > patch #2 and #3 can land.
> > >
> > > Since I have Dave's review I can commit this to drm-misc-next myself.
> > > My plan will be to wait until Thursday or Friday of this week (to give
> > > people a bit of time to object) and then land patch #1. Then I'll
> > > snooze things for a while and poke Abhinav and Dmitry to land patch #2
> > > / #3 when I notice it in mainline. If, at any point, someone comes out
> > > of the woodwork and yells that this is breaking them then, worst case,
> > > we can revert.
> >
> > This plan sounds good to me.
>
> Pushed to drm-misc-next:
>
> 55cac10739d5 drm/bridge: tc358762: Set pre_enable_prev_first
>
> If my math is right then I'd expect that to get into mainline for
> 6.4-rc1. I guess that means it'll be in Linus's tree mid-May. I'll
> schedule a reminder to suggest landing at patches #2 and #3 again in
> late May.

It might be earlier, if msm-next merges drm-misc earlier (e.g. for the
PSR patches).

-- 
With best wishes
Dmitry


Re: [Freedreno] [PATCH v3] drm/msm/dp: check core_initialized flag at both host_init() and host_deinit()

2023-03-02 Thread Kuogee Hsieh



On 3/1/2023 1:15 PM, Dmitry Baryshkov wrote:

On 01/03/2023 18:57, Kuogee Hsieh wrote:


On 2/28/2023 6:16 PM, Dmitry Baryshkov wrote:
On Wed, 1 Mar 2023 at 02:17, Kuogee Hsieh  
wrote:

There is a reboot/suspend test case where system suspend is forced
during system booting up. Since dp_display_host_init() of external
DP is executed at hpd thread context, this test case may created a
scenario that dp_display_host_deinit() from pm_suspend() run before
dp_display_host_init() if hpd thread has no chance to run during
booting up while suspend request command was issued. At this scenario
system will crash at aux register access at dp_display_host_deinit()
since aux clock had not yet been enabled by dp_display_host_init().
Therefore we have to ensure aux clock enabled by checking
core_initialized flag before access aux registers at pm_suspend.

Can a call to dp_display_host_init() be moved from
dp_display_config_hpd() to dp_display_bind()?


yes,  Sankeerth's  "drm/msm/dp: enable pm_runtime support for dp 
driver" patch is doing that which is under review.


https://patchwork.freedesktop.org/patch/523879/?series=114297&rev=1


No, he is doing another thing. He is moving these calls to pm_runtime 
callbacks, not to the dp_display_bind().



Related question: what is the primary reason for having
EV_HPD_INIT_SETUP and calling dp_display_config_hpd() via the event
thread? Does DP driver really depend on DPU irqs being installed? As
far as I understand, DP device uses MDSS interrupts and those IRQs are
available and working at the time of dp_display_probe() /
dp_display_bind().


HDP gpio pin has to run through DP aux module 100ms denouncing logic 
and have its mask bits.


Therefore DP irq has to be enabled to receive DP isr with mask bits set.


So... DP irq is enabled by the MDSS, not by the DPU. Again, why does 
DP driver depend on DPU irqs being installed?


sorry, previously i mis understand your question -- why does DP driver 
depend on DPU irqs being installed?


now, I think you are asking why  dpu_irq_postinstall() ==> 
msm_dp_irq_postinstall() ==> event_thread ==> dp_display_config_hdp() 
==> enable_irq(dp->irq)


With the below test i had run, i think the reason is to make sure 
dp->irq be requested before enable it.


I just run the execution timing order test and collect execution order 
as descending order at below,


1) dp_display_probe() -- start

2) dp_display_bind()

3) msm_dp_modeset_init()  ==> dp_display_request_irq() ==> 
dp_display_get_next_bridge()


4) dpu_irq_postinstall() ==> msm_dp_irq_postinstall() ==> 
enable_irq(dp->irq)


5) dp_display_probe() -- end

dp->irq is request at msm_dp_modeset_init() and enabled after.

That bring up the issue to move DP's dp_display_host_init() executed at 
dp_display_bind().


Since eDP have dp_dispaly_host_init() executed at 
dp_display_get_next_bridge() which executed after dp_display_bind().


If moved DP's dp_display_host_init() to dp_dispaly_bind() which means DP 
will be ready to receive HPD irq before eDP ready.


This may create some uncertainties at execution flow and complicate 
things up.






Similar mechanism is used for mdp, dsi, etc.


And none of them uses irq_postinstall callback.





Changes in v2:
-- at commit text, dp_display_host_init() instead of host_init()
-- at commit text, dp_display_host_deinit() instead of host_deinit()

Changes in v3:
-- re arrange to avoid commit text line over 75 chars

Fixes: 989ebe7bc446 ("drm/msm/dp: do not initialize phy until 
plugin interrupt received")

Signed-off-by: Kuogee Hsieh 
Reviewed-by: Stephen Boyd 
---
  drivers/gpu/drm/msm/dp/dp_display.c | 20 
  1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c

index bde1a7c..1850738 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -460,10 +460,12 @@ static void dp_display_host_init(struct 
dp_display_private *dp)

 dp->dp_display.connector_type, dp->core_initialized,
 dp->phy_initialized);

-   dp_power_init(dp->power, false);
-   dp_ctrl_reset_irq_ctrl(dp->ctrl, true);
-   dp_aux_init(dp->aux);
-   dp->core_initialized = true;
+   if (!dp->core_initialized) {
+   dp_power_init(dp->power, false);
+   dp_ctrl_reset_irq_ctrl(dp->ctrl, true);
+   dp_aux_init(dp->aux);
+   dp->core_initialized = true;
+   }
  }

  static void dp_display_host_deinit(struct dp_display_private *dp)
@@ -472,10 +474,12 @@ static void dp_display_host_deinit(struct 
dp_display_private *dp)

 dp->dp_display.connector_type, dp->core_initialized,
 dp->phy_initialized);

-   dp_ctrl_reset_irq_ctrl(dp->ctrl, false);
-   dp_aux_deinit(dp->aux);
-   dp_power_deinit(dp->power);
-   dp->core_initialized = false;
+   if (dp->core_initialized) {
+   dp_ctrl_reset_irq_ctr

Re: [Freedreno] [PATCH v3] drm/msm/dp: check core_initialized flag at both host_init() and host_deinit()

2023-03-02 Thread Dmitry Baryshkov
On Thu, 2 Mar 2023 at 20:41, Kuogee Hsieh  wrote:
>
>
> On 3/1/2023 1:15 PM, Dmitry Baryshkov wrote:
> > On 01/03/2023 18:57, Kuogee Hsieh wrote:
> >>
> >> On 2/28/2023 6:16 PM, Dmitry Baryshkov wrote:
> >>> On Wed, 1 Mar 2023 at 02:17, Kuogee Hsieh 
> >>> wrote:
>  There is a reboot/suspend test case where system suspend is forced
>  during system booting up. Since dp_display_host_init() of external
>  DP is executed at hpd thread context, this test case may created a
>  scenario that dp_display_host_deinit() from pm_suspend() run before
>  dp_display_host_init() if hpd thread has no chance to run during
>  booting up while suspend request command was issued. At this scenario
>  system will crash at aux register access at dp_display_host_deinit()
>  since aux clock had not yet been enabled by dp_display_host_init().
>  Therefore we have to ensure aux clock enabled by checking
>  core_initialized flag before access aux registers at pm_suspend.
> >>> Can a call to dp_display_host_init() be moved from
> >>> dp_display_config_hpd() to dp_display_bind()?
> >>
> >> yes,  Sankeerth's  "drm/msm/dp: enable pm_runtime support for dp
> >> driver" patch is doing that which is under review.
> >>
> >> https://patchwork.freedesktop.org/patch/523879/?series=114297&rev=1
> >
> > No, he is doing another thing. He is moving these calls to pm_runtime
> > callbacks, not to the dp_display_bind().
> >
> >>> Related question: what is the primary reason for having
> >>> EV_HPD_INIT_SETUP and calling dp_display_config_hpd() via the event
> >>> thread? Does DP driver really depend on DPU irqs being installed? As
> >>> far as I understand, DP device uses MDSS interrupts and those IRQs are
> >>> available and working at the time of dp_display_probe() /
> >>> dp_display_bind().
> >>
> >> HDP gpio pin has to run through DP aux module 100ms denouncing logic
> >> and have its mask bits.
> >>
> >> Therefore DP irq has to be enabled to receive DP isr with mask bits set.
> >
> > So... DP irq is enabled by the MDSS, not by the DPU. Again, why does
> > DP driver depend on DPU irqs being installed?
>
> sorry, previously i mis understand your question -- why does DP driver
> depend on DPU irqs being installed?
>
> now, I think you are asking why  dpu_irq_postinstall() ==>
> msm_dp_irq_postinstall() ==> event_thread ==> dp_display_config_hdp()
> ==> enable_irq(dp->irq)
>
> With the below test i had run, i think the reason is to make sure
> dp->irq be requested before enable it.
>
> I just run the execution timing order test and collect execution order
> as descending order at below,
>
> 1) dp_display_probe() -- start
>
> 2) dp_display_bind()
>
> 3) msm_dp_modeset_init()  ==> dp_display_request_irq() ==>
> dp_display_get_next_bridge()
>
> 4) dpu_irq_postinstall() ==> msm_dp_irq_postinstall() ==>
> enable_irq(dp->irq)
>
> 5) dp_display_probe() -- end
>
> dp->irq is request at msm_dp_modeset_init() and enabled after.

Should be moved to probe.

>
> That bring up the issue to move DP's dp_display_host_init() executed at
> dp_display_bind().
>
> Since eDP have dp_dispaly_host_init() executed at
> dp_display_get_next_bridge() which executed after dp_display_bind().
>
> If moved DP's dp_display_host_init() to dp_dispaly_bind() which means DP
> will be ready to receive HPD irq before eDP ready.

And the AUX bus population should also be moved to probe(), which
means we should call dp_display_host_init() from probe() too.
Having aux_bus_populate in probe would allow moving component_add() to
the done_probing() callback, making probe/defer case more robust

> This may create some uncertainties at execution flow and complicate
> things up.

Hopefully the changes suggested above will make it simpler.

-- 
With best wishes
Dmitry


Re: [Freedreno] [PATCH v4 3/4] drm/msm/dpu: Remove empty prepare_commit() function

2023-03-02 Thread Jessica Zhang




On 3/1/2023 2:13 AM, Marijn Suijten wrote:

On 2023-03-01 11:08:16, Marijn Suijten wrote:

On 2023-02-21 10:42:55, Jessica Zhang wrote:

Now that the TE setup has been moved to prepare_for_kickoff(),  we have
not prepare_commit() callbacks left. This makes dpu_encoder_prepare_commit()


s/not/no


do nothing. Remove prepare_commit() from DPU driver.


And again, this:


Changes in V3:
- Reworded commit message to be more clear
- Corrected spelling mistake in commit message

Changes in V4:
- Reworded commit message for clarity


... should go below the cut.


Signed-off-by: Jessica Zhang 


With the above two issues fixed:

Reviewed-by: Marijn Suijten 


---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 19 ---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  7 ---
  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 21 -
  3 files changed, 47 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index dcceed91aed8..35e120b5ef53 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2090,25 +2090,6 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
ctl->ops.clear_pending_flush(ctl);
  }
  
-void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc)

-{
-   struct dpu_encoder_virt *dpu_enc;
-   struct dpu_encoder_phys *phys;
-   int i;
-
-   if (!drm_enc) {
-   DPU_ERROR("invalid encoder\n");
-   return;
-   }
-   dpu_enc = to_dpu_encoder_virt(drm_enc);
-
-   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
-   phys = dpu_enc->phys_encs[i];
-   if (phys->ops.prepare_commit)
-   phys->ops.prepare_commit(phys);


In hindsight, Dmitry asked in v2 to remove prepare_commit from
dpu_encoder_phys_ops (and its documentation comment) in
dpu_encoder_phys.h, but that has not happened yet.  Can we do that in a
v5?


Ah, forgot to include that change. Will add it in the v5. Thanks for 
catching it!


- Jessica Zhang



- Marijn


-   }
-}
-
  #ifdef CONFIG_DEBUG_FS
  static int _dpu_encoder_status_show(struct seq_file *s, void *data)
  {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 9e7236ef34e6..2c9ef8d1b877 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -146,13 +146,6 @@ struct drm_encoder *dpu_encoder_init(
  int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc,
struct msm_display_info *disp_info);
  
-/**

- * dpu_encoder_prepare_commit - prepare encoder at the very beginning of an
- * atomic commit, before any registers are written
- * @drm_enc:Pointer to previously created drm encoder structure
- */
-void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc);
-
  /**
   * dpu_encoder_set_idle_timeout - set the idle timeout for video
   *and command mode encoders.
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 165958d47ec6..6f7ddbf0d9b7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -425,26 +425,6 @@ static ktime_t dpu_kms_vsync_time(struct msm_kms *kms, 
struct drm_crtc *crtc)
return ktime_get();
  }
  
-static void dpu_kms_prepare_commit(struct msm_kms *kms,

-   struct drm_atomic_state *state)
-{
-   struct drm_crtc *crtc;
-   struct drm_crtc_state *crtc_state;
-   struct drm_encoder *encoder;
-   int i;
-
-   if (!kms)
-   return;
-
-   /* Call prepare_commit for all affected encoders */
-   for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
-   drm_for_each_encoder_mask(encoder, crtc->dev,
- crtc_state->encoder_mask) {
-   dpu_encoder_prepare_commit(encoder);
-   }
-   }
-}
-
  static void dpu_kms_flush_commit(struct msm_kms *kms, unsigned crtc_mask)
  {
struct dpu_kms *dpu_kms = to_dpu_kms(kms);
@@ -949,7 +929,6 @@ static const struct msm_kms_funcs kms_funcs = {
.enable_commit   = dpu_kms_enable_commit,
.disable_commit  = dpu_kms_disable_commit,
.vsync_time  = dpu_kms_vsync_time,
-   .prepare_commit  = dpu_kms_prepare_commit,
.flush_commit= dpu_kms_flush_commit,
.wait_flush  = dpu_kms_wait_flush,
.complete_commit = dpu_kms_complete_commit,
--
2.39.2



Re: [Freedreno] [PATCH] drm/msm: Initialize mode_config earlier

2023-03-02 Thread Bjorn Andersson
On Wed, Mar 01, 2023 at 02:58:50PM +0100, Johan Hovold wrote:
> On Tue, Jan 24, 2023 at 09:09:02AM +0100, Johan Hovold wrote:
> > On Mon, Jan 23, 2023 at 09:17:49AM -0800, Bjorn Andersson wrote:
> > > On Mon, Jan 23, 2023 at 05:01:45PM +0100, Johan Hovold wrote:
> > > > On Tue, Jan 17, 2023 at 09:04:39AM +0100, Johan Hovold wrote:
> > > > > On Mon, Jan 16, 2023 at 08:51:22PM -0600, Bjorn Andersson wrote:
> > 
> > > > > > Perhaps we have shuffled other things around to avoid this bug?  
> > > > > > Either
> > > > > > way, let's this on hold  until further proof that it's still
> > > > > > reproducible.
> > > > > 
> > > > > As I've mentioned off list, I haven't hit the apparent race I reported
> > > > > here:
> > > > > 
> > > > >   
> > > > > https://lore.kernel.org/all/y1efjh11b5uqz...@hovoldconsulting.com/
> > > > > 
> > > > > since moving to 6.2. I did hit it with both 6.0 and 6.1-rc2, but it
> > > > > could very well be that something has changes that fixes (or hides) 
> > > > > the
> > > > > issue since.
> > > > 
> > > > For unrelated reasons, I tried enabling async probing, and apart from
> > > > apparently causing the panel driver to probe defer indefinitely, I also
> > > > again hit the WARN_ON() I had added to catch this:
> > > > 
> > > > [   13.593235] WARNING: CPU: 0 PID: 125 at 
> > > > drivers/gpu/drm/drm_probe_helper.c:664 
> > > > drm_kms_helper_hotplug_event+0x48/0x7
> > > > 0 [drm_kms_helper]
> > 
> > > > So the bug still appears to be there (and the MSM DRM driver is fragile
> > > > and broken, but we knew that).
> > > > 
> > > 
> > > But the ordering between mode_config.funcs = !NULL and
> > > drm_kms_helper_poll_init() in msm_drm_init() seems pretty clear.
> > > 
> > > And my testing shows that drm_kms_helper_poll_init() is the cause for
> > > getting bridge->hpd_cb != NULL.
> > > 
> > > So the ordering seems legit, unless there's something else causing the
> > > assignment of bridge->hpd_cb to happen earlier in this scenario.
> > 
> > I'm not saying that this patch is correct (indeed it doesn't seem to
> > be), but only that the bug I reported still appears to be present in
> > 6.2.
> 
> So after debugging this issue a third time, I can conclude that it is
> still very much present in 6.2.
> 
> It appears you looked at the linux-next tree when you concluded that
> this patch was not needed. In 6.2 the bridge->hpd_cb callback is set
> before mode_config.funcs is initialised as part of
> kms->funcs->hw_init(kms).
> 
> The hpd DRM changes heading into 6.3 do appear to avoid the NULL-pointer
> dereference by moving the bridge->hpd_cb initialisation to
> drm_kms_helper_poll_init() as you mention above.
> 
> The PMIC GLINK altmode driver still happily forwards notifications
> regardless of the DRM driver state though, which can lead to missed
> hotplug events. It seems you need to implement the
> hpd_enable()/disable() callbacks and either cache or not enable events
> in fw until the DRM driver is ready.
> 

It's not clear to me what the expectation from the DRM framework is on
this point. We register a drm_bridge which is only capable of signaling
HPD events (DRM_BRIDGE_OP_HPD), not querying HPD state (DRM_BRIDGE_OP_DETECT).

Does this imply that any such bridge must ensure that hpd events are
re-delivered once hpd_enable() has been invoked (we can't invoke it from
hpd_enable...)?

Is it reasonable to do this retriggering in the altmode driver? Or is it
the job of the TCPM (it seems reasonable to not send the PAN_EN message
until we get hpd_enable()...)?

Regards,
Bjorn


[Freedreno] [PATCH v9 00/15] dma-fence: Deadline awareness

2023-03-02 Thread Rob Clark
From: Rob Clark 

This series adds a deadline hint to fences, so realtime deadlines
such as vblank can be communicated to the fence signaller for power/
frequency management decisions.

This is partially inspired by a trick i915 does, but implemented
via dma-fence for a couple of reasons:

1) To continue to be able to use the atomic helpers
2) To support cases where display and gpu are different drivers

This iteration adds a dma-fence ioctl to set a deadline (both to
support igt-tests, and compositors which delay decisions about which
client buffer to display), and a sw_sync ioctl to read back the
deadline.  IGT tests utilizing these can be found at:

  https://gitlab.freedesktop.org/robclark/igt-gpu-tools/-/commits/fence-deadline


v1: https://patchwork.freedesktop.org/series/93035/
v2: Move filtering out of later deadlines to fence implementation
to avoid increasing the size of dma_fence
v3: Add support in fence-array and fence-chain; Add some uabi to
support igt tests and userspace compositors.
v4: Rebase, address various comments, and add syncobj deadline
support, and sync_file EPOLLPRI based on experience with perf/
freq issues with clvk compute workloads on i915 (anv)
v5: Clarify that this is a hint as opposed to a more hard deadline
guarantee, switch to using u64 ns values in UABI (still absolute
CLOCK_MONOTONIC values), drop syncobj related cap and driver
feature flag in favor of allowing count_handles==0 for probing
kernel support.
v6: Re-work vblank helper to calculate time of _start_ of vblank,
and work correctly if the last vblank event was more than a
frame ago.  Add (mostly unrelated) drm/msm patch which also
uses the vblank helper.  Use dma_fence_chain_contained().  More
verbose syncobj UABI comments.  Drop DMA_FENCE_FLAG_HAS_DEADLINE_BIT.
v7: Fix kbuild complaints about vblank helper.  Add more docs.
v8: Add patch to surface sync_file UAPI, and more docs updates.
v9: Drop (E)POLLPRI support.. I still like it, but not essential and
it can always be revived later.  Fix doc build warning.

Rob Clark (15):
  dma-buf/dma-fence: Add deadline awareness
  dma-buf/fence-array: Add fence deadline support
  dma-buf/fence-chain: Add fence deadline support
  dma-buf/dma-resv: Add a way to set fence deadline
  dma-buf/sync_file: Surface sync-file uABI
  dma-buf/sync_file: Add SET_DEADLINE ioctl
  dma-buf/sw_sync: Add fence deadline support
  drm/scheduler: Add fence deadline support
  drm/syncobj: Add deadline support for syncobj waits
  drm/vblank: Add helper to get next vblank time
  drm/atomic-helper: Set fence deadline for vblank
  drm/msm: Add deadline based boost support
  drm/msm: Add wait-boost support
  drm/msm/atomic: Switch to vblank_start helper
  drm/i915: Add deadline based boost support

 Documentation/driver-api/dma-buf.rst| 16 -
 drivers/dma-buf/dma-fence-array.c   | 11 
 drivers/dma-buf/dma-fence-chain.c   | 12 
 drivers/dma-buf/dma-fence.c | 60 ++
 drivers/dma-buf/dma-resv.c  | 22 +++
 drivers/dma-buf/sw_sync.c   | 81 +
 drivers/dma-buf/sync_debug.h|  2 +
 drivers/dma-buf/sync_file.c | 19 ++
 drivers/gpu/drm/drm_atomic_helper.c | 36 +++
 drivers/gpu/drm/drm_syncobj.c   | 64 +++
 drivers/gpu/drm/drm_vblank.c| 53 +---
 drivers/gpu/drm/i915/i915_request.c | 20 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 15 -
 drivers/gpu/drm/msm/msm_atomic.c|  8 ++-
 drivers/gpu/drm/msm/msm_drv.c   | 12 ++--
 drivers/gpu/drm/msm/msm_fence.c | 74 ++
 drivers/gpu/drm/msm/msm_fence.h | 20 ++
 drivers/gpu/drm/msm/msm_gem.c   |  5 ++
 drivers/gpu/drm/msm/msm_kms.h   |  8 ---
 drivers/gpu/drm/scheduler/sched_fence.c | 46 ++
 drivers/gpu/drm/scheduler/sched_main.c  |  2 +-
 include/drm/drm_vblank.h|  1 +
 include/drm/gpu_scheduler.h | 17 ++
 include/linux/dma-fence.h   | 22 +++
 include/linux/dma-resv.h|  2 +
 include/uapi/drm/drm.h  | 17 ++
 include/uapi/drm/msm_drm.h  | 14 -
 include/uapi/linux/sync_file.h  | 59 +++---
 28 files changed, 639 insertions(+), 79 deletions(-)

-- 
2.39.1



[Freedreno] [PATCH v9 01/15] dma-buf/dma-fence: Add deadline awareness

2023-03-02 Thread Rob Clark
From: Rob Clark 

Add a way to hint to the fence signaler of an upcoming deadline, such as
vblank, which the fence waiter would prefer not to miss.  This is to aid
the fence signaler in making power management decisions, like boosting
frequency as the deadline approaches and awareness of missing deadlines
so that can be factored in to the frequency scaling.

v2: Drop dma_fence::deadline and related logic to filter duplicate
deadlines, to avoid increasing dma_fence size.  The fence-context
implementation will need similar logic to track deadlines of all
the fences on the same timeline.  [ckoenig]
v3: Clarify locking wrt. set_deadline callback
v4: Clarify in docs comment that this is a hint
v5: Drop DMA_FENCE_FLAG_HAS_DEADLINE_BIT.
v6: More docs
v7: Fix typo, clarify past deadlines

Signed-off-by: Rob Clark 
Reviewed-by: Christian König 
Acked-by: Pekka Paalanen 
Reviewed-by: Bagas Sanjaya 
---
 Documentation/driver-api/dma-buf.rst |  6 +++
 drivers/dma-buf/dma-fence.c  | 59 
 include/linux/dma-fence.h| 22 +++
 3 files changed, 87 insertions(+)

diff --git a/Documentation/driver-api/dma-buf.rst 
b/Documentation/driver-api/dma-buf.rst
index 622b8156d212..183e480d8cea 100644
--- a/Documentation/driver-api/dma-buf.rst
+++ b/Documentation/driver-api/dma-buf.rst
@@ -164,6 +164,12 @@ DMA Fence Signalling Annotations
 .. kernel-doc:: drivers/dma-buf/dma-fence.c
:doc: fence signalling annotation
 
+DMA Fence Deadline Hints
+
+
+.. kernel-doc:: drivers/dma-buf/dma-fence.c
+   :doc: deadline hints
+
 DMA Fences Functions Reference
 ~~
 
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 0de0482cd36e..f177c56269bb 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -912,6 +912,65 @@ dma_fence_wait_any_timeout(struct dma_fence **fences, 
uint32_t count,
 }
 EXPORT_SYMBOL(dma_fence_wait_any_timeout);
 
+/**
+ * DOC: deadline hints
+ *
+ * In an ideal world, it would be possible to pipeline a workload sufficiently
+ * that a utilization based device frequency governor could arrive at a minimum
+ * frequency that meets the requirements of the use-case, in order to minimize
+ * power consumption.  But in the real world there are many workloads which
+ * defy this ideal.  For example, but not limited to:
+ *
+ * * Workloads that ping-pong between device and CPU, with alternating periods
+ *   of CPU waiting for device, and device waiting on CPU.  This can result in
+ *   devfreq and cpufreq seeing idle time in their respective domains and in
+ *   result reduce frequency.
+ *
+ * * Workloads that interact with a periodic time based deadline, such as 
double
+ *   buffered GPU rendering vs vblank sync'd page flipping.  In this scenario,
+ *   missing a vblank deadline results in an *increase* in idle time on the GPU
+ *   (since it has to wait an additional vblank period), sending a signal to
+ *   the GPU's devfreq to reduce frequency, when in fact the opposite is what 
is
+ *   needed.
+ *
+ * To this end, deadline hint(s) can be set on a &dma_fence via 
&dma_fence_set_deadline.
+ * The deadline hint provides a way for the waiting driver, or userspace, to
+ * convey an appropriate sense of urgency to the signaling driver.
+ *
+ * A deadline hint is given in absolute ktime (CLOCK_MONOTONIC for userspace
+ * facing APIs).  The time could either be some point in the future (such as
+ * the vblank based deadline for page-flipping, or the start of a compositor's
+ * composition cycle), or the current time to indicate an immediate deadline
+ * hint (Ie. forward progress cannot be made until this fence is signaled).
+ *
+ * Multiple deadlines may be set on a given fence, even in parallel.  See the
+ * documentation for &dma_fence_ops.set_deadline.
+ *
+ * The deadline hint is just that, a hint.  The driver that created the fence
+ * may react by increasing frequency, making different scheduling choices, etc.
+ * Or doing nothing at all.
+ */
+
+/**
+ * dma_fence_set_deadline - set desired fence-wait deadline hint
+ * @fence:the fence that is to be waited on
+ * @deadline: the time by which the waiter hopes for the fence to be
+ *signaled
+ *
+ * Give the fence signaler a hint about an upcoming deadline, such as
+ * vblank, by which point the waiter would prefer the fence to be
+ * signaled by.  This is intended to give feedback to the fence signaler
+ * to aid in power management decisions, such as boosting GPU frequency
+ * if a periodic vblank deadline is approaching but the fence is not
+ * yet signaled..
+ */
+void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
+{
+   if (fence->ops->set_deadline && !dma_fence_is_signaled(fence))
+   fence->ops->set_deadline(fence, deadline);
+}
+EXPORT_SYMBOL(dma_fence_set_deadline);
+
 /**
  * dma_fence_describe - Dump fence describtion into seq_file
  * @fence: the 6f

[Freedreno] [PATCH v9 02/15] dma-buf/fence-array: Add fence deadline support

2023-03-02 Thread Rob Clark
From: Rob Clark 

Propagate the deadline to all the fences in the array.

Signed-off-by: Rob Clark 
Reviewed-by: Christian König 
---
 drivers/dma-buf/dma-fence-array.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/drivers/dma-buf/dma-fence-array.c 
b/drivers/dma-buf/dma-fence-array.c
index 5c8a7084577b..9b3ce8948351 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -123,12 +123,23 @@ static void dma_fence_array_release(struct dma_fence 
*fence)
dma_fence_free(fence);
 }
 
+static void dma_fence_array_set_deadline(struct dma_fence *fence,
+ktime_t deadline)
+{
+   struct dma_fence_array *array = to_dma_fence_array(fence);
+   unsigned i;
+
+   for (i = 0; i < array->num_fences; ++i)
+   dma_fence_set_deadline(array->fences[i], deadline);
+}
+
 const struct dma_fence_ops dma_fence_array_ops = {
.get_driver_name = dma_fence_array_get_driver_name,
.get_timeline_name = dma_fence_array_get_timeline_name,
.enable_signaling = dma_fence_array_enable_signaling,
.signaled = dma_fence_array_signaled,
.release = dma_fence_array_release,
+   .set_deadline = dma_fence_array_set_deadline,
 };
 EXPORT_SYMBOL(dma_fence_array_ops);
 
-- 
2.39.1



[Freedreno] [PATCH v9 04/15] dma-buf/dma-resv: Add a way to set fence deadline

2023-03-02 Thread Rob Clark
From: Rob Clark 

Add a way to set a deadline on remaining resv fences according to the
requested usage.

Signed-off-by: Rob Clark 
Reviewed-by: Christian König 
---
 drivers/dma-buf/dma-resv.c | 22 ++
 include/linux/dma-resv.h   |  2 ++
 2 files changed, 24 insertions(+)

diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index 1c76aed8e262..2a594b754af1 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -684,6 +684,28 @@ long dma_resv_wait_timeout(struct dma_resv *obj, enum 
dma_resv_usage usage,
 }
 EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
 
+/**
+ * dma_resv_set_deadline - Set a deadline on reservation's objects fences
+ * @obj: the reservation object
+ * @usage: controls which fences to include, see enum dma_resv_usage.
+ * @deadline: the requested deadline (MONOTONIC)
+ *
+ * May be called without holding the dma_resv lock.  Sets @deadline on
+ * all fences filtered by @usage.
+ */
+void dma_resv_set_deadline(struct dma_resv *obj, enum dma_resv_usage usage,
+  ktime_t deadline)
+{
+   struct dma_resv_iter cursor;
+   struct dma_fence *fence;
+
+   dma_resv_iter_begin(&cursor, obj, usage);
+   dma_resv_for_each_fence_unlocked(&cursor, fence) {
+   dma_fence_set_deadline(fence, deadline);
+   }
+   dma_resv_iter_end(&cursor);
+}
+EXPORT_SYMBOL_GPL(dma_resv_set_deadline);
 
 /**
  * dma_resv_test_signaled - Test if a reservation object's fences have been
diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
index 0637659a702c..8d0e34dad446 100644
--- a/include/linux/dma-resv.h
+++ b/include/linux/dma-resv.h
@@ -479,6 +479,8 @@ int dma_resv_get_singleton(struct dma_resv *obj, enum 
dma_resv_usage usage,
 int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src);
 long dma_resv_wait_timeout(struct dma_resv *obj, enum dma_resv_usage usage,
   bool intr, unsigned long timeout);
+void dma_resv_set_deadline(struct dma_resv *obj, enum dma_resv_usage usage,
+  ktime_t deadline);
 bool dma_resv_test_signaled(struct dma_resv *obj, enum dma_resv_usage usage);
 void dma_resv_describe(struct dma_resv *obj, struct seq_file *seq);
 
-- 
2.39.1



[Freedreno] [PATCH v9 03/15] dma-buf/fence-chain: Add fence deadline support

2023-03-02 Thread Rob Clark
From: Rob Clark 

Propagate the deadline to all the fences in the chain.

v2: Use dma_fence_chain_contained [Tvrtko]

Signed-off-by: Rob Clark 
Reviewed-by: Christian König  for this one.
---
 drivers/dma-buf/dma-fence-chain.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/drivers/dma-buf/dma-fence-chain.c 
b/drivers/dma-buf/dma-fence-chain.c
index a0d920576ba6..9663ba1bb6ac 100644
--- a/drivers/dma-buf/dma-fence-chain.c
+++ b/drivers/dma-buf/dma-fence-chain.c
@@ -206,6 +206,17 @@ static void dma_fence_chain_release(struct dma_fence 
*fence)
dma_fence_free(fence);
 }
 
+
+static void dma_fence_chain_set_deadline(struct dma_fence *fence,
+ktime_t deadline)
+{
+   dma_fence_chain_for_each(fence, fence) {
+   struct dma_fence *f = dma_fence_chain_contained(fence);
+
+   dma_fence_set_deadline(f, deadline);
+   }
+}
+
 const struct dma_fence_ops dma_fence_chain_ops = {
.use_64bit_seqno = true,
.get_driver_name = dma_fence_chain_get_driver_name,
@@ -213,6 +224,7 @@ const struct dma_fence_ops dma_fence_chain_ops = {
.enable_signaling = dma_fence_chain_enable_signaling,
.signaled = dma_fence_chain_signaled,
.release = dma_fence_chain_release,
+   .set_deadline = dma_fence_chain_set_deadline,
 };
 EXPORT_SYMBOL(dma_fence_chain_ops);
 
-- 
2.39.1



[Freedreno] [PATCH v9 05/15] dma-buf/sync_file: Surface sync-file uABI

2023-03-02 Thread Rob Clark
From: Rob Clark 

We had all of the internal driver APIs, but not the all important
userspace uABI, in the dma-buf doc.  Fix that.  And re-arrange the
comments slightly as otherwise the comments for the ioctl nr defines
would not show up.

v2: Fix docs build warning coming from newly including the uabi header
in the docs build

Signed-off-by: Rob Clark 
Acked-by: Pekka Paalanen 
---
 Documentation/driver-api/dma-buf.rst | 10 ++--
 include/uapi/linux/sync_file.h   | 37 +++-
 2 files changed, 23 insertions(+), 24 deletions(-)

diff --git a/Documentation/driver-api/dma-buf.rst 
b/Documentation/driver-api/dma-buf.rst
index 183e480d8cea..ff3f8da296af 100644
--- a/Documentation/driver-api/dma-buf.rst
+++ b/Documentation/driver-api/dma-buf.rst
@@ -203,8 +203,8 @@ DMA Fence unwrap
 .. kernel-doc:: include/linux/dma-fence-unwrap.h
:internal:
 
-DMA Fence uABI/Sync File
-
+DMA Fence Sync File
+~~~
 
 .. kernel-doc:: drivers/dma-buf/sync_file.c
:export:
@@ -212,6 +212,12 @@ DMA Fence uABI/Sync File
 .. kernel-doc:: include/linux/sync_file.h
:internal:
 
+DMA Fence Sync File uABI
+
+
+.. kernel-doc:: include/uapi/linux/sync_file.h
+   :internal:
+
 Indefinite DMA Fences
 ~
 
diff --git a/include/uapi/linux/sync_file.h b/include/uapi/linux/sync_file.h
index ee2dcfb3d660..7e42a5b7558b 100644
--- a/include/uapi/linux/sync_file.h
+++ b/include/uapi/linux/sync_file.h
@@ -16,12 +16,16 @@
 #include 
 
 /**
- * struct sync_merge_data - data passed to merge ioctl
+ * struct sync_merge_data - SYNC_IOC_MERGE: merge two fences
  * @name:  name of new fence
  * @fd2:   file descriptor of second fence
  * @fence: returns the fd of the new fence to userspace
  * @flags: merge_data flags
  * @pad:   padding for 64-bit alignment, should always be zero
+ *
+ * Creates a new fence containing copies of the sync_pts in both
+ * the calling fd and sync_merge_data.fd2.  Returns the new fence's
+ * fd in sync_merge_data.fence
  */
 struct sync_merge_data {
charname[32];
@@ -34,8 +38,8 @@ struct sync_merge_data {
 /**
  * struct sync_fence_info - detailed fence information
  * @obj_name:  name of parent sync_timeline
-* @driver_name:name of driver implementing the parent
-* @status: status of the fence 0:active 1:signaled <0:error
+ * @driver_name:   name of driver implementing the parent
+ * @status:status of the fence 0:active 1:signaled <0:error
  * @flags: fence_info flags
  * @timestamp_ns:  timestamp of status change in nanoseconds
  */
@@ -48,14 +52,19 @@ struct sync_fence_info {
 };
 
 /**
- * struct sync_file_info - data returned from fence info ioctl
+ * struct sync_file_info - SYNC_IOC_FILE_INFO: get detailed information on a 
sync_file
  * @name:  name of fence
  * @status:status of fence. 1: signaled 0:active <0:error
  * @flags: sync_file_info flags
  * @num_fences number of fences in the sync_file
  * @pad:   padding for 64-bit alignment, should always be zero
- * @sync_fence_info: pointer to array of structs sync_fence_info with all
+ * @sync_fence_info: pointer to array of struct &sync_fence_info with all
  *  fences in the sync_file
+ *
+ * Takes a struct sync_file_info. If num_fences is 0, the field is updated
+ * with the actual number of fences. If num_fences is > 0, the system will
+ * use the pointer provided on sync_fence_info to return up to num_fences of
+ * struct sync_fence_info, with detailed fence information.
  */
 struct sync_file_info {
charname[32];
@@ -69,30 +78,14 @@ struct sync_file_info {
 
 #define SYNC_IOC_MAGIC '>'
 
-/**
+/*
  * Opcodes  0, 1 and 2 were burned during a API change to avoid users of the
  * old API to get weird errors when trying to handling sync_files. The API
  * change happened during the de-stage of the Sync Framework when there was
  * no upstream users available.
  */
 
-/**
- * DOC: SYNC_IOC_MERGE - merge two fences
- *
- * Takes a struct sync_merge_data.  Creates a new fence containing copies of
- * the sync_pts in both the calling fd and sync_merge_data.fd2.  Returns the
- * new fence's fd in sync_merge_data.fence
- */
 #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
-
-/**
- * DOC: SYNC_IOC_FILE_INFO - get detailed information on a sync_file
- *
- * Takes a struct sync_file_info. If num_fences is 0, the field is updated
- * with the actual number of fences. If num_fences is > 0, the system will
- * use the pointer provided on sync_fence_info to return up to num_fences of
- * struct sync_fence_info, with detailed fence information.
- */
 #define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info)
 
 #endif /* _UAPI_LINUX_SYNC_H */
-- 
2.39.1



[Freedreno] [PATCH v9 06/15] dma-buf/sync_file: Add SET_DEADLINE ioctl

2023-03-02 Thread Rob Clark
From: Rob Clark 

The initial purpose is for igt tests, but this would also be useful for
compositors that wait until close to vblank deadline to make decisions
about which frame to show.

The igt tests can be found at:

https://gitlab.freedesktop.org/robclark/igt-gpu-tools/-/commits/fence-deadline

v2: Clarify the timebase, add link to igt tests
v3: Use u64 value in ns to express deadline.
v4: More doc

Signed-off-by: Rob Clark 
Acked-by: Pekka Paalanen 
---
 drivers/dma-buf/dma-fence.c|  3 ++-
 drivers/dma-buf/sync_file.c| 19 +++
 include/uapi/linux/sync_file.h | 22 ++
 3 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index f177c56269bb..74e36f6d05b0 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -933,7 +933,8 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout);
  *   the GPU's devfreq to reduce frequency, when in fact the opposite is what 
is
  *   needed.
  *
- * To this end, deadline hint(s) can be set on a &dma_fence via 
&dma_fence_set_deadline.
+ * To this end, deadline hint(s) can be set on a &dma_fence via 
&dma_fence_set_deadline
+ * (or indirectly via userspace facing ioctls like &sync_set_deadline).
  * The deadline hint provides a way for the waiting driver, or userspace, to
  * convey an appropriate sense of urgency to the signaling driver.
  *
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
index af57799c86ce..418021cfb87c 100644
--- a/drivers/dma-buf/sync_file.c
+++ b/drivers/dma-buf/sync_file.c
@@ -350,6 +350,22 @@ static long sync_file_ioctl_fence_info(struct sync_file 
*sync_file,
return ret;
 }
 
+static int sync_file_ioctl_set_deadline(struct sync_file *sync_file,
+   unsigned long arg)
+{
+   struct sync_set_deadline ts;
+
+   if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
+   return -EFAULT;
+
+   if (ts.pad)
+   return -EINVAL;
+
+   dma_fence_set_deadline(sync_file->fence, ns_to_ktime(ts.deadline_ns));
+
+   return 0;
+}
+
 static long sync_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
 {
@@ -362,6 +378,9 @@ static long sync_file_ioctl(struct file *file, unsigned int 
cmd,
case SYNC_IOC_FILE_INFO:
return sync_file_ioctl_fence_info(sync_file, arg);
 
+   case SYNC_IOC_SET_DEADLINE:
+   return sync_file_ioctl_set_deadline(sync_file, arg);
+
default:
return -ENOTTY;
}
diff --git a/include/uapi/linux/sync_file.h b/include/uapi/linux/sync_file.h
index 7e42a5b7558b..d61752dca4c6 100644
--- a/include/uapi/linux/sync_file.h
+++ b/include/uapi/linux/sync_file.h
@@ -76,6 +76,27 @@ struct sync_file_info {
__u64   sync_fence_info;
 };
 
+/**
+ * struct sync_set_deadline - SYNC_IOC_SET_DEADLINE - set a deadline hint on a 
fence
+ * @deadline_ns: absolute time of the deadline
+ * @pad:   must be zero
+ *
+ * Allows userspace to set a deadline on a fence, see &dma_fence_set_deadline
+ *
+ * The timebase for the deadline is CLOCK_MONOTONIC (same as vblank).  For
+ * example
+ *
+ * clock_gettime(CLOCK_MONOTONIC, &t);
+ * deadline_ns = (t.tv_sec * 10L) + t.tv_nsec + ns_until_deadline
+ */
+struct sync_set_deadline {
+   __u64   deadline_ns;
+   /* Not strictly needed for alignment but gives some possibility
+* for future extension:
+*/
+   __u64   pad;
+};
+
 #define SYNC_IOC_MAGIC '>'
 
 /*
@@ -87,5 +108,6 @@ struct sync_file_info {
 
 #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
 #define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info)
+#define SYNC_IOC_SET_DEADLINE  _IOW(SYNC_IOC_MAGIC, 5, struct 
sync_set_deadline)
 
 #endif /* _UAPI_LINUX_SYNC_H */
-- 
2.39.1



[Freedreno] [PATCH v9 07/15] dma-buf/sw_sync: Add fence deadline support

2023-03-02 Thread Rob Clark
From: Rob Clark 

This consists of simply storing the most recent deadline, and adding an
ioctl to retrieve the deadline.  This can be used in conjunction with
the SET_DEADLINE ioctl on a fence fd for testing.  Ie. create various
sw_sync fences, merge them into a fence-array, set deadline on the
fence-array and confirm that it is propagated properly to each fence.

v2: Switch UABI to express deadline as u64
v3: More verbose UAPI docs, show how to convert from timespec
v4: Better comments, track the soonest deadline, as a normal fence
implementation would, return an error if no deadline set.

Signed-off-by: Rob Clark 
Reviewed-by: Christian König 
Acked-by: Pekka Paalanen 
---
 drivers/dma-buf/sw_sync.c| 81 
 drivers/dma-buf/sync_debug.h |  2 +
 2 files changed, 83 insertions(+)

diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
index 348b3a9170fa..f53071bca3af 100644
--- a/drivers/dma-buf/sw_sync.c
+++ b/drivers/dma-buf/sw_sync.c
@@ -52,12 +52,33 @@ struct sw_sync_create_fence_data {
__s32   fence; /* fd of new fence */
 };
 
+/**
+ * struct sw_sync_get_deadline - get the deadline hint of a sw_sync fence
+ * @deadline_ns: absolute time of the deadline
+ * @pad:   must be zero
+ * @fence_fd:  the sw_sync fence fd (in)
+ *
+ * Return the earliest deadline set on the fence.  The timebase for the
+ * deadline is CLOCK_MONOTONIC (same as vblank).  If there is no deadline
+ * set on the fence, this ioctl will return -ENOENT.
+ */
+struct sw_sync_get_deadline {
+   __u64   deadline_ns;
+   __u32   pad;
+   __s32   fence_fd;
+};
+
 #define SW_SYNC_IOC_MAGIC  'W'
 
 #define SW_SYNC_IOC_CREATE_FENCE   _IOWR(SW_SYNC_IOC_MAGIC, 0,\
struct sw_sync_create_fence_data)
 
 #define SW_SYNC_IOC_INC_IOW(SW_SYNC_IOC_MAGIC, 1, 
__u32)
+#define SW_SYNC_GET_DEADLINE   _IOWR(SW_SYNC_IOC_MAGIC, 2, \
+   struct sw_sync_get_deadline)
+
+
+#define SW_SYNC_HAS_DEADLINE_BIT   DMA_FENCE_FLAG_USER_BITS
 
 static const struct dma_fence_ops timeline_fence_ops;
 
@@ -171,6 +192,22 @@ static void timeline_fence_timeline_value_str(struct 
dma_fence *fence,
snprintf(str, size, "%d", parent->value);
 }
 
+static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t 
deadline)
+{
+   struct sync_pt *pt = dma_fence_to_sync_pt(fence);
+   unsigned long flags;
+
+   spin_lock_irqsave(fence->lock, flags);
+   if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) {
+   if (ktime_before(deadline, pt->deadline))
+   pt->deadline = deadline;
+   } else {
+   pt->deadline = deadline;
+   set_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags);
+   }
+   spin_unlock_irqrestore(fence->lock, flags);
+}
+
 static const struct dma_fence_ops timeline_fence_ops = {
.get_driver_name = timeline_fence_get_driver_name,
.get_timeline_name = timeline_fence_get_timeline_name,
@@ -179,6 +216,7 @@ static const struct dma_fence_ops timeline_fence_ops = {
.release = timeline_fence_release,
.fence_value_str = timeline_fence_value_str,
.timeline_value_str = timeline_fence_timeline_value_str,
+   .set_deadline = timeline_fence_set_deadline,
 };
 
 /**
@@ -387,6 +425,46 @@ static long sw_sync_ioctl_inc(struct sync_timeline *obj, 
unsigned long arg)
return 0;
 }
 
+static int sw_sync_ioctl_get_deadline(struct sync_timeline *obj, unsigned long 
arg)
+{
+   struct sw_sync_get_deadline data;
+   struct dma_fence *fence;
+   struct sync_pt *pt;
+   int ret = 0;
+
+   if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
+   return -EFAULT;
+
+   if (data.deadline_ns || data.pad)
+   return -EINVAL;
+
+   fence = sync_file_get_fence(data.fence_fd);
+   if (!fence)
+   return -EINVAL;
+
+   pt = dma_fence_to_sync_pt(fence);
+   if (!pt)
+   return -EINVAL;
+
+   spin_lock(fence->lock);
+   if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) {
+   data.deadline_ns = ktime_to_ns(pt->deadline);
+   } else {
+   ret = -ENOENT;
+   }
+   spin_unlock(fence->lock);
+
+   dma_fence_put(fence);
+
+   if (ret)
+   return ret;
+
+   if (copy_to_user((void __user *)arg, &data, sizeof(data)))
+   return -EFAULT;
+
+   return 0;
+}
+
 static long sw_sync_ioctl(struct file *file, unsigned int cmd,
  unsigned long arg)
 {
@@ -399,6 +477,9 @@ static long sw_sync_ioctl(struct file *file, unsigned int 
cmd,
case SW_SYNC_IOC_INC:
return sw_sync_ioctl_inc(obj, arg);
 
+   case SW_SYNC_GET_DEADLINE:
+   return sw_sync_ioctl_get_deadline(obj, arg);
+
default:
return -ENOTTY;
}
diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-

[Freedreno] [PATCH v9 09/15] drm/syncobj: Add deadline support for syncobj waits

2023-03-02 Thread Rob Clark
From: Rob Clark 

Add a new flag to let userspace provide a deadline as a hint for syncobj
and timeline waits.  This gives a hint to the driver signaling the
backing fences about how soon userspace needs it to compete work, so it
can addjust GPU frequency accordingly.  An immediate deadline can be
given to provide something equivalent to i915 "wait boost".

v2: Use absolute u64 ns value for deadline hint, drop cap and driver
feature flag in favor of allowing count_handles==0 as a way for
userspace to probe kernel for support of new flag
v3: More verbose comments about UAPI

Signed-off-by: Rob Clark 
---
 drivers/gpu/drm/drm_syncobj.c | 64 ---
 include/uapi/drm/drm.h| 17 ++
 2 files changed, 68 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 0c2be8360525..a85e9464f07b 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -126,6 +126,11 @@
  * synchronize between the two.
  * This requirement is inherited from the Vulkan fence API.
  *
+ * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE is set, the ioctl will also set
+ * a fence deadline hint on the backing fences before waiting, to provide the
+ * fence signaler with an appropriate sense of urgency.  The deadline is
+ * specified as an absolute &CLOCK_MONOTONIC value in units of ns.
+ *
  * Similarly, &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT takes an array of syncobj
  * handles as well as an array of u64 points and does a host-side wait on all
  * of syncobj fences at the given points simultaneously.
@@ -973,7 +978,8 @@ static signed long drm_syncobj_array_wait_timeout(struct 
drm_syncobj **syncobjs,
  uint32_t count,
  uint32_t flags,
  signed long timeout,
- uint32_t *idx)
+ uint32_t *idx,
+ ktime_t *deadline)
 {
struct syncobj_wait_entry *entries;
struct dma_fence *fence;
@@ -1053,6 +1059,15 @@ static signed long drm_syncobj_array_wait_timeout(struct 
drm_syncobj **syncobjs,
drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);
}
 
+   if (deadline) {
+   for (i = 0; i < count; ++i) {
+   fence = entries[i].fence;
+   if (!fence)
+   continue;
+   dma_fence_set_deadline(fence, *deadline);
+   }
+   }
+
do {
set_current_state(TASK_INTERRUPTIBLE);
 
@@ -1151,7 +1166,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev,
  struct drm_file *file_private,
  struct drm_syncobj_wait *wait,
  struct drm_syncobj_timeline_wait 
*timeline_wait,
- struct drm_syncobj **syncobjs, bool timeline)
+ struct drm_syncobj **syncobjs, bool timeline,
+ ktime_t *deadline)
 {
signed long timeout = 0;
uint32_t first = ~0;
@@ -1162,7 +1178,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev,
 NULL,
 wait->count_handles,
 wait->flags,
-timeout, &first);
+timeout, &first,
+deadline);
if (timeout < 0)
return timeout;
wait->first_signaled = first;
@@ -1172,7 +1189,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev,
 
u64_to_user_ptr(timeline_wait->points),
 
timeline_wait->count_handles,
 timeline_wait->flags,
-timeout, &first);
+timeout, &first,
+deadline);
if (timeout < 0)
return timeout;
timeline_wait->first_signaled = first;
@@ -1243,17 +1261,22 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void 
*data,
 {
struct drm_syncobj_wait *args = data;
struct drm_syncobj **syncobjs;
+   unsigned possible_flags;
+   ktime_t t, *tp = NULL;
int ret = 0;
 
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
return -EOPNOTSUPP;
 
- 

[Freedreno] [PATCH v9 10/15] drm/vblank: Add helper to get next vblank time

2023-03-02 Thread Rob Clark
From: Rob Clark 

Will be used in the next commit to set a deadline on fences that an
atomic update is waiting on.

v2: Calculate time at *start* of vblank period, not end
v3: Fix kbuild complaints

Signed-off-by: Rob Clark 
Reviewed-by: Mario Kleiner 
---
 drivers/gpu/drm/drm_vblank.c | 53 ++--
 include/drm/drm_vblank.h |  1 +
 2 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 2ff31717a3de..299fa2a19a90 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -844,10 +844,9 @@ bool drm_crtc_vblank_helper_get_vblank_timestamp(struct 
drm_crtc *crtc,
 EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp);
 
 /**
- * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
- * vblank interval
- * @dev: DRM device
- * @pipe: index of CRTC whose vblank timestamp to retrieve
+ * drm_crtc_get_last_vbltimestamp - retrieve raw timestamp for the most
+ *  recent vblank interval
+ * @crtc: CRTC whose vblank timestamp to retrieve
  * @tvblank: Pointer to target time which should receive the timestamp
  * @in_vblank_irq:
  * True when called from drm_crtc_handle_vblank().  Some drivers
@@ -865,10 +864,9 @@ EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp);
  * True if timestamp is considered to be very precise, false otherwise.
  */
 static bool
-drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
- ktime_t *tvblank, bool in_vblank_irq)
+drm_crtc_get_last_vbltimestamp(struct drm_crtc *crtc, ktime_t *tvblank,
+  bool in_vblank_irq)
 {
-   struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
bool ret = false;
 
/* Define requested maximum error on timestamps (nanoseconds). */
@@ -876,8 +874,6 @@ drm_get_last_vbltimestamp(struct drm_device *dev, unsigned 
int pipe,
 
/* Query driver if possible and precision timestamping enabled. */
if (crtc && crtc->funcs->get_vblank_timestamp && max_error > 0) {
-   struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
-
ret = crtc->funcs->get_vblank_timestamp(crtc, &max_error,
tvblank, in_vblank_irq);
}
@@ -891,6 +887,15 @@ drm_get_last_vbltimestamp(struct drm_device *dev, unsigned 
int pipe,
return ret;
 }
 
+static bool
+drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
+ ktime_t *tvblank, bool in_vblank_irq)
+{
+   struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
+
+   return drm_crtc_get_last_vbltimestamp(crtc, tvblank, in_vblank_irq);
+}
+
 /**
  * drm_crtc_vblank_count - retrieve "cooked" vblank counter value
  * @crtc: which counter to retrieve
@@ -980,6 +985,36 @@ u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
 }
 EXPORT_SYMBOL(drm_crtc_vblank_count_and_time);
 
+/**
+ * drm_crtc_next_vblank_start - calculate the time of the next vblank
+ * @crtc: the crtc for which to calculate next vblank time
+ * @vblanktime: pointer to time to receive the next vblank timestamp.
+ *
+ * Calculate the expected time of the start of the next vblank period,
+ * based on time of previous vblank and frame duration
+ */
+int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime)
+{
+   unsigned int pipe = drm_crtc_index(crtc);
+   struct drm_vblank_crtc *vblank = &crtc->dev->vblank[pipe];
+   struct drm_display_mode *mode = &vblank->hwmode;
+   u64 vblank_start;
+
+   if (!vblank->framedur_ns || !vblank->linedur_ns)
+   return -EINVAL;
+
+   if (!drm_crtc_get_last_vbltimestamp(crtc, vblanktime, false))
+   return -EINVAL;
+
+   vblank_start = DIV_ROUND_DOWN_ULL(
+   (u64)vblank->framedur_ns * mode->crtc_vblank_start,
+   mode->crtc_vtotal);
+   *vblanktime  = ktime_add(*vblanktime, ns_to_ktime(vblank_start));
+
+   return 0;
+}
+EXPORT_SYMBOL(drm_crtc_next_vblank_start);
+
 static void send_vblank_event(struct drm_device *dev,
struct drm_pending_vblank_event *e,
u64 seq, ktime_t now)
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index 733a3e2d1d10..7f3957943dd1 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -230,6 +230,7 @@ bool drm_dev_has_vblank(const struct drm_device *dev);
 u64 drm_crtc_vblank_count(struct drm_crtc *crtc);
 u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
   ktime_t *vblanktime);
+int drm_crtc_next_vblank_start(struct drm_crtc *crtc, ktime_t *vblanktime);
 void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
   struct drm_pending_vblank_event *e);
 void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
-- 
2.39.1



[Freedreno] [PATCH v9 08/15] drm/scheduler: Add fence deadline support

2023-03-02 Thread Rob Clark
As the finished fence is the one that is exposed to userspace, and
therefore the one that other operations, like atomic update, would
block on, we need to propagate the deadline from from the finished
fence to the actual hw fence.

v2: Split into drm_sched_fence_set_parent() (ckoenig)
v3: Ensure a thread calling drm_sched_fence_set_deadline_finished() sees
fence->parent set before drm_sched_fence_set_parent() does this
test_bit(DMA_FENCE_FLAG_HAS_DEADLINE_BIT).

Signed-off-by: Rob Clark 
Acked-by: Luben Tuikov 
---
 drivers/gpu/drm/scheduler/sched_fence.c | 46 +
 drivers/gpu/drm/scheduler/sched_main.c  |  2 +-
 include/drm/gpu_scheduler.h | 17 +
 3 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/scheduler/sched_fence.c 
b/drivers/gpu/drm/scheduler/sched_fence.c
index 7fd869520ef2..fe9c6468e440 100644
--- a/drivers/gpu/drm/scheduler/sched_fence.c
+++ b/drivers/gpu/drm/scheduler/sched_fence.c
@@ -123,6 +123,37 @@ static void drm_sched_fence_release_finished(struct 
dma_fence *f)
dma_fence_put(&fence->scheduled);
 }
 
+static void drm_sched_fence_set_deadline_finished(struct dma_fence *f,
+ ktime_t deadline)
+{
+   struct drm_sched_fence *fence = to_drm_sched_fence(f);
+   struct dma_fence *parent;
+   unsigned long flags;
+
+   spin_lock_irqsave(&fence->lock, flags);
+
+   /* If we already have an earlier deadline, keep it: */
+   if (test_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT, &f->flags) &&
+   ktime_before(fence->deadline, deadline)) {
+   spin_unlock_irqrestore(&fence->lock, flags);
+   return;
+   }
+
+   fence->deadline = deadline;
+   set_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT, &f->flags);
+
+   spin_unlock_irqrestore(&fence->lock, flags);
+
+   /*
+* smp_load_aquire() to ensure that if we are racing another
+* thread calling drm_sched_fence_set_parent(), that we see
+* the parent set before it calls test_bit(HAS_DEADLINE_BIT)
+*/
+   parent = smp_load_acquire(&fence->parent);
+   if (parent)
+   dma_fence_set_deadline(parent, deadline);
+}
+
 static const struct dma_fence_ops drm_sched_fence_ops_scheduled = {
.get_driver_name = drm_sched_fence_get_driver_name,
.get_timeline_name = drm_sched_fence_get_timeline_name,
@@ -133,6 +164,7 @@ static const struct dma_fence_ops 
drm_sched_fence_ops_finished = {
.get_driver_name = drm_sched_fence_get_driver_name,
.get_timeline_name = drm_sched_fence_get_timeline_name,
.release = drm_sched_fence_release_finished,
+   .set_deadline = drm_sched_fence_set_deadline_finished,
 };
 
 struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f)
@@ -147,6 +179,20 @@ struct drm_sched_fence *to_drm_sched_fence(struct 
dma_fence *f)
 }
 EXPORT_SYMBOL(to_drm_sched_fence);
 
+void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
+   struct dma_fence *fence)
+{
+   /*
+* smp_store_release() to ensure another thread racing us
+* in drm_sched_fence_set_deadline_finished() sees the
+* fence's parent set before test_bit()
+*/
+   smp_store_release(&s_fence->parent, dma_fence_get(fence));
+   if (test_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT,
+&s_fence->finished.flags))
+   dma_fence_set_deadline(fence, s_fence->deadline);
+}
+
 struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity,
  void *owner)
 {
diff --git a/drivers/gpu/drm/scheduler/sched_main.c 
b/drivers/gpu/drm/scheduler/sched_main.c
index 4e6ad6e122bc..007f98c48f8d 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -1019,7 +1019,7 @@ static int drm_sched_main(void *param)
drm_sched_fence_scheduled(s_fence);
 
if (!IS_ERR_OR_NULL(fence)) {
-   s_fence->parent = dma_fence_get(fence);
+   drm_sched_fence_set_parent(s_fence, fence);
/* Drop for original kref_init of the fence */
dma_fence_put(fence);
 
diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
index 9db9e5e504ee..99584e457153 100644
--- a/include/drm/gpu_scheduler.h
+++ b/include/drm/gpu_scheduler.h
@@ -41,6 +41,15 @@
  */
 #define DRM_SCHED_FENCE_DONT_PIPELINE  DMA_FENCE_FLAG_USER_BITS
 
+/**
+ * DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT - A fence deadline hint has been set
+ *
+ * Because we could have a deadline hint can be set before the backing hw
+ * fence is created, we need to keep track of whether a deadline has already
+ * been set.
+ */
+#define DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT  (DMA_FENCE_FLAG_USER_BITS + 1)
+
 enum dma_resv_usage;
 struct dma_resv;
 struct drm_gem_object;
@@

[Freedreno] [PATCH v9 11/15] drm/atomic-helper: Set fence deadline for vblank

2023-03-02 Thread Rob Clark
From: Rob Clark 

For an atomic commit updating a single CRTC (ie. a pageflip) calculate
the next vblank time, and inform the fence(s) of that deadline.

v2: Comment typo fix (danvet)

Signed-off-by: Rob Clark 
Reviewed-by: Daniel Vetter 
Signed-off-by: Rob Clark 
---
 drivers/gpu/drm/drm_atomic_helper.c | 36 +
 1 file changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index d579fd8f7cb8..d8ee98ce2fc5 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1511,6 +1511,40 @@ void drm_atomic_helper_commit_modeset_enables(struct 
drm_device *dev,
 }
 EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
 
+/*
+ * For atomic updates which touch just a single CRTC, calculate the time of the
+ * next vblank, and inform all the fences of the deadline.
+ */
+static void set_fence_deadline(struct drm_device *dev,
+  struct drm_atomic_state *state)
+{
+   struct drm_crtc *crtc, *wait_crtc = NULL;
+   struct drm_crtc_state *new_crtc_state;
+   struct drm_plane *plane;
+   struct drm_plane_state *new_plane_state;
+   ktime_t vbltime;
+   int i;
+
+   for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) {
+   if (wait_crtc)
+   return;
+   wait_crtc = crtc;
+   }
+
+   /* If no CRTCs updated, then nothing to do: */
+   if (!wait_crtc)
+   return;
+
+   if (drm_crtc_next_vblank_start(wait_crtc, &vbltime))
+   return;
+
+   for_each_new_plane_in_state (state, plane, new_plane_state, i) {
+   if (!new_plane_state->fence)
+   continue;
+   dma_fence_set_deadline(new_plane_state->fence, vbltime);
+   }
+}
+
 /**
  * drm_atomic_helper_wait_for_fences - wait for fences stashed in plane state
  * @dev: DRM device
@@ -1540,6 +1574,8 @@ int drm_atomic_helper_wait_for_fences(struct drm_device 
*dev,
struct drm_plane_state *new_plane_state;
int i, ret;
 
+   set_fence_deadline(dev, state);
+
for_each_new_plane_in_state(state, plane, new_plane_state, i) {
if (!new_plane_state->fence)
continue;
-- 
2.39.1



[Freedreno] [PATCH v9 12/15] drm/msm: Add deadline based boost support

2023-03-02 Thread Rob Clark
From: Rob Clark 

Track the nearest deadline on a fence timeline and set a timer to expire
shortly before to trigger boost if the fence has not yet been signaled.

v2: rebase

Signed-off-by: Rob Clark 
---
 drivers/gpu/drm/msm/msm_fence.c | 74 +
 drivers/gpu/drm/msm/msm_fence.h | 20 +
 2 files changed, 94 insertions(+)

diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c
index 56641408ea74..51b461f32103 100644
--- a/drivers/gpu/drm/msm/msm_fence.c
+++ b/drivers/gpu/drm/msm/msm_fence.c
@@ -8,6 +8,35 @@
 
 #include "msm_drv.h"
 #include "msm_fence.h"
+#include "msm_gpu.h"
+
+static struct msm_gpu *fctx2gpu(struct msm_fence_context *fctx)
+{
+   struct msm_drm_private *priv = fctx->dev->dev_private;
+   return priv->gpu;
+}
+
+static enum hrtimer_restart deadline_timer(struct hrtimer *t)
+{
+   struct msm_fence_context *fctx = container_of(t,
+   struct msm_fence_context, deadline_timer);
+
+   kthread_queue_work(fctx2gpu(fctx)->worker, &fctx->deadline_work);
+
+   return HRTIMER_NORESTART;
+}
+
+static void deadline_work(struct kthread_work *work)
+{
+   struct msm_fence_context *fctx = container_of(work,
+   struct msm_fence_context, deadline_work);
+
+   /* If deadline fence has already passed, nothing to do: */
+   if (msm_fence_completed(fctx, fctx->next_deadline_fence))
+   return;
+
+   msm_devfreq_boost(fctx2gpu(fctx), 2);
+}
 
 
 struct msm_fence_context *
@@ -36,6 +65,13 @@ msm_fence_context_alloc(struct drm_device *dev, volatile 
uint32_t *fenceptr,
fctx->completed_fence = fctx->last_fence;
*fctx->fenceptr = fctx->last_fence;
 
+   hrtimer_init(&fctx->deadline_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+   fctx->deadline_timer.function = deadline_timer;
+
+   kthread_init_work(&fctx->deadline_work, deadline_work);
+
+   fctx->next_deadline = ktime_get();
+
return fctx;
 }
 
@@ -62,6 +98,8 @@ void msm_update_fence(struct msm_fence_context *fctx, 
uint32_t fence)
spin_lock_irqsave(&fctx->spinlock, flags);
if (fence_after(fence, fctx->completed_fence))
fctx->completed_fence = fence;
+   if (msm_fence_completed(fctx, fctx->next_deadline_fence))
+   hrtimer_cancel(&fctx->deadline_timer);
spin_unlock_irqrestore(&fctx->spinlock, flags);
 }
 
@@ -92,10 +130,46 @@ static bool msm_fence_signaled(struct dma_fence *fence)
return msm_fence_completed(f->fctx, f->base.seqno);
 }
 
+static void msm_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
+{
+   struct msm_fence *f = to_msm_fence(fence);
+   struct msm_fence_context *fctx = f->fctx;
+   unsigned long flags;
+   ktime_t now;
+
+   spin_lock_irqsave(&fctx->spinlock, flags);
+   now = ktime_get();
+
+   if (ktime_after(now, fctx->next_deadline) ||
+   ktime_before(deadline, fctx->next_deadline)) {
+   fctx->next_deadline = deadline;
+   fctx->next_deadline_fence =
+   max(fctx->next_deadline_fence, (uint32_t)fence->seqno);
+
+   /*
+* Set timer to trigger boost 3ms before deadline, or
+* if we are already less than 3ms before the deadline
+* schedule boost work immediately.
+*/
+   deadline = ktime_sub(deadline, ms_to_ktime(3));
+
+   if (ktime_after(now, deadline)) {
+   kthread_queue_work(fctx2gpu(fctx)->worker,
+   &fctx->deadline_work);
+   } else {
+   hrtimer_start(&fctx->deadline_timer, deadline,
+   HRTIMER_MODE_ABS);
+   }
+   }
+
+   spin_unlock_irqrestore(&fctx->spinlock, flags);
+}
+
 static const struct dma_fence_ops msm_fence_ops = {
.get_driver_name = msm_fence_get_driver_name,
.get_timeline_name = msm_fence_get_timeline_name,
.signaled = msm_fence_signaled,
+   .set_deadline = msm_fence_set_deadline,
 };
 
 struct dma_fence *
diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h
index 7f1798c54cd1..cdaebfb94f5c 100644
--- a/drivers/gpu/drm/msm/msm_fence.h
+++ b/drivers/gpu/drm/msm/msm_fence.h
@@ -52,6 +52,26 @@ struct msm_fence_context {
volatile uint32_t *fenceptr;
 
spinlock_t spinlock;
+
+   /*
+* TODO this doesn't really deal with multiple deadlines, like
+* if userspace got multiple frames ahead.. OTOH atomic updates
+* don't queue, so maybe that is ok
+*/
+
+   /** next_deadline: Time of next deadline */
+   ktime_t next_deadline;
+
+   /**
+* next_deadline_fence:
+*
+* Fence value for next pending deadline.  The deadline timer is
+* canceled when this fence is signaled.
+*/
+   uint

[Freedreno] [PATCH v9 13/15] drm/msm: Add wait-boost support

2023-03-02 Thread Rob Clark
From: Rob Clark 

Add a way for various userspace waits to signal urgency.

Signed-off-by: Rob Clark 
---
 drivers/gpu/drm/msm/msm_drv.c | 12 
 drivers/gpu/drm/msm/msm_gem.c |  5 +
 include/uapi/drm/msm_drm.h| 14 --
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index aca48c868c14..f6764a86b2da 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -46,6 +46,7 @@
  * - 1.8.0 - Add MSM_BO_CACHED_COHERENT for supported GPUs (a6xx)
  * - 1.9.0 - Add MSM_SUBMIT_FENCE_SN_IN
  * - 1.10.0 - Add MSM_SUBMIT_BO_NO_IMPLICIT
+ * - 1.11.0 - Add wait boost (MSM_WAIT_FENCE_BOOST, MSM_PREP_BOOST)
  */
 #define MSM_VERSION_MAJOR  1
 #define MSM_VERSION_MINOR  10
@@ -899,7 +900,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void 
*data,
 }
 
 static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id,
- ktime_t timeout)
+ ktime_t timeout, uint32_t flags)
 {
struct dma_fence *fence;
int ret;
@@ -929,6 +930,9 @@ static int wait_fence(struct msm_gpu_submitqueue *queue, 
uint32_t fence_id,
if (!fence)
return 0;
 
+   if (flags & MSM_WAIT_FENCE_BOOST)
+   dma_fence_set_deadline(fence, ktime_get());
+
ret = dma_fence_wait_timeout(fence, true, timeout_to_jiffies(&timeout));
if (ret == 0) {
ret = -ETIMEDOUT;
@@ -949,8 +953,8 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, 
void *data,
struct msm_gpu_submitqueue *queue;
int ret;
 
-   if (args->pad) {
-   DRM_ERROR("invalid pad: %08x\n", args->pad);
+   if (args->flags & ~MSM_WAIT_FENCE_FLAGS) {
+   DRM_ERROR("invalid flags: %08x\n", args->flags);
return -EINVAL;
}
 
@@ -961,7 +965,7 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, 
void *data,
if (!queue)
return -ENOENT;
 
-   ret = wait_fence(queue, args->fence, to_ktime(args->timeout));
+   ret = wait_fence(queue, args->fence, to_ktime(args->timeout), 
args->flags);
 
msm_submitqueue_put(queue);
 
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 1dee0d18abbb..dd4a0d773f6e 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -846,6 +846,11 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t 
op, ktime_t *timeout)
op & MSM_PREP_NOSYNC ? 0 : timeout_to_jiffies(timeout);
long ret;
 
+   if (op & MSM_PREP_BOOST) {
+   dma_resv_set_deadline(obj->resv, dma_resv_usage_rw(write),
+ ktime_get());
+   }
+
ret = dma_resv_wait_timeout(obj->resv, dma_resv_usage_rw(write),
true,  remain);
if (ret == 0)
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 329100016e7c..dbf0d6f43fa9 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -151,8 +151,13 @@ struct drm_msm_gem_info {
 #define MSM_PREP_READ0x01
 #define MSM_PREP_WRITE   0x02
 #define MSM_PREP_NOSYNC  0x04
+#define MSM_PREP_BOOST   0x08
 
-#define MSM_PREP_FLAGS   (MSM_PREP_READ | MSM_PREP_WRITE | MSM_PREP_NOSYNC)
+#define MSM_PREP_FLAGS   (MSM_PREP_READ | \
+ MSM_PREP_WRITE | \
+ MSM_PREP_NOSYNC | \
+ MSM_PREP_BOOST | \
+ 0)
 
 struct drm_msm_gem_cpu_prep {
__u32 handle; /* in */
@@ -286,6 +291,11 @@ struct drm_msm_gem_submit {
 
 };
 
+#define MSM_WAIT_FENCE_BOOST   0x0001
+#define MSM_WAIT_FENCE_FLAGS   ( \
+   MSM_WAIT_FENCE_BOOST | \
+   0)
+
 /* The normal way to synchronize with the GPU is just to CPU_PREP on
  * a buffer if you need to access it from the CPU (other cmdstream
  * submission from same or other contexts, PAGE_FLIP ioctl, etc, all
@@ -295,7 +305,7 @@ struct drm_msm_gem_submit {
  */
 struct drm_msm_wait_fence {
__u32 fence;  /* in */
-   __u32 pad;
+   __u32 flags;  /* in, bitmask of MSM_WAIT_FENCE_x */
struct drm_msm_timespec timeout;   /* in */
__u32 queueid; /* in, submitqueue id */
 };
-- 
2.39.1



[Freedreno] [PATCH v9 14/15] drm/msm/atomic: Switch to vblank_start helper

2023-03-02 Thread Rob Clark
From: Rob Clark 

Drop our custom thing and switch to drm_crtc_next_vblank_start() for
calculating the time of the start of the next vblank period.

Signed-off-by: Rob Clark 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 15 ---
 drivers/gpu/drm/msm/msm_atomic.c|  8 +---
 drivers/gpu/drm/msm/msm_kms.h   |  8 
 3 files changed, 5 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index a683bd9b5a04..43996aecaf8c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -411,20 +411,6 @@ static void dpu_kms_disable_commit(struct msm_kms *kms)
pm_runtime_put_sync(&dpu_kms->pdev->dev);
 }
 
-static ktime_t dpu_kms_vsync_time(struct msm_kms *kms, struct drm_crtc *crtc)
-{
-   struct drm_encoder *encoder;
-
-   drm_for_each_encoder_mask(encoder, crtc->dev, 
crtc->state->encoder_mask) {
-   ktime_t vsync_time;
-
-   if (dpu_encoder_vsync_time(encoder, &vsync_time) == 0)
-   return vsync_time;
-   }
-
-   return ktime_get();
-}
-
 static void dpu_kms_prepare_commit(struct msm_kms *kms,
struct drm_atomic_state *state)
 {
@@ -953,7 +939,6 @@ static const struct msm_kms_funcs kms_funcs = {
.irq = dpu_core_irq,
.enable_commit   = dpu_kms_enable_commit,
.disable_commit  = dpu_kms_disable_commit,
-   .vsync_time  = dpu_kms_vsync_time,
.prepare_commit  = dpu_kms_prepare_commit,
.flush_commit= dpu_kms_flush_commit,
.wait_flush  = dpu_kms_wait_flush,
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 1686fbb611fd..c5e71c05f038 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -186,8 +186,7 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
struct msm_kms *kms = priv->kms;
struct drm_crtc *async_crtc = NULL;
unsigned crtc_mask = get_crtc_mask(state);
-   bool async = kms->funcs->vsync_time &&
-   can_do_async(state, &async_crtc);
+   bool async = can_do_async(state, &async_crtc);
 
trace_msm_atomic_commit_tail_start(async, crtc_mask);
 
@@ -231,7 +230,9 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
 
kms->pending_crtc_mask |= crtc_mask;
 
-   vsync_time = kms->funcs->vsync_time(kms, async_crtc);
+   if (drm_crtc_next_vblank_start(async_crtc, &vsync_time))
+   goto fallback;
+
wakeup_time = ktime_sub(vsync_time, ms_to_ktime(1));
 
msm_hrtimer_queue_work(&timer->work, wakeup_time,
@@ -253,6 +254,7 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
return;
}
 
+fallback:
/*
 * If there is any async flush pending on updated crtcs, fold
 * them into the current flush.
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index f8ed7588928c..086a3f1ff956 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -59,14 +59,6 @@ struct msm_kms_funcs {
void (*enable_commit)(struct msm_kms *kms);
void (*disable_commit)(struct msm_kms *kms);
 
-   /**
-* If the kms backend supports async commit, it should implement
-* this method to return the time of the next vsync.  This is
-* used to determine a time slightly before vsync, for the async
-* commit timer to run and complete an async commit.
-*/
-   ktime_t (*vsync_time)(struct msm_kms *kms, struct drm_crtc *crtc);
-
/**
 * Prepare for atomic commit.  This is called after any previous
 * (async or otherwise) commit has completed.
-- 
2.39.1



[Freedreno] [PATCH v9 15/15] drm/i915: Add deadline based boost support

2023-03-02 Thread Rob Clark
From: Rob Clark 

v2: rebase

Signed-off-by: Rob Clark 
---
 drivers/gpu/drm/i915/i915_request.c | 20 
 1 file changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_request.c 
b/drivers/gpu/drm/i915/i915_request.c
index 7503dcb9043b..44491e7e214c 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -97,6 +97,25 @@ static bool i915_fence_enable_signaling(struct dma_fence 
*fence)
return i915_request_enable_breadcrumb(to_request(fence));
 }
 
+static void i915_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
+{
+   struct i915_request *rq = to_request(fence);
+
+   if (i915_request_completed(rq))
+   return;
+
+   if (i915_request_started(rq))
+   return;
+
+   /*
+* TODO something more clever for deadlines that are in the
+* future.  I think probably track the nearest deadline in
+* rq->timeline and set timer to trigger boost accordingly?
+*/
+
+   intel_rps_boost(rq);
+}
+
 static signed long i915_fence_wait(struct dma_fence *fence,
   bool interruptible,
   signed long timeout)
@@ -182,6 +201,7 @@ const struct dma_fence_ops i915_fence_ops = {
.signaled = i915_fence_signaled,
.wait = i915_fence_wait,
.release = i915_fence_release,
+   .set_deadline = i915_fence_set_deadline,
 };
 
 static void irq_execute_cb(struct irq_work *wrk)
-- 
2.39.1



Re: [Freedreno] [PATCH v9 15/15] drm/i915: Add deadline based boost support

2023-03-02 Thread Rodrigo Vivi
On Thu, Mar 02, 2023 at 03:53:37PM -0800, Rob Clark wrote:
> From: Rob Clark 
>

missing some wording here...

> v2: rebase
> 
> Signed-off-by: Rob Clark 
> ---
>  drivers/gpu/drm/i915/i915_request.c | 20 
>  1 file changed, 20 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/i915_request.c 
> b/drivers/gpu/drm/i915/i915_request.c
> index 7503dcb9043b..44491e7e214c 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -97,6 +97,25 @@ static bool i915_fence_enable_signaling(struct dma_fence 
> *fence)
>   return i915_request_enable_breadcrumb(to_request(fence));
>  }
>  
> +static void i915_fence_set_deadline(struct dma_fence *fence, ktime_t 
> deadline)
> +{
> + struct i915_request *rq = to_request(fence);
> +
> + if (i915_request_completed(rq))
> + return;
> +
> + if (i915_request_started(rq))
> + return;

why do we skip the boost if already started?
don't we want to boost the freq anyway?

> +
> + /*
> +  * TODO something more clever for deadlines that are in the
> +  * future.  I think probably track the nearest deadline in
> +  * rq->timeline and set timer to trigger boost accordingly?
> +  */

I'm afraid it will be very hard to find some heuristics of what's
late enough for the boost no?
I mean, how early to boost the freq on an upcoming deadline for the
timer?

> +
> + intel_rps_boost(rq);
> +}
> +
>  static signed long i915_fence_wait(struct dma_fence *fence,
>  bool interruptible,
>  signed long timeout)
> @@ -182,6 +201,7 @@ const struct dma_fence_ops i915_fence_ops = {
>   .signaled = i915_fence_signaled,
>   .wait = i915_fence_wait,
>   .release = i915_fence_release,
> + .set_deadline = i915_fence_set_deadline,
>  };
>  
>  static void irq_execute_cb(struct irq_work *wrk)
> -- 
> 2.39.1
>