Refactor existing CRC code for layer mixer and add CRC support for interface blocks
Changes since V1: - Create helper methods for collect_misr and setup_misr in dpu_hw_util.c - Move common bitmasks into dpu_hw_util.h - Update copyrights - Create a dynamically allocated crcs array in dpu_crtc_state - Collect CRCs for all drm_encoders connected to the crtc
Changes since V2: - Separate dpu_hw_util changes into a separate patch - Revert back to using a static array and define a macro for MAX_CRC_ENTRIES
Jessica Zhang (4): drm/msm/dpu: Move LM CRC code into separate method drm/msm/dpu: Generalize MISR methods to hw_util drm/msm/dpu: Add MISR register support for interface drm/msm/dpu: Add interface support for CRC debugfs
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 130 +++++++++++++++----- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 11 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 64 ++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 22 ++++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 19 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 8 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c | 42 +------ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c | 49 +++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 16 +++ 9 files changed, 287 insertions(+), 74 deletions(-)
Move layer mixer-specific section of dpu_crtc_get_crc() into a separate helper method. This way, we can make it easier to get CRCs from other HW blocks by adding other get_crc helper methods.
Changes since V1: - Move common bitmasks to dpu_hw_util.h - Move common CRC methods to dpu_hw_util.c - Update copyrights - Change crcs array to a dynamically allocated array and added it as a member of crtc_state
Changes since V2: - Put changes for hw_util into a separate commit - Revert crcs array to a static array - Add else case for set_crc_source to return EINVAL if no valid source is selected - Add DPU_CRTC_MAX_CRC_ENTRIES macro
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 79 ++++++++++++++---------- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 8 +++ 2 files changed, 56 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index b56f777dbd0e..69a1257d3b6d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com @@ -99,17 +100,32 @@ static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, return 0; }
+static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) +{ + struct dpu_crtc_mixer *m; + int i; + + for (i = 0; i < crtc_state->num_mixers; ++i) { + m = &crtc_state->mixers[i]; + + if (!m->hw_lm || !m->hw_lm->ops.setup_misr) + continue; + + /* Calculate MISR over 1 frame */ + m->hw_lm->ops.setup_misr(m->hw_lm, true, 1); + } +} + static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); enum dpu_crtc_crc_source current_source; struct dpu_crtc_state *crtc_state; struct drm_device *drm_dev = crtc->dev; - struct dpu_crtc_mixer *m;
bool was_enabled; bool enable = false; - int i, ret = 0; + int ret = 0;
if (source < 0) { DRM_DEBUG_DRIVER("Invalid CRC source %s for CRTC%d\n", src_name, crtc->index); @@ -146,16 +162,10 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
crtc_state->crc_frame_skip_count = 0;
- for (i = 0; i < crtc_state->num_mixers; ++i) { - m = &crtc_state->mixers[i]; - - if (!m->hw_lm || !m->hw_lm->ops.setup_misr) - continue; - - /* Calculate MISR over 1 frame */ - m->hw_lm->ops.setup_misr(m->hw_lm, true, 1); - } - + if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) + dpu_crtc_setup_lm_misr(crtc_state); + else + ret = -EINVAL;
cleanup: drm_modeset_unlock(&crtc->mutex); @@ -174,34 +184,22 @@ static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) return dpu_encoder_get_vsync_count(encoder); }
- -static int dpu_crtc_get_crc(struct drm_crtc *crtc) +static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, + struct dpu_crtc_state *crtc_state, u32 *crcs) { - struct dpu_crtc_state *crtc_state; - struct dpu_crtc_mixer *m; - u32 crcs[CRTC_DUAL_MIXERS]; + struct dpu_crtc_mixer *lm;
- int i = 0; int rc = 0; - - crtc_state = to_dpu_crtc_state(crtc->state); - - BUILD_BUG_ON(ARRAY_SIZE(crcs) != ARRAY_SIZE(crtc_state->mixers)); - - /* Skip first 2 frames in case of "uncooked" CRCs */ - if (crtc_state->crc_frame_skip_count < 2) { - crtc_state->crc_frame_skip_count++; - return 0; - } + int i;
for (i = 0; i < crtc_state->num_mixers; ++i) {
- m = &crtc_state->mixers[i]; + lm = &crtc_state->mixers[i];
- if (!m->hw_lm || !m->hw_lm->ops.collect_misr) + if (!lm->hw_lm || !lm->hw_lm->ops.collect_misr) continue;
- rc = m->hw_lm->ops.collect_misr(m->hw_lm, &crcs[i]); + rc = lm->hw_lm->ops.collect_misr(lm->hw_lm, &crcs[i]);
if (rc) { if (rc != -ENODATA) @@ -214,6 +212,25 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) drm_crtc_accurate_vblank_count(crtc), crcs); }
+static int dpu_crtc_get_crc(struct drm_crtc *crtc) +{ + struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state); + u32 crcs[DPU_CRTC_MAX_CRC_ENTRIES]; + + /* Skip first 2 frames in case of "uncooked" CRCs */ + if (crtc_state->crc_frame_skip_count < 2) { + crtc_state->crc_frame_skip_count++; + return 0; + } + + if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { + BUILD_BUG_ON(ARRAY_SIZE(crcs) < ARRAY_SIZE(crtc_state->mixers)); + return dpu_crtc_get_lm_crc(crtc, crtc_state, crcs); + } + + return 0; +} + static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq, int *vpos, int *hpos, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index b8785c394fcc..aa897ec28ad3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -69,6 +69,11 @@ struct dpu_crtc_smmu_state_data { uint32_t transition_error; };
+/* + * Maximum CRC entries that can be in crcs entries array + */ +#define DPU_CRTC_MAX_CRC_ENTRIES 8 + /** * enum dpu_crtc_crc_source: CRC source * @DPU_CRTC_CRC_SOURCE_NONE: no source set @@ -201,6 +206,9 @@ struct dpu_crtc { * @mixers : List of active mixers * @num_ctls : Number of ctl paths in use * @hw_ctls : List of active ctl paths + * @crc_source : CRC source + * @crc_frame_skip_count: Number of frames skipped before getting CRC + * @crcs : Array to store CRC values */ struct dpu_crtc_state { struct drm_crtc_state base;
On Tue, 21 Jun 2022 at 03:50, Jessica Zhang quic_jesszhan@quicinc.com wrote:
Move layer mixer-specific section of dpu_crtc_get_crc() into a separate helper method. This way, we can make it easier to get CRCs from other HW blocks by adding other get_crc helper methods.
Changes since V1:
- Move common bitmasks to dpu_hw_util.h
- Move common CRC methods to dpu_hw_util.c
- Update copyrights
- Change crcs array to a dynamically allocated array and added it as a member of crtc_state
Changes since V2:
- Put changes for hw_util into a separate commit
- Revert crcs array to a static array
- Add else case for set_crc_source to return EINVAL if no valid source is selected
- Add DPU_CRTC_MAX_CRC_ENTRIES macro
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 79 ++++++++++++++---------- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 8 +++ 2 files changed, 56 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index b56f777dbd0e..69a1257d3b6d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /*
- Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
- Copyright (C) 2013 Red Hat
- Author: Rob Clark robdclark@gmail.com
@@ -99,17 +100,32 @@ static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, return 0; }
+static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) +{
struct dpu_crtc_mixer *m;
int i;
for (i = 0; i < crtc_state->num_mixers; ++i) {
m = &crtc_state->mixers[i];
if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
continue;
/* Calculate MISR over 1 frame */
m->hw_lm->ops.setup_misr(m->hw_lm, true, 1);
}
+}
static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); enum dpu_crtc_crc_source current_source; struct dpu_crtc_state *crtc_state; struct drm_device *drm_dev = crtc->dev;
struct dpu_crtc_mixer *m; bool was_enabled; bool enable = false;
int i, ret = 0;
int ret = 0; if (source < 0) { DRM_DEBUG_DRIVER("Invalid CRC source %s for CRTC%d\n", src_name, crtc->index);
@@ -146,16 +162,10 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
crtc_state->crc_frame_skip_count = 0;
for (i = 0; i < crtc_state->num_mixers; ++i) {
m = &crtc_state->mixers[i];
if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
continue;
/* Calculate MISR over 1 frame */
m->hw_lm->ops.setup_misr(m->hw_lm, true, 1);
}
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER)
dpu_crtc_setup_lm_misr(crtc_state);
else
ret = -EINVAL;
cleanup: drm_modeset_unlock(&crtc->mutex); @@ -174,34 +184,22 @@ static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) return dpu_encoder_get_vsync_count(encoder); }
-static int dpu_crtc_get_crc(struct drm_crtc *crtc) +static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc,
struct dpu_crtc_state *crtc_state, u32 *crcs)
{
struct dpu_crtc_state *crtc_state;
struct dpu_crtc_mixer *m;
u32 crcs[CRTC_DUAL_MIXERS];
struct dpu_crtc_mixer *lm;
int i = 0; int rc = 0;
crtc_state = to_dpu_crtc_state(crtc->state);
BUILD_BUG_ON(ARRAY_SIZE(crcs) != ARRAY_SIZE(crtc_state->mixers));
/* Skip first 2 frames in case of "uncooked" CRCs */
if (crtc_state->crc_frame_skip_count < 2) {
crtc_state->crc_frame_skip_count++;
return 0;
}
int i; for (i = 0; i < crtc_state->num_mixers; ++i) {
m = &crtc_state->mixers[i];
lm = &crtc_state->mixers[i];
Why?
if (!m->hw_lm || !m->hw_lm->ops.collect_misr)
if (!lm->hw_lm || !lm->hw_lm->ops.collect_misr) continue;
rc = m->hw_lm->ops.collect_misr(m->hw_lm, &crcs[i]);
rc = lm->hw_lm->ops.collect_misr(lm->hw_lm, &crcs[i]); if (rc) { if (rc != -ENODATA)
@@ -214,6 +212,25 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) drm_crtc_accurate_vblank_count(crtc), crcs); }
+static int dpu_crtc_get_crc(struct drm_crtc *crtc) +{
struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state);
u32 crcs[DPU_CRTC_MAX_CRC_ENTRIES];
Following up the review of patch 4, I'd suggest moving crcs to dpu_crtc_get_lm_crc().
/* Skip first 2 frames in case of "uncooked" CRCs */
if (crtc_state->crc_frame_skip_count < 2) {
crtc_state->crc_frame_skip_count++;
return 0;
}
if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) {
BUILD_BUG_ON(ARRAY_SIZE(crcs) < ARRAY_SIZE(crtc_state->mixers));
return dpu_crtc_get_lm_crc(crtc, crtc_state, crcs);
}
return 0;
-EINVAL?
+}
static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq, int *vpos, int *hpos, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index b8785c394fcc..aa897ec28ad3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -69,6 +69,11 @@ struct dpu_crtc_smmu_state_data { uint32_t transition_error; };
+/*
- Maximum CRC entries that can be in crcs entries array
- */
+#define DPU_CRTC_MAX_CRC_ENTRIES 8
/**
- enum dpu_crtc_crc_source: CRC source
- @DPU_CRTC_CRC_SOURCE_NONE: no source set
@@ -201,6 +206,9 @@ struct dpu_crtc {
- @mixers : List of active mixers
- @num_ctls : Number of ctl paths in use
- @hw_ctls : List of active ctl paths
- @crc_source : CRC source
- @crc_frame_skip_count: Number of frames skipped before getting CRC
- @crcs : Array to store CRC values
There is no crcs array anymore
*/ struct dpu_crtc_state { struct drm_crtc_state base; -- 2.35.1
On 6/20/2022 11:42 PM, Dmitry Baryshkov wrote:
On Tue, 21 Jun 2022 at 03:50, Jessica Zhang quic_jesszhan@quicinc.com wrote:
Move layer mixer-specific section of dpu_crtc_get_crc() into a separate helper method. This way, we can make it easier to get CRCs from other HW blocks by adding other get_crc helper methods.
Changes since V1:
- Move common bitmasks to dpu_hw_util.h
- Move common CRC methods to dpu_hw_util.c
- Update copyrights
- Change crcs array to a dynamically allocated array and added it as a member of crtc_state
Changes since V2:
- Put changes for hw_util into a separate commit
- Revert crcs array to a static array
- Add else case for set_crc_source to return EINVAL if no valid source is selected
- Add DPU_CRTC_MAX_CRC_ENTRIES macro
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 79 ++++++++++++++---------- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 8 +++ 2 files changed, 56 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index b56f777dbd0e..69a1257d3b6d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /*
- Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
- Copyright (C) 2013 Red Hat
- Author: Rob Clark robdclark@gmail.com
@@ -99,17 +100,32 @@ static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, return 0; }
+static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) +{
struct dpu_crtc_mixer *m;
int i;
for (i = 0; i < crtc_state->num_mixers; ++i) {
m = &crtc_state->mixers[i];
if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
continue;
/* Calculate MISR over 1 frame */
m->hw_lm->ops.setup_misr(m->hw_lm, true, 1);
}
+}
- static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); enum dpu_crtc_crc_source current_source; struct dpu_crtc_state *crtc_state; struct drm_device *drm_dev = crtc->dev;
struct dpu_crtc_mixer *m; bool was_enabled; bool enable = false;
int i, ret = 0;
int ret = 0; if (source < 0) { DRM_DEBUG_DRIVER("Invalid CRC source %s for CRTC%d\n", src_name, crtc->index);
@@ -146,16 +162,10 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
crtc_state->crc_frame_skip_count = 0;
for (i = 0; i < crtc_state->num_mixers; ++i) {
m = &crtc_state->mixers[i];
if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
continue;
/* Calculate MISR over 1 frame */
m->hw_lm->ops.setup_misr(m->hw_lm, true, 1);
}
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER)
dpu_crtc_setup_lm_misr(crtc_state);
else
ret = -EINVAL;
cleanup: drm_modeset_unlock(&crtc->mutex);
@@ -174,34 +184,22 @@ static u32 dpu_crtc_get_vblank_counter(struct drm_crtc *crtc) return dpu_encoder_get_vsync_count(encoder); }
-static int dpu_crtc_get_crc(struct drm_crtc *crtc) +static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc,
{struct dpu_crtc_state *crtc_state, u32 *crcs)
struct dpu_crtc_state *crtc_state;
struct dpu_crtc_mixer *m;
u32 crcs[CRTC_DUAL_MIXERS];
struct dpu_crtc_mixer *lm;
int i = 0; int rc = 0;
crtc_state = to_dpu_crtc_state(crtc->state);
BUILD_BUG_ON(ARRAY_SIZE(crcs) != ARRAY_SIZE(crtc_state->mixers));
/* Skip first 2 frames in case of "uncooked" CRCs */
if (crtc_state->crc_frame_skip_count < 2) {
crtc_state->crc_frame_skip_count++;
return 0;
}
int i; for (i = 0; i < crtc_state->num_mixers; ++i) {
m = &crtc_state->mixers[i];
lm = &crtc_state->mixers[i];
Why?
Renamed to lm for readability, but I can change it back to m if you think that's more readable.
if (!m->hw_lm || !m->hw_lm->ops.collect_misr)
if (!lm->hw_lm || !lm->hw_lm->ops.collect_misr) continue;
rc = m->hw_lm->ops.collect_misr(m->hw_lm, &crcs[i]);
rc = lm->hw_lm->ops.collect_misr(lm->hw_lm, &crcs[i]); if (rc) { if (rc != -ENODATA)
@@ -214,6 +212,25 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) drm_crtc_accurate_vblank_count(crtc), crcs); }
+static int dpu_crtc_get_crc(struct drm_crtc *crtc) +{
struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state);
u32 crcs[DPU_CRTC_MAX_CRC_ENTRIES];
Following up the review of patch 4, I'd suggest moving crcs to dpu_crtc_get_lm_crc().
Noted.
/* Skip first 2 frames in case of "uncooked" CRCs */
if (crtc_state->crc_frame_skip_count < 2) {
crtc_state->crc_frame_skip_count++;
return 0;
}
if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) {
BUILD_BUG_ON(ARRAY_SIZE(crcs) < ARRAY_SIZE(crtc_state->mixers));
return dpu_crtc_get_lm_crc(crtc, crtc_state, crcs);
}
return 0;
-EINVAL?
Ah, made the EINVAL change to set_crc_source, but forgot to propogate here.
+}
- static bool dpu_crtc_get_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq, int *vpos, int *hpos,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index b8785c394fcc..aa897ec28ad3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -69,6 +69,11 @@ struct dpu_crtc_smmu_state_data { uint32_t transition_error; };
+/*
- Maximum CRC entries that can be in crcs entries array
- */
+#define DPU_CRTC_MAX_CRC_ENTRIES 8
- /**
- enum dpu_crtc_crc_source: CRC source
- @DPU_CRTC_CRC_SOURCE_NONE: no source set
@@ -201,6 +206,9 @@ struct dpu_crtc {
- @mixers : List of active mixers
- @num_ctls : Number of ctl paths in use
- @hw_ctls : List of active ctl paths
- @crc_source : CRC source
- @crc_frame_skip_count: Number of frames skipped before getting CRC
- @crcs : Array to store CRC values
There is no crcs array anymore
Noted.
Thanks,
Jessica Zhang
*/ struct dpu_crtc_state { struct drm_crtc_state base; -- 2.35.1
-- With best wishes Dmitry
Move layer mixer specific MISR methods to generalized helper methods. This will make it easier to add CRC support for other blocks in the future.
Changes since V2: - Reordered parameters so that offsets are after hw_blk_reg_map - Fixed mismatched whitespace in bitmask definitions
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c | 42 ++---------------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c | 49 ++++++++++++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 16 +++++++ 3 files changed, 67 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index 462f5082099e..e370dcd76e17 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */
@@ -27,11 +28,6 @@
#define LM_MISR_CTRL 0x310 #define LM_MISR_SIGNATURE 0x314 -#define LM_MISR_FRAME_COUNT_MASK 0xFF -#define LM_MISR_CTRL_ENABLE BIT(8) -#define LM_MISR_CTRL_STATUS BIT(9) -#define LM_MISR_CTRL_STATUS_CLEAR BIT(10) -#define LM_MISR_CTRL_FREE_RUN_MASK BIT(31)
static const struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer, @@ -108,44 +104,12 @@ static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx,
static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count) { - struct dpu_hw_blk_reg_map *c = &ctx->hw; - u32 config = 0; - - DPU_REG_WRITE(c, LM_MISR_CTRL, LM_MISR_CTRL_STATUS_CLEAR); - - /* Clear old MISR value (in case it's read before a new value is calculated)*/ - wmb(); - - if (enable) { - config = (frame_count & LM_MISR_FRAME_COUNT_MASK) | - LM_MISR_CTRL_ENABLE | LM_MISR_CTRL_FREE_RUN_MASK; - - DPU_REG_WRITE(c, LM_MISR_CTRL, config); - } else { - DPU_REG_WRITE(c, LM_MISR_CTRL, 0); - } - + dpu_hw_setup_misr(&ctx->hw, LM_MISR_CTRL, enable, frame_count); }
static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value) { - struct dpu_hw_blk_reg_map *c = &ctx->hw; - u32 ctrl = 0; - - if (!misr_value) - return -EINVAL; - - ctrl = DPU_REG_READ(c, LM_MISR_CTRL); - - if (!(ctrl & LM_MISR_CTRL_ENABLE)) - return -ENODATA; - - if (!(ctrl & LM_MISR_CTRL_STATUS)) - return -EINVAL; - - *misr_value = DPU_REG_READ(c, LM_MISR_SIGNATURE); - - return 0; + return dpu_hw_collect_misr(&ctx->hw, LM_MISR_CTRL, LM_MISR_SIGNATURE, misr_value); }
static void dpu_hw_lm_setup_blend_config_sdm845(struct dpu_hw_mixer *ctx, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c index 512316f25a51..a679757159e9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
@@ -447,3 +449,48 @@ u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
return 0; } + +void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, + u32 misr_ctrl_offset, + bool enable, u32 frame_count) +{ + u32 config = 0; + + DPU_REG_WRITE(c, misr_ctrl_offset, MISR_CTRL_STATUS_CLEAR); + + /* Clear old MISR value (in case it's read before a new value is calculated)*/ + wmb(); + + if (enable) { + config = (frame_count & MISR_FRAME_COUNT_MASK) | + MISR_CTRL_ENABLE | MISR_CTRL_FREE_RUN_MASK; + + DPU_REG_WRITE(c, misr_ctrl_offset, config); + } else { + DPU_REG_WRITE(c, misr_ctrl_offset, 0); + } + +} + +int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c, + u32 misr_ctrl_offset, + u32 misr_signature_offset, + u32 *misr_value) +{ + u32 ctrl = 0; + + if (!misr_value) + return -EINVAL; + + ctrl = DPU_REG_READ(c, misr_ctrl_offset); + + if (!(ctrl & MISR_CTRL_ENABLE)) + return -ENODATA; + + if (!(ctrl & MISR_CTRL_STATUS)) + return -EINVAL; + + *misr_value = DPU_REG_READ(c, misr_signature_offset); + + return 0; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h index e4a65eb4f769..98f1be0d2559 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */
@@ -12,6 +13,11 @@ #include "dpu_hw_catalog.h"
#define REG_MASK(n) ((BIT(n)) - 1) +#define MISR_FRAME_COUNT_MASK 0xFF +#define MISR_CTRL_ENABLE BIT(8) +#define MISR_CTRL_STATUS BIT(9) +#define MISR_CTRL_STATUS_CLEAR BIT(10) +#define MISR_CTRL_FREE_RUN_MASK BIT(31)
/* * This is the common struct maintained by each sub block @@ -343,4 +349,14 @@ void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl, u32 total_fl);
+void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, + u32 misr_ctrl_offset, + bool enable, + u32 frame_count); + +int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c, + u32 misr_ctrl_offset, + u32 misr_signature_offset, + u32 *misr_value); + #endif /* _DPU_HW_UTIL_H */
On Tue, 21 Jun 2022 at 03:50, Jessica Zhang quic_jesszhan@quicinc.com wrote:
Move layer mixer specific MISR methods to generalized helper methods. This will make it easier to add CRC support for other blocks in the future.
Changes since V2:
- Reordered parameters so that offsets are after hw_blk_reg_map
- Fixed mismatched whitespace in bitmask definitions
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com
Reviewed-by: Dmitry Baryshkov dmitry.baryshkov@linaro.org
Add support for writing CRC values for the interface block to the debugfs by calling the necessary MISR setup/collect methods.
Changes since V1: - Set values_cnt to only include phys with backing hw_intf - Loop over all drm_encs connected to crtc
Changes since V2: - Remove vblank.h inclusion - Change `pos + i` to `pos + entries` - Initialize values_cnt to 0 for encoder - Change DPU_CRTC_CRC_SOURCE_INTF to DPU_CRTC_CRC_SOURCE_ENCODER (and "intf" to "enc") - Change dpu_encoder_get_num_phys to dpu_encoder_get_num_hw_intfs - Add checks for setup_misr and collect_misr in dpu_encoder_get_num_hw_intfs
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 3 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 64 +++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 22 +++++++ 4 files changed, 138 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 69a1257d3b6d..b4e8a4432796 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -79,6 +79,8 @@ static enum dpu_crtc_crc_source dpu_crtc_parse_crc_source(const char *src_name) if (!strcmp(src_name, "auto") || !strcmp(src_name, "lm")) return DPU_CRTC_CRC_SOURCE_LAYER_MIXER; + if (!strcmp(src_name, "enc")) + return DPU_CRTC_CRC_SOURCE_ENCODER;
return DPU_CRTC_CRC_SOURCE_INVALID; } @@ -94,8 +96,16 @@ static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, return -EINVAL; }
- if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) + if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { *values_cnt = crtc_state->num_mixers; + } else if (source == DPU_CRTC_CRC_SOURCE_ENCODER) { + struct drm_encoder *drm_enc; + + *values_cnt = 0; + + drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) + *values_cnt += dpu_encoder_get_num_hw_intfs(drm_enc); + }
return 0; } @@ -116,6 +126,14 @@ static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) } }
+static void dpu_crtc_setup_encoder_misr(struct drm_crtc *crtc) +{ + struct drm_encoder *drm_enc; + + drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) + dpu_encoder_setup_misr(drm_enc); +} + static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); @@ -164,6 +182,8 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) dpu_crtc_setup_lm_misr(crtc_state); + else if (source == DPU_CRTC_CRC_SOURCE_ENCODER) + dpu_crtc_setup_encoder_misr(crtc); else ret = -EINVAL;
@@ -212,6 +232,28 @@ static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, drm_crtc_accurate_vblank_count(crtc), crcs); }
+static int dpu_crtc_get_encoder_crc(struct drm_crtc *crtc, u32 *crcs) +{ + struct drm_encoder *drm_enc; + int rc, pos = 0; + + + drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) { + rc = dpu_encoder_get_crc(drm_enc, crcs, pos); + if (rc < 0) { + if (rc != -ENODATA) + DRM_DEBUG_DRIVER("MISR read failed\n"); + + return rc; + } + + pos += rc; + } + + return drm_crtc_add_crc_entry(crtc, true, + drm_crtc_accurate_vblank_count(crtc), crcs); +} + static int dpu_crtc_get_crc(struct drm_crtc *crtc) { struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state); @@ -226,6 +268,12 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { BUILD_BUG_ON(ARRAY_SIZE(crcs) < ARRAY_SIZE(crtc_state->mixers)); return dpu_crtc_get_lm_crc(crtc, crtc_state, crcs); + } else if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_ENCODER) { + if (ARRAY_SIZE(crcs) < INTF_MAX) + DPU_ERROR("crcs array of size %ld less than %d\n", + ARRAY_SIZE(crcs), INTF_MAX); + + return dpu_crtc_get_encoder_crc(crtc, crcs); }
return 0; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index aa897ec28ad3..b49cf8ae126f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com @@ -78,11 +79,13 @@ struct dpu_crtc_smmu_state_data { * enum dpu_crtc_crc_source: CRC source * @DPU_CRTC_CRC_SOURCE_NONE: no source set * @DPU_CRTC_CRC_SOURCE_LAYER_MIXER: CRC in layer mixer + * @DPU_CRTC_CRC_SOURCE_ENCODER: CRC in encoder * @DPU_CRTC_CRC_SOURCE_INVALID: Invalid source */ enum dpu_crtc_crc_source { DPU_CRTC_CRC_SOURCE_NONE = 0, DPU_CRTC_CRC_SOURCE_LAYER_MIXER, + DPU_CRTC_CRC_SOURCE_ENCODER, DPU_CRTC_CRC_SOURCE_MAX, DPU_CRTC_CRC_SOURCE_INVALID = -1 }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 52516eb20cb8..a8f841180383 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -225,6 +225,70 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc) return dpu_enc->wide_bus_en; }
+int dpu_encoder_get_num_hw_intfs(const struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + int i, num_intf = 0; + + dpu_enc = to_dpu_encoder_virt(drm_enc); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys->hw_intf && phys->hw_intf->ops.setup_misr + && phys->hw_intf->ops.collect_misr) + num_intf++; + } + + return num_intf; +} + +void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + + int i; + + dpu_enc = to_dpu_encoder_virt(drm_enc); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys->hw_intf || !phys->hw_intf->ops.setup_misr) + continue; + + phys->hw_intf->ops.setup_misr(phys->hw_intf, true, 1); + } +} + +int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos) +{ + struct dpu_encoder_virt *dpu_enc; + + int i, rc = 0, entries_added = 0; + + if (!drm_enc->crtc) { + DRM_ERROR("no crtc found for encoder %d\n", drm_enc->index); + return -EINVAL; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys->hw_intf || !phys->hw_intf->ops.collect_misr) + continue; + + rc = phys->hw_intf->ops.collect_misr(phys->hw_intf, &crcs[pos + entries_added]); + if (rc) + return rc; + entries_added++; + } + + return entries_added; +} + static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned bpc) { struct dpu_hw_dither_cfg dither_cfg = { 0 }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 781d41c91994..749e0144d2de 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark robdclark@gmail.com @@ -174,6 +175,27 @@ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
+/** + * dpu_encoder_get_num_hw_intfs - get number of physical encoders contained + * in virtual encoder + * @drm_enc: Pointer to previously created drm encoder structure + * Returns: Number of physical encoders for given drm encoder + */ +int dpu_encoder_get_num_hw_intfs(const struct drm_encoder *drm_enc); + +/** + * dpu_encoder_setup_misr - enable misr calculations + * @drm_enc: Pointer to previously created drm encoder structure + */ +void dpu_encoder_setup_misr(const struct drm_encoder *drm_encoder); + +/** + * dpu_encoder_get_crc - get the crc value from interface blocks + * @drm_enc: Pointer to previously created drm encoder structure + * Returns: 0 on success, error otherwise + */ +int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos); + /** * dpu_encoder_use_dsc_merge - returns true if the encoder uses DSC merge topology. * @drm_enc: Pointer to previously created drm encoder structure
On Tue, 21 Jun 2022 at 03:50, Jessica Zhang quic_jesszhan@quicinc.com wrote:
Add support for writing CRC values for the interface block to the debugfs by calling the necessary MISR setup/collect methods.
Changes since V1:
- Set values_cnt to only include phys with backing hw_intf
- Loop over all drm_encs connected to crtc
Changes since V2:
- Remove vblank.h inclusion
- Change `pos + i` to `pos + entries`
- Initialize values_cnt to 0 for encoder
- Change DPU_CRTC_CRC_SOURCE_INTF to DPU_CRTC_CRC_SOURCE_ENCODER (and "intf" to "enc")
- Change dpu_encoder_get_num_phys to dpu_encoder_get_num_hw_intfs
- Add checks for setup_misr and collect_misr in dpu_encoder_get_num_hw_intfs
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 3 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 64 +++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 22 +++++++ 4 files changed, 138 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 69a1257d3b6d..b4e8a4432796 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -79,6 +79,8 @@ static enum dpu_crtc_crc_source dpu_crtc_parse_crc_source(const char *src_name) if (!strcmp(src_name, "auto") || !strcmp(src_name, "lm")) return DPU_CRTC_CRC_SOURCE_LAYER_MIXER;
if (!strcmp(src_name, "enc"))
"encoder" unless you have any strong reason (like being compatible with other platforms).
return DPU_CRTC_CRC_SOURCE_ENCODER; return DPU_CRTC_CRC_SOURCE_INVALID;
} @@ -94,8 +96,16 @@ static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, return -EINVAL; }
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER)
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { *values_cnt = crtc_state->num_mixers;
} else if (source == DPU_CRTC_CRC_SOURCE_ENCODER) {
struct drm_encoder *drm_enc;
*values_cnt = 0;
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask)
*values_cnt += dpu_encoder_get_num_hw_intfs(drm_enc);
} return 0;
} @@ -116,6 +126,14 @@ static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) } }
+static void dpu_crtc_setup_encoder_misr(struct drm_crtc *crtc) +{
struct drm_encoder *drm_enc;
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask)
dpu_encoder_setup_misr(drm_enc);
+}
static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name); @@ -164,6 +182,8 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) dpu_crtc_setup_lm_misr(crtc_state);
else if (source == DPU_CRTC_CRC_SOURCE_ENCODER)
dpu_crtc_setup_encoder_misr(crtc); else ret = -EINVAL;
@@ -212,6 +232,28 @@ static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, drm_crtc_accurate_vblank_count(crtc), crcs); }
+static int dpu_crtc_get_encoder_crc(struct drm_crtc *crtc, u32 *crcs) +{
struct drm_encoder *drm_enc;
int rc, pos = 0;
Extra empty line.
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) {
rc = dpu_encoder_get_crc(drm_enc, crcs, pos);
if (rc < 0) {
if (rc != -ENODATA)
DRM_DEBUG_DRIVER("MISR read failed\n");
return rc;
}
pos += rc;
}
return drm_crtc_add_crc_entry(crtc, true,
drm_crtc_accurate_vblank_count(crtc), crcs);
+}
static int dpu_crtc_get_crc(struct drm_crtc *crtc) { struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state); @@ -226,6 +268,12 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { BUILD_BUG_ON(ARRAY_SIZE(crcs) < ARRAY_SIZE(crtc_state->mixers)); return dpu_crtc_get_lm_crc(crtc, crtc_state, crcs);
} else if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_ENCODER) {
if (ARRAY_SIZE(crcs) < INTF_MAX)
DPU_ERROR("crcs array of size %ld less than %d\n",
ARRAY_SIZE(crcs), INTF_MAX);
Ok. With the crcs array being local you don't have to preallocate it here and pass it as an argument. Just declare it in the dpu_crtc_get_encoder_crc(). Then you can allocate it as `u32 crcs[INTF_MAX]` and remove the check.
return dpu_crtc_get_encoder_crc(crtc, crcs); } return 0;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index aa897ec28ad3..b49cf8ae126f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /*
- Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
- Copyright (C) 2013 Red Hat
- Author: Rob Clark robdclark@gmail.com
@@ -78,11 +79,13 @@ struct dpu_crtc_smmu_state_data {
- enum dpu_crtc_crc_source: CRC source
- @DPU_CRTC_CRC_SOURCE_NONE: no source set
- @DPU_CRTC_CRC_SOURCE_LAYER_MIXER: CRC in layer mixer
*/
- @DPU_CRTC_CRC_SOURCE_ENCODER: CRC in encoder
- @DPU_CRTC_CRC_SOURCE_INVALID: Invalid source
enum dpu_crtc_crc_source { DPU_CRTC_CRC_SOURCE_NONE = 0, DPU_CRTC_CRC_SOURCE_LAYER_MIXER,
DPU_CRTC_CRC_SOURCE_ENCODER, DPU_CRTC_CRC_SOURCE_MAX, DPU_CRTC_CRC_SOURCE_INVALID = -1
}; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 52516eb20cb8..a8f841180383 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -225,6 +225,70 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc) return dpu_enc->wide_bus_en; }
+int dpu_encoder_get_num_hw_intfs(const struct drm_encoder *drm_enc)
dpu_encoder_get_crc_values_cnt(), please.
+{
struct dpu_encoder_virt *dpu_enc;
int i, num_intf = 0;
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (phys->hw_intf && phys->hw_intf->ops.setup_misr
&& phys->hw_intf->ops.collect_misr)
num_intf++;
}
return num_intf;
+}
+void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc) +{
struct dpu_encoder_virt *dpu_enc;
int i;
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (!phys->hw_intf || !phys->hw_intf->ops.setup_misr)
continue;
phys->hw_intf->ops.setup_misr(phys->hw_intf, true, 1);
}
+}
+int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos) +{
struct dpu_encoder_virt *dpu_enc;
int i, rc = 0, entries_added = 0;
if (!drm_enc->crtc) {
DRM_ERROR("no crtc found for encoder %d\n", drm_enc->index);
return -EINVAL;
}
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (!phys->hw_intf || !phys->hw_intf->ops.collect_misr)
continue;
rc = phys->hw_intf->ops.collect_misr(phys->hw_intf, &crcs[pos + entries_added]);
if (rc)
return rc;
entries_added++;
}
return entries_added;
+}
static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned bpc) { struct dpu_hw_dither_cfg dither_cfg = { 0 }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 781d41c91994..749e0144d2de 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /*
- Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
- Copyright (C) 2013 Red Hat
- Author: Rob Clark robdclark@gmail.com
@@ -174,6 +175,27 @@ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
+/**
- dpu_encoder_get_num_hw_intfs - get number of physical encoders contained
in virtual encoder
- @drm_enc: Pointer to previously created drm encoder structure
- Returns: Number of physical encoders for given drm encoder
- */
+int dpu_encoder_get_num_hw_intfs(const struct drm_encoder *drm_enc);
+/**
- dpu_encoder_setup_misr - enable misr calculations
- @drm_enc: Pointer to previously created drm encoder structure
- */
+void dpu_encoder_setup_misr(const struct drm_encoder *drm_encoder);
+/**
- dpu_encoder_get_crc - get the crc value from interface blocks
- @drm_enc: Pointer to previously created drm encoder structure
- Returns: 0 on success, error otherwise
- */
+int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos);
/**
- dpu_encoder_use_dsc_merge - returns true if the encoder uses DSC merge topology.
- @drm_enc: Pointer to previously created drm encoder structure
-- 2.35.1
On 6/20/2022 11:36 PM, Dmitry Baryshkov wrote:
On Tue, 21 Jun 2022 at 03:50, Jessica Zhang quic_jesszhan@quicinc.com wrote:
Add support for writing CRC values for the interface block to the debugfs by calling the necessary MISR setup/collect methods.
Changes since V1:
- Set values_cnt to only include phys with backing hw_intf
- Loop over all drm_encs connected to crtc
Changes since V2:
- Remove vblank.h inclusion
- Change `pos + i` to `pos + entries`
- Initialize values_cnt to 0 for encoder
- Change DPU_CRTC_CRC_SOURCE_INTF to DPU_CRTC_CRC_SOURCE_ENCODER (and "intf" to "enc")
- Change dpu_encoder_get_num_phys to dpu_encoder_get_num_hw_intfs
- Add checks for setup_misr and collect_misr in dpu_encoder_get_num_hw_intfs
Signed-off-by: Jessica Zhang quic_jesszhan@quicinc.com
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 50 +++++++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 3 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 64 +++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 22 +++++++ 4 files changed, 138 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 69a1257d3b6d..b4e8a4432796 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -79,6 +79,8 @@ static enum dpu_crtc_crc_source dpu_crtc_parse_crc_source(const char *src_name) if (!strcmp(src_name, "auto") || !strcmp(src_name, "lm")) return DPU_CRTC_CRC_SOURCE_LAYER_MIXER;
if (!strcmp(src_name, "enc"))
"encoder" unless you have any strong reason (like being compatible with other platforms).
Sure
return DPU_CRTC_CRC_SOURCE_ENCODER; return DPU_CRTC_CRC_SOURCE_INVALID;
}
@@ -94,8 +96,16 @@ static int dpu_crtc_verify_crc_source(struct drm_crtc *crtc, return -EINVAL; }
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER)
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { *values_cnt = crtc_state->num_mixers;
} else if (source == DPU_CRTC_CRC_SOURCE_ENCODER) {
struct drm_encoder *drm_enc;
*values_cnt = 0;
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask)
*values_cnt += dpu_encoder_get_num_hw_intfs(drm_enc);
} return 0;
}
@@ -116,6 +126,14 @@ static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) } }
+static void dpu_crtc_setup_encoder_misr(struct drm_crtc *crtc) +{
struct drm_encoder *drm_enc;
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask)
dpu_encoder_setup_misr(drm_enc);
+}
- static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { enum dpu_crtc_crc_source source = dpu_crtc_parse_crc_source(src_name);
@@ -164,6 +182,8 @@ static int dpu_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
if (source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) dpu_crtc_setup_lm_misr(crtc_state);
else if (source == DPU_CRTC_CRC_SOURCE_ENCODER)
dpu_crtc_setup_encoder_misr(crtc); else ret = -EINVAL;
@@ -212,6 +232,28 @@ static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, drm_crtc_accurate_vblank_count(crtc), crcs); }
+static int dpu_crtc_get_encoder_crc(struct drm_crtc *crtc, u32 *crcs) +{
struct drm_encoder *drm_enc;
int rc, pos = 0;
Extra empty line.
Noted.
drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) {
rc = dpu_encoder_get_crc(drm_enc, crcs, pos);
if (rc < 0) {
if (rc != -ENODATA)
DRM_DEBUG_DRIVER("MISR read failed\n");
return rc;
}
pos += rc;
}
return drm_crtc_add_crc_entry(crtc, true,
drm_crtc_accurate_vblank_count(crtc), crcs);
+}
- static int dpu_crtc_get_crc(struct drm_crtc *crtc) { struct dpu_crtc_state *crtc_state = to_dpu_crtc_state(crtc->state);
@@ -226,6 +268,12 @@ static int dpu_crtc_get_crc(struct drm_crtc *crtc) if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_LAYER_MIXER) { BUILD_BUG_ON(ARRAY_SIZE(crcs) < ARRAY_SIZE(crtc_state->mixers)); return dpu_crtc_get_lm_crc(crtc, crtc_state, crcs);
} else if (crtc_state->crc_source == DPU_CRTC_CRC_SOURCE_ENCODER) {
if (ARRAY_SIZE(crcs) < INTF_MAX)
DPU_ERROR("crcs array of size %ld less than %d\n",
ARRAY_SIZE(crcs), INTF_MAX);
Ok. With the crcs array being local you don't have to preallocate it here and pass it as an argument. Just declare it in the dpu_crtc_get_encoder_crc(). Then you can allocate it as `u32 crcs[INTF_MAX]` and remove the check.
Sure.
return dpu_crtc_get_encoder_crc(crtc, crcs); } return 0;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index aa897ec28ad3..b49cf8ae126f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /*
- Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
- Copyright (C) 2013 Red Hat
- Author: Rob Clark robdclark@gmail.com
@@ -78,11 +79,13 @@ struct dpu_crtc_smmu_state_data {
- enum dpu_crtc_crc_source: CRC source
- @DPU_CRTC_CRC_SOURCE_NONE: no source set
- @DPU_CRTC_CRC_SOURCE_LAYER_MIXER: CRC in layer mixer
*/ enum dpu_crtc_crc_source { DPU_CRTC_CRC_SOURCE_NONE = 0, DPU_CRTC_CRC_SOURCE_LAYER_MIXER,
- @DPU_CRTC_CRC_SOURCE_ENCODER: CRC in encoder
- @DPU_CRTC_CRC_SOURCE_INVALID: Invalid source
};DPU_CRTC_CRC_SOURCE_ENCODER, DPU_CRTC_CRC_SOURCE_MAX, DPU_CRTC_CRC_SOURCE_INVALID = -1
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 52516eb20cb8..a8f841180383 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -225,6 +225,70 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc) return dpu_enc->wide_bus_en; }
+int dpu_encoder_get_num_hw_intfs(const struct drm_encoder *drm_enc)
dpu_encoder_get_crc_values_cnt(), please.
Sure
Thanks,
Jessica Zhang
+{
struct dpu_encoder_virt *dpu_enc;
int i, num_intf = 0;
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (phys->hw_intf && phys->hw_intf->ops.setup_misr
&& phys->hw_intf->ops.collect_misr)
num_intf++;
}
return num_intf;
+}
+void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc) +{
struct dpu_encoder_virt *dpu_enc;
int i;
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (!phys->hw_intf || !phys->hw_intf->ops.setup_misr)
continue;
phys->hw_intf->ops.setup_misr(phys->hw_intf, true, 1);
}
+}
+int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos) +{
struct dpu_encoder_virt *dpu_enc;
int i, rc = 0, entries_added = 0;
if (!drm_enc->crtc) {
DRM_ERROR("no crtc found for encoder %d\n", drm_enc->index);
return -EINVAL;
}
dpu_enc = to_dpu_encoder_virt(drm_enc);
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
if (!phys->hw_intf || !phys->hw_intf->ops.collect_misr)
continue;
rc = phys->hw_intf->ops.collect_misr(phys->hw_intf, &crcs[pos + entries_added]);
if (rc)
return rc;
entries_added++;
}
return entries_added;
+}
- static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned bpc) { struct dpu_hw_dither_cfg dither_cfg = { 0 };
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 781d41c91994..749e0144d2de 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /*
- Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
- Copyright (C) 2013 Red Hat
- Author: Rob Clark robdclark@gmail.com
@@ -174,6 +175,27 @@ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
+/**
- dpu_encoder_get_num_hw_intfs - get number of physical encoders contained
in virtual encoder
- @drm_enc: Pointer to previously created drm encoder structure
- Returns: Number of physical encoders for given drm encoder
- */
+int dpu_encoder_get_num_hw_intfs(const struct drm_encoder *drm_enc);
+/**
- dpu_encoder_setup_misr - enable misr calculations
- @drm_enc: Pointer to previously created drm encoder structure
- */
+void dpu_encoder_setup_misr(const struct drm_encoder *drm_encoder);
+/**
- dpu_encoder_get_crc - get the crc value from interface blocks
- @drm_enc: Pointer to previously created drm encoder structure
- Returns: 0 on success, error otherwise
- */
+int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos);
- /**
- dpu_encoder_use_dsc_merge - returns true if the encoder uses DSC merge topology.
- @drm_enc: Pointer to previously created drm encoder structure
-- 2.35.1
-- With best wishes Dmitry
dri-devel@lists.freedesktop.org