From 73e9f16be4d153d9019fc1d5a218c8ff0fd92ad3 Mon Sep 17 00:00:00 2001 From: "Jia, Lin A" Date: Fri, 6 Sep 2024 21:09:25 +0800 Subject: [PATCH 1/5] drm/i915: Define WD trancoder for i915 Add WD Types, WD transcoder to enum list and WD Transcoder offsets. Add i915 register definitions related to WD transcoder Signed-off-by: Jialin --- drivers/gpu/drm/i915/display/intel_display.h | 6 + .../drm/i915/display/intel_display_types.h | 1 + .../drm/i915/display/intel_writeback_reg.h | 128 ++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 10 ++ 4 files changed, 145 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_writeback_reg.h diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 884e8e67b17c7..a1ed9c82e2ed4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -120,6 +120,8 @@ enum transcoder { TRANSCODER_DSI_1, TRANSCODER_DSI_A = TRANSCODER_DSI_0, /* legacy DSI */ TRANSCODER_DSI_C = TRANSCODER_DSI_1, /* legacy DSI */ + TRANSCODER_WD_0, + TRANSCODER_WD_1, I915_MAX_TRANSCODERS }; @@ -141,6 +143,10 @@ static inline const char *transcoder_name(enum transcoder transcoder) return "DSI A"; case TRANSCODER_DSI_C: return "DSI C"; + case TRANSCODER_WD_0: + return "WD 0"; + case TRANSCODER_WD_1: + return "WD 1"; default: return ""; } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 298d00a11f473..131d3b1151212 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -79,6 +79,7 @@ enum intel_output_type { INTEL_OUTPUT_DSI = 9, INTEL_OUTPUT_DDI = 10, INTEL_OUTPUT_DP_MST = 11, + INTEL_OUTPUT_WB = 12, }; enum hdmi_force_audio { diff --git a/drivers/gpu/drm/i915/display/intel_writeback_reg.h b/drivers/gpu/drm/i915/display/intel_writeback_reg.h new file mode 100644 index 0000000000000..955ad7596726a --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_writeback_reg.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: MIT*/ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef _INTEL_WRITEBACK_REG_H_ +#define _INTEL_WRITEBACK_REG_H_ + +#include "i915_reg.h" +/* Gen12 WD */ +#define _MMIO_WD(tc, wd0, wd1) _MMIO_TRANS((tc) - TRANSCODER_WD_0, \ + wd0, wd1) + +#define WD_TRANS_ENABLE (1 << 31) +#define WD_TRANS_DISABLE 0 +#define WD_TRANS_ACTIVE (1 << 30) + +/* WD transcoder control */ +#define _WD_TRANS_FUNC_CTL_0 0x6e400 +#define _WD_TRANS_FUNC_CTL_1 0x6ec00 +#define WD_TRANS_FUNC_CTL(tc) _MMIO_WD(tc,\ + _WD_TRANS_FUNC_CTL_0,\ + _WD_TRANS_FUNC_CTL_1) + +#define TRANS_WD_FUNC_ENABLE (1 << 31) +#define WD_TRIGGERED_CAP_MODE_ENABLE (1 << 30) +#define START_TRIGGER_FRAME (1 << 29) +#define STOP_TRIGGER_FRAME (1 << 28) +#define WD_CTL_POINTER_ETEH (0 << 18) +#define WD_CTL_POINTER_ETDH (1 << 18) +#define WD_CTL_POINTER_DTDH (2 << 18) +#define WD_INPUT_SELECT_MASK (7 << 12) +#define WD_INPUT_PIPE_A (0 << 12) +#define WD_INPUT_PIPE_B (5 << 12) +#define WD_INPUT_PIPE_C (6 << 12) +#define WD_INPUT_PIPE_D (7 << 12) + +#define WD_PIX_FMT_MASK (0x3 << 20) +#define WD_PIX_FMT_YUYV (0x1 << 20) +#define WD_PIX_FMT_XYUV8888 (0x2 << 20) +#define WD_PIX_FMT_XBGR8888 (0x3 << 20) +#define WD_PIX_FMT_Y410 (0x4 << 20) +#define WD_PIX_FMT_YUV422 (0x5 << 20) +#define WD_PIX_FMT_XBGR2101010 (0x6 << 20) +#define WD_PIX_FMT_RGB565 (0x7 << 20) + +#define WD_FRAME_NUMBER_MASK 15 + +#define _WD_STRIDE_0 0x6e510 +#define _WD_STRIDE_1 0x6ed10 +#define WD_STRIDE(tc) _MMIO_WD(tc,\ + _WD_STRIDE_0,\ + _WD_STRIDE_1) +#define WD_STRIDE_SHIFT 6 +#define WD_STRIDE_MASK (0x3ff << WD_STRIDE_SHIFT) + +#define _WD_STREAMCAP_CTL0 0x6e590 +#define _WD_STREAMCAP_CTL1 0x6ed90 +#define WD_STREAMCAP_CTL(tc) _MMIO_WD(tc,\ + _WD_STREAMCAP_CTL0,\ + _WD_STREAMCAP_CTL1) + +#define WD_STREAM_CAP_MODE_EN (1 << 31) +#define WD_STRAT_MASK (3 << 24) +#define WD_SLICING_STRAT_1_1 (0 << 24) +#define WD_SLICING_STRAT_2_1 (1 << 24) +#define WD_SLICING_STRAT_4_1 (2 << 24) +#define WD_SLICING_STRAT_8_1 (3 << 24) +#define WD_STREAM_OVERRUN_STATUS 1 + +#define _WD_SURF_0 0x6e514 +#define _WD_SURF_1 0x6ed14 +#define WD_SURF(tc) _MMIO_WD(tc,\ + _WD_SURF_0,\ + _WD_SURF_1) + +#define _WD_IMR_0 0x6e560 +#define _WD_IMR_1 0x6ed60 +#define WD_IMR(tc) _MMIO_WD(tc,\ + _WD_IMR_0,\ + _WD_IMR_1) +#define WD_FRAME_COMPLETE_INT (1 << 7) +#define WD_GTT_FAULT_INT (1 << 6) +#define WD_VBLANK_INT (1 << 5) +#define WD_OVERRUN_INT (1 << 4) +#define WD_CAPTURING_INT (1 << 3) +#define WD_WRITE_COMPLETE_INT (1 << 2) + +#define _WD_IIR_0 0x6e564 +#define _WD_IIR_1 0x6ed64 +#define WD_IIR(tc) _MMIO_WD(tc,\ + _WD_IIR_0,\ + _WD_IIR_1) + +#define _WD_FRAME_STATUS_0 0x6e56b +#define _WD_FRAME_STATUS_1 0x6ed6b +#define WD_FRAME_STATUS(tc) _MMIO_WD(tc,\ + _WD_FRAME_STATUS_0,\ + _WD_FRAME_STATUS_1) + +#define WD_FRAME_COMPLETE (1 << 31) +#define WD_STATE_IDLE (0 << 24) +#define WD_STATE_CAPSTART (1 << 24) +#define WD_STATE_FRAME_START (2 << 24) +#define WD_STATE_CAPACITIVE (3 << 24) +#define WD_STATE_TG_DONE (4 << 24) +#define WD_STATE_WDX_DONE (5 << 24) +#define WD_STATE_QUICK_CAP (6 << 24) + +#define _WD_27_M_0 0x6e524 +#define _WD_27_M_1 0x6ed24 +#define WD_27_M(tc) _MMIO_WD(tc,\ + _WD_27_M_0,\ + _WD_27_M_1) + +#define _WD_27_N_0 0x6e528 +#define _WD_27_N_1 0x6ec28 +#define WD_27_N(tc) _MMIO_WD(tc,\ + _WD_27_N_0,\ + _WD_27_N_1) + +#define _WD_TAIL_CFG_0 0x6e520 +#define _WD_TAIL_CFG_1 0x6ed20 + +#define WD_TAIL_CFG(tc) _MMIO_WD(tc,\ + _WD_TAIL_CFG_0,\ + _WD_TAIL_CFG_1) +#endif /* _INTEL_WRITEBACK_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f2cda99b2b21a..df82a089d7d33 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2015,6 +2015,8 @@ #define TRANSCODER_EDP_OFFSET 0x6f000 #define TRANSCODER_DSI0_OFFSET 0x6b000 #define TRANSCODER_DSI1_OFFSET 0x6b800 +#define TRANSCODER_WD0_OFFSET 0x6e000 +#define TRANSCODER_WD1_OFFSET 0x6e800 #define HTOTAL(trans) _MMIO_TRANS2(trans, _HTOTAL_A) #define HBLANK(trans) _MMIO_TRANS2(trans, _HBLANK_A) @@ -3713,6 +3715,9 @@ #define PIPE_DSI0_OFFSET 0x7b000 #define PIPE_DSI1_OFFSET 0x7b800 +#define PIPE_WD0_OFFSET 0x7e000 +#define PIPE_WD1_OFFSET 0x7d000 + #define PIPECONF(pipe) _MMIO_PIPE2(pipe, _PIPEACONF) #define PIPEDSL(pipe) _MMIO_PIPE2(pipe, _PIPEADSL) #define PIPEFRAME(pipe) _MMIO_PIPE2(pipe, _PIPEAFRAMEHIGH) @@ -4377,6 +4382,10 @@ #define _PIPEDSI0CONF 0x7b008 #define _PIPEDSI1CONF 0x7b808 +/* WD 0 and 1 */ +#define _PIPEWD0CONF 0x7e008 +#define _PIPEWD1CONF 0x7d008 + /* Sprite A control */ #define _DVSACNTR 0x72180 #define DVS_ENABLE REG_BIT(31) @@ -5602,6 +5611,7 @@ #define GEN8_DE_MISC_IER _MMIO(0x4446c) #define GEN8_DE_MISC_GSE (1 << 27) #define GEN8_DE_EDP_PSR (1 << 19) +#define GEN8_DE_MISC_WD0 (1 << 23) #define GEN8_PCU_ISR _MMIO(0x444e0) #define GEN8_PCU_IMR _MMIO(0x444e4) From e0f542dae1d54f23f7948453072732df4f3c5244 Mon Sep 17 00:00:00 2001 From: "Jia, Lin A" Date: Fri, 6 Sep 2024 21:12:52 +0800 Subject: [PATCH 2/5] drm/i915: Change intel_connector iterators Change intel_connector iterators as with writeback introduction not all drm_connector will be embedded within intel_connector. Signed-off-by: Jialin --- drivers/gpu/drm/i915/display/intel_acpi.c | 7 +++++- drivers/gpu/drm/i915/display/intel_display.h | 3 ++- .../drm/i915/display/intel_display_types.h | 24 ++++++++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c index 9df78e7caa2bd..912fe5c2ffe55 100644 --- a/drivers/gpu/drm/i915/display/intel_acpi.c +++ b/drivers/gpu/drm/i915/display/intel_acpi.c @@ -349,8 +349,13 @@ void intel_acpi_video_register(struct drm_i915_private *i915) */ drm_connector_list_iter_begin(&i915->drm, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { - struct intel_panel *panel = &to_intel_connector(connector)->panel; + struct intel_panel *panel; + struct intel_connector *intel_connector = + to_intel_connector(connector); + if (!intel_connector) + continue; + panel = &intel_connector->panel; if (panel->backlight.funcs && !panel->backlight.device) { acpi_video_register_backlight(); break; diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index a1ed9c82e2ed4..7ab18f1b2442a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -52,6 +52,7 @@ struct intel_crtc_state; struct intel_digital_port; struct intel_dp; struct intel_encoder; +struct intel_connector; struct intel_initial_plane_config; struct intel_load_detect_pipe; struct intel_plane; @@ -469,7 +470,7 @@ enum hpd_pin { for_each_if(intel_encoder_can_psr(intel_encoder)) #define for_each_intel_connector_iter(intel_connector, iter) \ - while ((intel_connector = to_intel_connector(drm_connector_list_iter_next(iter)))) + while ((intel_connector = intel_connector_list_iter_next(iter))) #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 131d3b1151212..01cde0fd57a12 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1496,9 +1496,10 @@ struct cxsr_latency { }; #define to_intel_atomic_state(x) container_of(x, struct intel_atomic_state, base) +#define to_intel_connector(x) ((((x)->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)) ?\ + NULL : container_of(x, struct intel_connector, base)) #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_crtc_state(x) container_of(x, struct intel_crtc_state, uapi) -#define to_intel_connector(x) container_of(x, struct intel_connector, base) #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) #define to_intel_plane(x) container_of(x, struct intel_plane, base) @@ -2069,4 +2070,25 @@ to_intel_frontbuffer(struct drm_framebuffer *fb) return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL; } +static inline struct intel_connector * +intel_connector_list_iter_next(struct drm_connector_list_iter *iter) +{ + struct drm_connector *connector; + bool flag = true; + /* + * Skipping connector that are Writeback connector as they will + * not be embedded in intel connector + */ + while (flag) { + connector = drm_connector_list_iter_next(iter); + if (connector && !to_intel_connector(connector)) + continue; + + flag = false; + + if (connector) + return to_intel_connector(connector); + } + return NULL; +} #endif /* __INTEL_DISPLAY_TYPES_H__ */ From f828d400681b05f936b8bfce9f0ec10dc2998fd0 Mon Sep 17 00:00:00 2001 From: "Jia, Lin A" Date: Fri, 6 Sep 2024 21:15:23 +0800 Subject: [PATCH 3/5] drm/i915: Enable WD Transcoder Add support for writeback transcoder to start capturing frames using interrupt mechanism Signed-off-by: Jialin --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_acpi.c | 1 + drivers/gpu/drm/i915/display/intel_crtc.c | 6 + .../drm/i915/display/intel_crtc_state_dump.c | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 6 + drivers/gpu/drm/i915/display/intel_display.c | 75 +- drivers/gpu/drm/i915/display/intel_display.h | 5 + .../drm/i915/display/intel_display_debugfs.c | 13 +- .../drm/i915/display/intel_display_types.h | 10 +- drivers/gpu/drm/i915/display/intel_dpll.c | 6 + .../drm/i915/display/intel_modeset_setup.c | 103 ++- .../drm/i915/display/intel_modeset_verify.c | 17 +- drivers/gpu/drm/i915/display/intel_opregion.c | 3 + drivers/gpu/drm/i915/display/intel_wb.c | 714 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_wb.h | 49 ++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 8 +- drivers/gpu/drm/i915/i915_pci.c | 7 +- 18 files changed, 977 insertions(+), 49 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_wb.c create mode 100644 drivers/gpu/drm/i915/display/intel_wb.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e202ea8a86bb4..f3b7d29da66b8 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -330,6 +330,7 @@ i915-y += \ display/intel_tv.o \ display/intel_vdsc.o \ display/intel_vrr.o \ + display/intel_wb.o \ display/vlv_dsi.o \ display/vlv_dsi_pll.o diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c index 912fe5c2ffe55..3321ef62fdbdf 100644 --- a/drivers/gpu/drm/i915/display/intel_acpi.c +++ b/drivers/gpu/drm/i915/display/intel_acpi.c @@ -248,6 +248,7 @@ static u32 acpi_display_type(struct intel_connector *connector) case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_eDP: case DRM_MODE_CONNECTOR_DSI: + case DRM_MODE_CONNECTOR_WRITEBACK: display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL; break; case DRM_MODE_CONNECTOR_Unknown: diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 6792a9056f46f..41fd43745e2a1 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -491,6 +491,9 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) if (new_crtc_state->do_async_flip) return; + if (new_crtc_state->output_types & BIT(INTEL_OUTPUT_WB)) + return; + if (intel_crtc_needs_vblank_work(new_crtc_state)) intel_crtc_vblank_work_init(new_crtc_state); @@ -638,6 +641,9 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) if (new_crtc_state->do_async_flip) return; + if (new_crtc_state->output_types & BIT(INTEL_OUTPUT_WB)) + return; + trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end); /* diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index e9212f69c360b..7af6bc5c2fa12 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -71,6 +71,7 @@ static const char * const output_type_str[] = { OUTPUT_TYPE(DSI), OUTPUT_TYPE(DDI), OUTPUT_TYPE(DP_MST), + OUTPUT_TYPE(WB), }; #undef OUTPUT_TYPE diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index da8472cdc1357..63dc653e84e0b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1953,6 +1953,12 @@ void intel_ddi_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) */ if (encoder->type == INTEL_OUTPUT_DP_MST) return; + /* + * WD transcoder is a virtual encoder hence sanization + * is not required for it + */ + if (encoder->type == INTEL_OUTPUT_WB) + return; if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) { u8 pipe_mask; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 461c62c884133..52c1cdcbe37b2 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -115,6 +115,7 @@ #include "intel_sprite.h" #include "intel_tc.h" #include "intel_vga.h" +#include "intel_wb.h" #include "i9xx_plane.h" #include "skl_scaler.h" #include "skl_universal_plane.h" @@ -1338,7 +1339,8 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, if (hsw_ips_pre_update(state, crtc)) intel_crtc_wait_for_next_vblank(crtc); - if (intel_fbc_pre_update(state, crtc)) + if (intel_fbc_pre_update(state, crtc) && + !(new_crtc_state->output_types & BIT(INTEL_OUTPUT_WB))) intel_crtc_wait_for_next_vblank(crtc); if (!needs_async_flip_vtd_wa(old_crtc_state) && @@ -1514,6 +1516,10 @@ static void intel_encoders_update_prepare(struct intel_atomic_state *state) continue; intel_connector = to_intel_connector(connector); + /* intel_connector instance is not created for WD transcoder */ + if (!intel_connector) + continue; + encoder = intel_connector_primary_encoder(intel_connector); if (!encoder->update_prepare) continue; @@ -1543,6 +1549,10 @@ static void intel_encoders_update_complete(struct intel_atomic_state *state) continue; intel_connector = to_intel_connector(connector); + /* intel_connector instance is not created for WD transcoder */ + if (!intel_connector) + continue; + encoder = intel_connector_primary_encoder(intel_connector); if (!encoder->update_complete) continue; @@ -1553,6 +1563,38 @@ static void intel_encoders_update_complete(struct intel_atomic_state *state) } } +static void intel_queue_writeback_job(struct intel_atomic_state *state) +{ + struct drm_connector_state *new_conn_state; + struct drm_connector *connector; + struct drm_writeback_connector *wb_conn; + int i; + + for_each_new_connector_in_state(&state->base, connector, new_conn_state, + i) { + if (!new_conn_state->writeback_job) + continue; + + wb_conn = drm_connector_to_writeback(connector); + drm_writeback_queue_job(wb_conn, new_conn_state); + } +} + +static void intel_enable_writeback_capture(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state) +{ + struct drm_connector_state *new_conn_state; + struct drm_connector *connector; + int i; + + for_each_new_connector_in_state(&state->base, connector, new_conn_state, + i) { + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + continue; + intel_wb_enable_capture(crtc_state, new_conn_state); + } +} + static void intel_encoders_pre_pll_enable(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -1653,8 +1695,12 @@ static void intel_encoders_post_disable(struct intel_atomic_state *state, int i; for_each_old_connector_in_state(&state->base, conn, old_conn_state, i) { - struct intel_encoder *encoder = - to_intel_encoder(old_conn_state->best_encoder); + struct intel_encoder *encoder; + + if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + encoder = to_intel_encoder(old_conn_state->best_encoder); if (old_conn_state->crtc != &crtc->base) continue; @@ -1933,7 +1979,8 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, bdw_set_pipemisc(new_crtc_state); if (!intel_crtc_is_bigjoiner_slave(new_crtc_state) && - !transcoder_is_dsi(cpu_transcoder)) + !transcoder_is_dsi(cpu_transcoder) && + !transcoder_is_wd(cpu_transcoder)) hsw_configure_cpu_transcoder(new_crtc_state); crtc->active = true; @@ -7535,6 +7582,11 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) } } + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + if ((new_crtc_state->output_types & BIT(INTEL_OUTPUT_WB))) + intel_wb_set_vblank_event(state, crtc, new_crtc_state); + } + intel_encoders_update_prepare(state); intel_dbuf_pre_plane_update(state); @@ -7545,9 +7597,20 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_crtc_enable_flip_done(state, crtc); } + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if ((new_crtc_state->output_types & BIT(INTEL_OUTPUT_WB))) { + intel_queue_writeback_job(state); + intel_enable_writeback_capture(state, new_crtc_state); + } + } + /* Now enable the clocks, plane, pipe, and connectors that we set up. */ dev_priv->display.funcs.display->commit_modeset_enables(state); + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + if ((new_crtc_state->output_types & BIT(INTEL_OUTPUT_WB))) + intel_wb_set_vblank_event(state, crtc, new_crtc_state); + } intel_encoders_update_complete(state); if (state->modeset) @@ -7899,6 +7962,10 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; + /* Initializing WD transcoder */ + if (DISPLAY_VER(dev_priv) >= 12) + intel_wb_init(dev_priv, TRANSCODER_WD_0); + if (IS_DG2(dev_priv)) { intel_ddi_init(dev_priv, PORT_A); intel_ddi_init(dev_priv, PORT_B); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 7ab18f1b2442a..63cc186979f14 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -158,6 +158,11 @@ static inline bool transcoder_is_dsi(enum transcoder transcoder) return transcoder == TRANSCODER_DSI_A || transcoder == TRANSCODER_DSI_C; } +static inline bool transcoder_is_wd(enum transcoder transcoder) +{ + return transcoder == TRANSCODER_WD_0 || transcoder == TRANSCODER_WD_1; +} + /* * Global legacy plane identifier. Valid only for primary/sprite * planes on pre-g4x, and only for primary planes on g4x-bdw. diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index ce75ca713e966..edcf1ec38b813 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -550,7 +550,7 @@ static void intel_hdmi_info(struct seq_file *m, static void intel_connector_info(struct seq_file *m, struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_connector *intel_connector; const struct drm_connector_state *conn_state = connector->state; struct intel_encoder *encoder = to_intel_encoder(conn_state->best_encoder); @@ -573,6 +573,8 @@ static void intel_connector_info(struct seq_file *m, if (!encoder) return; + intel_connector = to_intel_connector(connector); + switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: @@ -590,12 +592,15 @@ static void intel_connector_info(struct seq_file *m, break; } - seq_puts(m, "\tHDCP version: "); - intel_hdcp_info(m, intel_connector); + if (intel_connector) { + seq_puts(m, "\tHDCP version: "); + intel_hdcp_info(m, intel_connector); + } seq_printf(m, "\tmax bpc: %u\n", connector->display_info.bpc); - intel_panel_info(m, intel_connector); + if (intel_connector) + intel_panel_info(m, intel_connector); seq_printf(m, "\tmodes:\n"); list_for_each_entry(mode, &connector->modes, head) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 01cde0fd57a12..3e59940a79e24 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include "i915_vma.h" @@ -1371,6 +1372,11 @@ struct intel_crtc { bool cpu_fifo_underrun_disabled; bool pch_fifo_underrun_disabled; + struct { + struct drm_pending_vblank_event *e; + atomic_t work_busy; + wait_queue_head_t wb_wait; + } wb; /* per-pipe watermark state */ struct { /* watermarks currently being used */ @@ -2076,8 +2082,8 @@ intel_connector_list_iter_next(struct drm_connector_list_iter *iter) struct drm_connector *connector; bool flag = true; /* - * Skipping connector that are Writeback connector as they will - * not be embedded in intel connector + * An intel_connector entity is not created for a writeback + * connector hence decoupling. */ while (flag) { connector = drm_connector_list_iter_next(iter); diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index b15ba78d64d62..fdb104091cf4b 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -940,6 +940,9 @@ static int hsw_crtc_compute_clock(struct intel_atomic_state *state, intel_get_crtc_new_encoder(state, crtc_state); int ret; + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_WB)) + return 0; + if (DISPLAY_VER(dev_priv) < 11 && intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) return 0; @@ -968,6 +971,9 @@ static int hsw_crtc_get_shared_dpll(struct intel_atomic_state *state, struct intel_encoder *encoder = intel_get_crtc_new_encoder(state, crtc_state); + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_WB)) + return 0; + if (DISPLAY_VER(dev_priv) < 11 && intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) return 0; diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index cbfabd58b75a6..1462c5f408535 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -24,6 +24,7 @@ #include "intel_pch_display.h" #include "intel_pm.h" #include "skl_watermark.h" +#include "intel_wb.h" static void intel_crtc_disable_noatomic(struct intel_crtc *crtc, struct drm_modeset_acquire_ctx *ctx) @@ -111,17 +112,17 @@ static void intel_crtc_disable_noatomic(struct intel_crtc *crtc, static void intel_modeset_update_connector_atomic_state(struct drm_i915_private *i915) { - struct intel_connector *connector; + struct drm_connector *connector; struct drm_connector_list_iter conn_iter; drm_connector_list_iter_begin(&i915->drm, &conn_iter); - for_each_intel_connector_iter(connector, &conn_iter) { - struct drm_connector_state *conn_state = connector->base.state; + drm_for_each_connector_iter(connector, &conn_iter) { + struct drm_connector_state *conn_state = connector->state; struct intel_encoder *encoder = - to_intel_encoder(connector->base.encoder); + to_intel_encoder(connector->encoder); if (conn_state->crtc) - drm_connector_put(&connector->base); + drm_connector_put(connector); if (encoder) { struct intel_crtc *crtc = @@ -133,7 +134,7 @@ static void intel_modeset_update_connector_atomic_state(struct drm_i915_private conn_state->crtc = &crtc->base; conn_state->max_bpc = (crtc_state->pipe_bpp ?: 24) / 3; - drm_connector_get(&connector->base); + drm_connector_get(connector); } else { conn_state->best_encoder = NULL; conn_state->crtc = NULL; @@ -423,6 +424,8 @@ static void intel_modeset_readout_hw_state(struct drm_i915_private *i915) struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; + struct drm_connector *_connector; + struct drm_encoder *_encoder; struct drm_connector_list_iter conn_iter; u8 active_pipes = 0; @@ -499,38 +502,70 @@ static void intel_modeset_readout_hw_state(struct drm_i915_private *i915) intel_dpll_readout_hw_state(i915); drm_connector_list_iter_begin(&i915->drm, &conn_iter); - for_each_intel_connector_iter(connector, &conn_iter) { - if (connector->get_hw_state(connector)) { - struct intel_crtc_state *crtc_state; - struct intel_crtc *crtc; - - connector->base.dpms = DRM_MODE_DPMS_ON; - - encoder = intel_attached_encoder(connector); - connector->base.encoder = &encoder->base; - - crtc = to_intel_crtc(encoder->base.crtc); - crtc_state = crtc ? to_intel_crtc_state(crtc->base.state) : NULL; - - if (crtc_state && crtc_state->hw.active) { - /* - * This has to be done during hardware readout - * because anything calling .crtc_disable may - * rely on the connector_mask being accurate. - */ - crtc_state->uapi.connector_mask |= - drm_connector_mask(&connector->base); - crtc_state->uapi.encoder_mask |= - drm_encoder_mask(&encoder->base); + drm_for_each_connector_iter(_connector, &conn_iter) { + struct intel_crtc_state *crtc_state; + struct intel_crtc *crtc; + struct drm_writeback_connector *wb_conn; + struct intel_wb *intel_wb; + + connector = to_intel_connector(_connector); + if (!connector) { + wb_conn = drm_connector_to_writeback(_connector); + intel_wb = wb_conn_to_intel_wb(wb_conn); + _encoder = &intel_wb->base.base; + _connector->encoder = _encoder; + encoder = to_intel_encoder(_encoder); + pipe = 0; + if (encoder->get_hw_state(encoder, &pipe)) { + _connector->dpms = DRM_MODE_DPMS_ON; + crtc = to_intel_crtc(_encoder->crtc); + crtc_state = crtc ? to_intel_crtc_state(crtc->base.state) : NULL; + + if (crtc_state && crtc_state->hw.active) { + /* + * This has to be done during hardware readout + * because anything calling .crtc_disable may + * rely on the connector_mask being accurate. + */ + crtc_state->uapi.connector_mask |= + drm_connector_mask(&connector->base); + crtc_state->uapi.encoder_mask |= + drm_encoder_mask(&encoder->base); + } + } else { + _connector->dpms = DRM_MODE_DPMS_OFF; + _connector->encoder = NULL; } } else { - connector->base.dpms = DRM_MODE_DPMS_OFF; - connector->base.encoder = NULL; + if (connector->get_hw_state(connector)) { + connector->base.dpms = DRM_MODE_DPMS_OFF; + encoder = intel_attached_encoder(connector); + connector->base.encoder = &encoder->base; + + crtc = to_intel_crtc(encoder->base.crtc); + crtc_state = crtc ? to_intel_crtc_state(crtc->base.state) : NULL; + + if (crtc_state && crtc_state->hw.active) { + /* + * This has to be done during hardware readout + * because anything calling .crtc_disable may + * rely on the connector_mask being accurate. + */ + crtc_state->uapi.connector_mask |= + drm_connector_mask(&connector->base); + crtc_state->uapi.encoder_mask |= + drm_encoder_mask(&encoder->base); + } + } else { + connector->base.dpms = DRM_MODE_DPMS_OFF; + connector->base.encoder = NULL; + } } drm_dbg_kms(&i915->drm, - "[CONNECTOR:%d:%s] hw state readout: %s\n", - connector->base.base.id, connector->base.name, - str_enabled_disabled(connector->base.encoder)); + "[CONNECTOR:%d:%s] hw state readout: %s\n", + _connector->base.id, _connector->name, + str_enabled_disabled(_connector->encoder)); + } drm_connector_list_iter_end(&conn_iter); diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 0fdcf2e6d57fe..1800441e15544 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -25,11 +25,16 @@ static void intel_connector_verify_state(struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct intel_connector *connector = to_intel_connector(conn_state->connector); - struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_connector *_connector = conn_state->connector; + struct intel_connector *connector; + struct drm_i915_private *i915 = to_i915(_connector->dev); drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n", - connector->base.base.id, connector->base.name); + _connector->base.id, _connector->name); + + connector = to_intel_connector(_connector); + if (!connector) + return; if (connector->get_hw_state(connector)) { struct intel_encoder *encoder = intel_attached_encoder(connector); @@ -119,6 +124,9 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat encoder->base.base.id, encoder->base.name); + if (encoder->type == INTEL_OUTPUT_WB) + continue; + for_each_oldnew_connector_in_state(&state->base, connector, old_conn_state, new_conn_state, i) { if (old_conn_state->best_encoder == &encoder->base) @@ -177,6 +185,9 @@ verify_crtc_state(struct intel_crtc *crtc, intel_crtc_get_pipe_config(pipe_config); + if (new_crtc_state->output_types & BIT(INTEL_OUTPUT_WB)) + return; + /* we keep both pipes enabled on 830 */ if (IS_I830(dev_priv) && pipe_config->hw.active) pipe_config->hw.active = new_crtc_state->hw.active; diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index df4c14be7f61e..d644fb336b837 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -374,6 +374,9 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, if (ret) return ret; + if (intel_encoder->type == INTEL_OUTPUT_WB) + return 0; + if (intel_encoder->type == INTEL_OUTPUT_DSI) port = 0; else diff --git a/drivers/gpu/drm/i915/display/intel_wb.c b/drivers/gpu/drm/i915/display/intel_wb.c new file mode 100644 index 0000000000000..d1aec16415a50 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_wb.c @@ -0,0 +1,714 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corporation + */ + +#include +#include +#include + +#include "intel_atomic.h" +#include "intel_connector.h" +#include "intel_wb.h" +#include "intel_fb_pin.h" +#include "intel_de.h" +#include "intel_writeback_reg.h" + +enum { + WD_CAPTURE_4_PIX, + WD_CAPTURE_2_PIX, +} wb_capture_format; + +struct drm_writeback_job +*intel_get_writeback_job_from_queue(struct intel_wb *intel_wb) +{ + struct drm_writeback_job *job; + struct drm_i915_private *i915 = to_i915(intel_wb->base.base.dev); + struct drm_writeback_connector *wb_conn = + &intel_wb->wb_conn; + unsigned long flags; + + spin_lock_irqsave(&wb_conn->job_lock, flags); + job = list_first_entry_or_null(&wb_conn->job_queue, + struct drm_writeback_job, + list_entry); + spin_unlock_irqrestore(&wb_conn->job_lock, flags); + if (!job) + drm_dbg_kms(&i915->drm, "job queue is empty\n"); + + return job; +} + +static const u32 wb_fmts[] = { + DRM_FORMAT_YUV444, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_Y410, + DRM_FORMAT_YUV422, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_RGB565, +}; + +static int intel_wb_get_format(int pixel_format) +{ + int wb_format = -EINVAL; + + switch (pixel_format) { + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_YUV444: + wb_format = WD_CAPTURE_4_PIX; + break; + case DRM_FORMAT_YUV422: + case DRM_FORMAT_RGB565: + wb_format = WD_CAPTURE_2_PIX; + break; + default: + DRM_ERROR("unsupported pixel format %x!\n", + pixel_format); + } + + return wb_format; +} + +static int intel_wb_verify_pix_format(int format) +{ + const struct drm_format_info *info = drm_format_info(format); + int pix_format = info->format; + int i = 0; + + for (i = 0; i < ARRAY_SIZE(wb_fmts); i++) + if (pix_format == wb_fmts[i]) + return 0; + + return true; +} + +static u32 intel_wb_get_stride(const struct intel_crtc_state *crtc_state, + int format) +{ + const struct drm_format_info *info = drm_format_info(format); + int wb_format; + int hactive, pixel_size; + + wb_format = intel_wb_get_format(info->format); + + switch (wb_format) { + case WD_CAPTURE_4_PIX: + pixel_size = 4; + break; + case WD_CAPTURE_2_PIX: + pixel_size = 2; + break; + default: + pixel_size = 1; + break; + } + + hactive = crtc_state->hw.adjusted_mode.crtc_hdisplay; + + return DIV_ROUND_UP(hactive * pixel_size, 64); +} + +static int intel_wb_pin_fb(struct intel_wb *intel_wb, + struct drm_framebuffer *fb) +{ + const struct i915_gtt_view view = { + .type = I915_GTT_VIEW_NORMAL, + }; + struct i915_vma *vma; + + vma = intel_pin_and_fence_fb_obj(fb, false, &view, true, + &intel_wb->flags); + + if (IS_ERR(vma)) + return PTR_ERR(vma); + + intel_wb->vma = vma; + return 0; +} + +static void intel_configure_slicing_strategy(struct drm_i915_private *i915, + struct intel_wb *intel_wb, + u32 *tmp) +{ + *tmp &= ~WD_STRAT_MASK; + if (intel_wb->slicing_strategy == 1) + *tmp |= WD_SLICING_STRAT_1_1; + else if (intel_wb->slicing_strategy == 2) + *tmp |= WD_SLICING_STRAT_2_1; + else if (intel_wb->slicing_strategy == 3) + *tmp |= WD_SLICING_STRAT_4_1; + else if (intel_wb->slicing_strategy == 4) + *tmp |= WD_SLICING_STRAT_8_1; + + intel_de_write(i915, WD_STREAMCAP_CTL(intel_wb->trans), + *tmp); +} + +static enum drm_mode_status +intel_wb_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static int intel_wb_get_modes(struct drm_connector *connector) +{ + return 0; +} + +static void intel_wb_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ + struct intel_crtc *intel_crtc = + to_intel_crtc(pipe_config->uapi.crtc); + + if (intel_crtc) { + memcpy(pipe_config, intel_crtc->config, + sizeof(*pipe_config)); + pipe_config->output_types |= BIT(INTEL_OUTPUT_WB); + } +} + +static int intel_wb_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) +{ + struct intel_wb *intel_wb = enc_to_intel_wb(encoder); + struct drm_writeback_job *job; + + job = intel_get_writeback_job_from_queue(intel_wb); + if (job || conn_state->writeback_job) { + /* + * Saving reference of pipe/crtc for later use if + * writeback job is present + */ + intel_wb->wb_crtc = to_intel_crtc(pipe_config->uapi.crtc); + return 0; + } + + return 0; +} + +static void intel_wb_get_power_domains(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_wb *intel_wb = enc_to_intel_wb(encoder); + intel_wakeref_t wakeref; + + wakeref = intel_display_power_get(i915, encoder->power_domain); + + intel_wb->io_wakeref[0] = wakeref; +} + +static bool intel_wb_get_hw_state(struct intel_encoder *encoder, + enum pipe *pipe) +{ + bool ret = false; + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_wb *intel_wb = enc_to_intel_wb(encoder); + struct intel_crtc *wb_crtc = intel_wb->wb_crtc; + intel_wakeref_t wakeref; + u32 tmp; + + if (!wb_crtc) + return false; + + wakeref = intel_display_power_get_if_enabled(dev_priv, + encoder->power_domain); + + if (!wakeref) + goto out; + + tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); + ret = tmp & WD_TRANS_ACTIVE; + if (ret) { + *pipe = wb_crtc->pipe; + return true; + } + +out: + intel_display_power_put(dev_priv, encoder->power_domain, wakeref); + return false; +} + +static int intel_wb_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_st, + struct drm_connector_state *conn_st) +{ + /* Check for the format and buffers and property validity */ + struct drm_framebuffer *fb; + struct drm_writeback_job *job = conn_st->writeback_job; + struct drm_i915_private *i915 = to_i915(encoder->dev); + const struct drm_display_mode *mode = &crtc_st->mode; + int ret; + + if (!job) { + drm_dbg_kms(&i915->drm, "No writeback job created returning\n"); + crtc_st->no_vblank = true; + return 0; + } + + fb = job->fb; + if (!fb) { + drm_dbg_kms(&i915->drm, "Invalid framebuffer\n"); + return -EINVAL; + } + + if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) { + drm_dbg_kms(&i915->drm, "Invalid framebuffer size %ux%u\n", + fb->width, fb->height); + return -EINVAL; + } + + ret = intel_wb_verify_pix_format(fb->format->format); + if (ret) { + drm_dbg_kms(&i915->drm, "Unsupported framebuffer format %08x\n", + fb->format->format); + return -EINVAL; + } + + return 0; +} + +static const struct drm_encoder_helper_funcs wb_encoder_helper_funcs = { + .atomic_check = intel_wb_encoder_atomic_check, +}; + +static void intel_wb_connector_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); +} + +static enum drm_connector_status +intel_wb_connector_detect(struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +static void intel_wb_cleanup_writeback_job(struct drm_writeback_connector *connector, + struct drm_writeback_job *job) +{ + struct intel_wb *intel_wb = wb_conn_to_intel_wb(connector); + + intel_unpin_fb_vma(intel_wb->vma, intel_wb->flags); +} + +static const struct drm_connector_funcs wb_connector_funcs = { + .detect = intel_wb_connector_detect, + .reset = drm_atomic_helper_connector_reset, + .destroy = intel_wb_connector_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +}; + +static const struct drm_connector_helper_funcs wb_connector_helper_funcs = { + .get_modes = intel_wb_get_modes, + .mode_valid = intel_wb_mode_valid, + .cleanup_writeback_job = intel_wb_cleanup_writeback_job, +}; + +static const struct drm_encoder_funcs drm_writeback_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static bool intel_fastset_dis(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ + return false; +} + +static void intel_wb_connector_init(struct intel_wb *intel_wb) +{ + drm_atomic_helper_connector_reset(&intel_wb->wb_conn.base); +} + +static void intel_wb_disable_capture(struct intel_wb *intel_wb) +{ + struct drm_i915_private *dev_priv = to_i915(intel_wb->base.base.dev); + u32 tmp; + + intel_de_write_fw(dev_priv, WD_IMR(intel_wb->trans), 0xFF); + tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); + tmp &= WD_TRANS_DISABLE; + intel_de_write(dev_priv, PIPECONF(intel_wb->trans), tmp); + tmp = intel_de_read(dev_priv, WD_TRANS_FUNC_CTL(intel_wb->trans)); + tmp |= WD_TRANS_DISABLE; + intel_de_write(dev_priv, WD_TRANS_FUNC_CTL(intel_wb->trans), tmp); +} + +void intel_wb_init(struct drm_i915_private *i915, enum transcoder trans) +{ + struct intel_wb *intel_wb; + struct intel_encoder *encoder; + struct drm_writeback_connector *wb_conn; + int n_formats = ARRAY_SIZE(wb_fmts); + struct drm_encoder *drm_enc; + int err, ret; + + intel_wb = kzalloc(sizeof(*intel_wb), GFP_KERNEL); + if (!intel_wb) + return; + + intel_wb_connector_init(intel_wb); + encoder = &intel_wb->base; + drm_enc = &encoder->base; + wb_conn = &intel_wb->wb_conn; + intel_wb->trans = trans; + intel_wb->triggered_cap_mode = 1; + intel_wb->frame_num = 1; + intel_wb->slicing_strategy = 1; + encoder->get_config = intel_wb_get_config; + encoder->compute_config = intel_wb_compute_config; + encoder->get_hw_state = intel_wb_get_hw_state; + encoder->type = INTEL_OUTPUT_WB; + encoder->cloneable = 0; + encoder->pipe_mask = ~0; + encoder->power_domain = POWER_DOMAIN_TRANSCODER_B; + encoder->get_power_domains = intel_wb_get_power_domains; + encoder->initial_fastset_check = intel_fastset_dis; + + drm_encoder_helper_add(drm_enc, + &wb_encoder_helper_funcs); + + drm_enc->possible_crtcs = ~0; + ret = drm_encoder_init(&i915->drm, drm_enc, + &drm_writeback_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, NULL); + + if (ret) { + drm_dbg_kms(&i915->drm, + "Writeback drm_encoder init Failed: %d\n", + ret); + goto cleanup; + } + + err = drm_writeback_connector_init_with_encoder(&i915->drm, + wb_conn, + drm_enc, + &wb_connector_funcs, + wb_fmts, n_formats); + + if (err != 0) { + drm_dbg_kms(&i915->drm, + "drm_writeback_connector_init: Failed: %d\n", + err); + goto cleanup; + } + + wb_conn->base.encoder = drm_enc; + drm_connector_helper_add(&wb_conn->base, &wb_connector_helper_funcs); + wb_conn->base.status = connector_status_connected; + return; + +cleanup: + kfree(intel_wb); + return; +} + +static void intel_wb_writeback_complete(struct intel_wb *intel_wb, + struct drm_writeback_job *job, + int status) +{ + struct drm_writeback_connector *wb_conn = + &intel_wb->wb_conn; + drm_writeback_signal_completion(wb_conn, status); +} + +static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct drm_writeback_job *job) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->uapi.crtc); + enum pipe pipe = intel_crtc->pipe; + struct drm_framebuffer *fb; + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + struct drm_gem_object *wb_fb_obj; + int ret; + u32 stride, tmp; + u16 hactive, vactive; + + fb = job->fb; + wb_fb_obj = fb->obj[0]; + if (!wb_fb_obj) { + drm_dbg_kms(&dev_priv->drm, "No framebuffer gem object created\n"); + return -EINVAL; + } + + ret = intel_wb_pin_fb(intel_wb, fb); + drm_WARN_ON(&dev_priv->drm, ret != 0); + /* Write stride and surface registers in that particular order */ + stride = intel_wb_get_stride(pipe_config, fb->format->format); + + tmp = intel_de_read(dev_priv, WD_STRIDE(intel_wb->trans)); + tmp &= ~WD_STRIDE_MASK; + tmp |= (stride << WD_STRIDE_SHIFT); + + intel_de_write(dev_priv, WD_STRIDE(intel_wb->trans), tmp); + + tmp = intel_de_read(dev_priv, WD_SURF(intel_wb->trans)); + + intel_de_write(dev_priv, WD_SURF(intel_wb->trans), + i915_ggtt_offset(intel_wb->vma)); + + tmp = intel_de_read_fw(dev_priv, WD_IIR(intel_wb->trans)); + intel_de_write_fw(dev_priv, WD_IIR(intel_wb->trans), tmp); + + tmp = ~(WD_GTT_FAULT_INT | WD_WRITE_COMPLETE_INT | WD_FRAME_COMPLETE_INT | + WD_VBLANK_INT | WD_OVERRUN_INT | WD_CAPTURING_INT); + intel_de_write_fw(dev_priv, WD_IMR(intel_wb->trans), tmp); + + if (intel_wb->stream_cap) { + tmp = intel_de_read(dev_priv, + WD_STREAMCAP_CTL(intel_wb->trans)); + tmp |= WD_STREAM_CAP_MODE_EN; + intel_configure_slicing_strategy(dev_priv, intel_wb, &tmp); + } + + hactive = pipe_config->uapi.mode.hdisplay; + vactive = pipe_config->uapi.mode.vdisplay; + tmp = intel_de_read(dev_priv, HTOTAL(intel_wb->trans)); + tmp = intel_de_read(dev_priv, VTOTAL(intel_wb->trans)); + + /* minimum hactive as per bspec: 64 pixels */ + if (hactive < 64) + drm_err(&dev_priv->drm, "hactive is less then 64 pixels\n"); + + intel_de_write(dev_priv, HTOTAL(intel_wb->trans), hactive - 1); + intel_de_write(dev_priv, VTOTAL(intel_wb->trans), vactive - 1); + + tmp = intel_de_read(dev_priv, WD_TRANS_FUNC_CTL(intel_wb->trans)); + /* select pixel format */ + tmp &= ~WD_PIX_FMT_MASK; + + switch (fb->format->format) { + default: + fallthrough; + case DRM_FORMAT_YUYV: + tmp |= WD_PIX_FMT_YUYV; + break; + case DRM_FORMAT_XYUV8888: + tmp |= WD_PIX_FMT_XYUV8888; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + tmp |= WD_PIX_FMT_XBGR8888; + break; + case DRM_FORMAT_Y410: + tmp |= WD_PIX_FMT_Y410; + break; + case DRM_FORMAT_YUV422: + tmp |= WD_PIX_FMT_YUV422; + break; + case DRM_FORMAT_XBGR2101010: + tmp |= WD_PIX_FMT_XBGR2101010; + break; + case DRM_FORMAT_RGB565: + tmp |= WD_PIX_FMT_RGB565; + break; + } + + if (intel_wb->triggered_cap_mode) + tmp |= WD_TRIGGERED_CAP_MODE_ENABLE; + + if (intel_wb->stream_cap) + tmp |= WD_CTL_POINTER_DTDH; + + /* select input pipe */ + tmp &= ~WD_INPUT_SELECT_MASK; + switch (pipe) { + default: + fallthrough; + case PIPE_A: + tmp |= WD_INPUT_PIPE_A; + break; + case PIPE_B: + tmp |= WD_INPUT_PIPE_B; + break; + case PIPE_C: + tmp |= WD_INPUT_PIPE_C; + break; + case PIPE_D: + tmp |= WD_INPUT_PIPE_D; + break; + } + + /* enable DDI buffer */ + if (!(tmp & TRANS_WD_FUNC_ENABLE)) + tmp |= TRANS_WD_FUNC_ENABLE; + + intel_de_write(dev_priv, WD_TRANS_FUNC_CTL(intel_wb->trans), tmp); + + tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); + ret = tmp & WD_TRANS_ACTIVE; + if (!ret) { + /* enable the transcoder */ + tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); + tmp |= WD_TRANS_ENABLE; + intel_de_write(dev_priv, PIPECONF(intel_wb->trans), tmp); + + /* wait for transcoder to be enabled */ + if (intel_de_wait_for_set(dev_priv, PIPECONF(intel_wb->trans), + WD_TRANS_ACTIVE, 10)) + drm_err(&dev_priv->drm, "WD transcoder could not be enabled\n"); + } + + return 0; +} + +static int intel_wb_capture(struct intel_wb *intel_wb, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct drm_writeback_job *job) +{ + u32 tmp; + struct drm_i915_private *i915 = to_i915(intel_wb->base.base.dev); + int ret = 0, status = 0; + struct intel_crtc *wb_crtc = intel_wb->wb_crtc; + unsigned long flags; + + if (!job->out_fence) + drm_dbg_kms(&i915->drm, "Not able to get out_fence for job\n"); + + ret = intel_wb_setup_transcoder(intel_wb, pipe_config, + conn_state, job); + + if (ret < 0) { + drm_dbg_kms(&i915->drm, + "WD transcoder setup not completed aborting capture\n"); + return -1; + } + + if (!wb_crtc) { + drm_err(&i915->drm, "CRTC not attached\n"); + return -1; + } + + tmp = intel_de_read_fw(i915, WD_TRANS_FUNC_CTL(intel_wb->trans)); + tmp |= START_TRIGGER_FRAME; + tmp &= ~WD_FRAME_NUMBER_MASK; + tmp |= intel_wb->frame_num; + intel_de_write_fw(i915, WD_TRANS_FUNC_CTL(intel_wb->trans), tmp); + + if (!intel_de_wait_for_set(i915, WD_IIR(intel_wb->trans), + WD_FRAME_COMPLETE_INT, 100)){ + drm_dbg_kms(&i915->drm, "frame captured\n"); + status = 0; + } else { + drm_dbg_kms(&i915->drm, "frame not captured triggering stop frame\n"); + tmp = intel_de_read(i915, WD_TRANS_FUNC_CTL(intel_wb->trans)); + tmp |= STOP_TRIGGER_FRAME; + intel_de_write(i915, WD_TRANS_FUNC_CTL(intel_wb->trans), tmp); + status = -1; + } + + intel_wb_writeback_complete(intel_wb, job, status); + if (wb_crtc->wb.e) { + spin_lock_irqsave(&i915->drm.event_lock, flags); + drm_dbg_kms(&i915->drm, "send %p\n", wb_crtc->wb.e); + drm_crtc_send_vblank_event(&wb_crtc->base, + wb_crtc->wb.e); + spin_unlock_irqrestore(&i915->drm.event_lock, flags); + wb_crtc->wb.e = NULL; + } else { + drm_err(&i915->drm, "Event NULL! %p, %p\n", &i915->drm, + wb_crtc); + } + if (!intel_get_writeback_job_from_queue(intel_wb)) + intel_wb_disable_capture(intel_wb); + return 0; +} + +void intel_wb_enable_capture(struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state) +{ + struct drm_i915_private *i915 = + to_i915(conn_state->connector->dev); + struct drm_writeback_connector *wb_conn = + drm_connector_to_writeback(conn_state->connector); + struct intel_wb *intel_wb = wb_conn_to_intel_wb(wb_conn); + struct drm_writeback_job *job; + + job = intel_get_writeback_job_from_queue(intel_wb); + if (!job) { + drm_dbg_kms(&i915->drm, + "job queue is empty not capturing any frame\n"); + return; + } + + intel_wb_capture(intel_wb, pipe_config, + conn_state, job); + intel_wb->frame_num += 1; +} + +void intel_wb_set_vblank_event(struct intel_atomic_state *state, + struct intel_crtc *intel_crtc, + struct intel_crtc_state *intel_crtc_state) +{ + struct drm_i915_private *i915 = to_i915(intel_crtc->base.dev); + struct drm_crtc_state *crtc_state = &intel_crtc_state->uapi; + struct intel_encoder *encoder; + struct intel_wb *intel_wb; + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + struct drm_connector *connector; + int i; + + for_each_intel_encoder(&i915->drm, encoder) { + if (encoder->type != INTEL_OUTPUT_WB) + continue; + + intel_wb = enc_to_intel_wb(encoder); + if (!intel_wb->wb_crtc) + return; + } + + if (intel_wb && intel_crtc == intel_wb->wb_crtc) { + for_each_oldnew_connector_in_state(&state->base, connector, + old_conn_state, + new_conn_state, i) { + if (new_conn_state->writeback_job) { + intel_crtc->wb.e = crtc_state->event; + crtc_state->event = NULL; + } + } + + if (crtc_state->event) { + crtc_state->no_vblank = true; + drm_atomic_helper_fake_vblank(&state->base); + } + } +} + +void intel_wb_handle_isr(struct drm_i915_private *i915) +{ + u32 iir_value = 0; + struct intel_encoder *encoder; + struct intel_wb *intel_wb; + + iir_value = intel_de_read(i915, WD_IIR(TRANSCODER_WD_0)); + + for_each_intel_encoder(&i915->drm, encoder) { + if (encoder->type != INTEL_OUTPUT_WB) + continue; + + intel_wb = enc_to_intel_wb(encoder); + if (!intel_wb->wb_crtc) { + drm_err(&i915->drm, "NO CRTC attached with WD\n"); + goto clear_iir; + } + } + + if (iir_value & WD_FRAME_COMPLETE_INT) + return; + +clear_iir: + intel_de_write(i915, WD_IIR(TRANSCODER_WD_0), iir_value); +} diff --git a/drivers/gpu/drm/i915/display/intel_wb.h b/drivers/gpu/drm/i915/display/intel_wb.h new file mode 100644 index 0000000000000..7719c03bba150 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_wb.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: MIT*/ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef _INTEL_WB_H +#define _INTEL_WB_H + +#include + +#include "intel_display_types.h" + +#define I915_MAX_WD_TANSCODERS 2 + +struct intel_wb { + struct intel_encoder base; + struct drm_writeback_connector wb_conn; + struct intel_crtc *wb_crtc; + intel_wakeref_t io_wakeref[I915_MAX_WD_TANSCODERS]; + enum transcoder trans; + struct i915_vma *vma; + unsigned long flags; + struct drm_writeback_job *job; + int triggered_cap_mode; + int frame_num; + bool stream_cap; + bool start_capture; + int slicing_strategy; +}; + +static inline struct intel_wb *enc_to_intel_wb(struct intel_encoder *encoder) +{ + return container_of(&encoder->base, struct intel_wb, base.base); +} + +static inline struct intel_wb *wb_conn_to_intel_wb(struct drm_writeback_connector *wb_conn) +{ + return container_of(wb_conn, struct intel_wb, wb_conn); +} + +void intel_wb_init(struct drm_i915_private *dev_priv, enum transcoder trans); +void intel_wb_enable_capture(struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state); +void intel_wb_handle_isr(struct drm_i915_private *dev_priv); +void intel_wb_set_vblank_event(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state); +struct drm_writeback_job *intel_get_writeback_job_from_queue(struct intel_wb *intel_wb); +#endif/* _INTEL_WB_H */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 229eb1b4bdbf5..ddbf65545a2b7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -34,6 +34,7 @@ #include +#include #include #include "display/intel_display.h" diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e6ef6079da2b7..d2a46e732b0b6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -42,6 +42,7 @@ #include "display/intel_hotplug.h" #include "display/intel_lpe_audio.h" #include "display/intel_psr.h" +#include "display/intel_wb.h" #include "gt/intel_breadcrumbs.h" #include "gt/intel_gt.h" @@ -2342,6 +2343,11 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) found = true; } + if (iir & GEN8_DE_MISC_WD0) { + intel_wb_handle_isr(dev_priv); + found = true; + } + if (iir & GEN8_DE_EDP_PSR) { struct intel_encoder *encoder; u32 psr_iir; @@ -3788,7 +3794,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) u32 de_pipe_enables; u32 de_port_masked = gen8_de_port_aux_mask(dev_priv); u32 de_port_enables; - u32 de_misc_masked = GEN8_DE_EDP_PSR; + u32 de_misc_masked = GEN8_DE_EDP_PSR | GEN8_DE_MISC_WD0; u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | BIT(TRANSCODER_C) | BIT(TRANSCODER_D); enum pipe pipe; diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 311d6785c22f4..1b97bd0cd61e1 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -869,7 +869,8 @@ static const struct intel_device_info jsl_info = { .__runtime.pipe_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), \ .__runtime.cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | \ BIT(TRANSCODER_C) | BIT(TRANSCODER_D) | \ - BIT(TRANSCODER_DSI_0) | BIT(TRANSCODER_DSI_1), \ + BIT(TRANSCODER_DSI_0) | BIT(TRANSCODER_DSI_1) | \ + BIT(TRANSCODER_WD_0), \ .display.pipe_offsets = { \ [TRANSCODER_A] = PIPE_A_OFFSET, \ [TRANSCODER_B] = PIPE_B_OFFSET, \ @@ -877,6 +878,8 @@ static const struct intel_device_info jsl_info = { [TRANSCODER_D] = PIPE_D_OFFSET, \ [TRANSCODER_DSI_0] = PIPE_DSI0_OFFSET, \ [TRANSCODER_DSI_1] = PIPE_DSI1_OFFSET, \ + [TRANSCODER_WD_0] = PIPE_WD0_OFFSET, \ + [TRANSCODER_WD_1] = PIPE_WD1_OFFSET, \ }, \ .display.trans_offsets = { \ [TRANSCODER_A] = TRANSCODER_A_OFFSET, \ @@ -885,6 +888,8 @@ static const struct intel_device_info jsl_info = { [TRANSCODER_D] = TRANSCODER_D_OFFSET, \ [TRANSCODER_DSI_0] = TRANSCODER_DSI0_OFFSET, \ [TRANSCODER_DSI_1] = TRANSCODER_DSI1_OFFSET, \ + [TRANSCODER_WD_0] = TRANSCODER_WD0_OFFSET, \ + [TRANSCODER_WD_1] = TRANSCODER_WD1_OFFSET, \ }, \ TGL_CURSOR_OFFSETS, \ .has_global_mocs = 1, \ From c0f684bf0da4ccafce4b365d314ab5e8c760dce4 Mon Sep 17 00:00:00 2001 From: "Jia, Lin A" Date: Mon, 9 Sep 2024 15:22:23 +0800 Subject: [PATCH 4/5] Enable stream capture and dump registers 1. Enable stream capture by default. 2, Dump wd transcoder registers for debug. Signed-off-by: Jialin --- drivers/gpu/drm/drm_atomic_uapi.c | 2 + drivers/gpu/drm/i915/display/intel_wb.c | 139 ++++++++++++++++-- drivers/gpu/drm/i915/display/intel_wb.h | 1 + .../drm/i915/display/intel_writeback_reg.h | 79 +++++++++- drivers/gpu/drm/i915/i915_reg.h | 2 + 5 files changed, 208 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 79730fa1dd8e1..aead94be7b7b0 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -750,6 +750,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, } else if (property == config->writeback_fb_id_property) { struct drm_framebuffer *fb; int ret; + drm_dbg_kms(dev, "writeback_fb_id_property, val %d\n", val); fb = drm_framebuffer_lookup(dev, file_priv, val); ret = drm_atomic_set_writeback_fb_for_connector(state, fb); @@ -758,6 +759,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, return ret; } else if (property == config->writeback_out_fence_ptr_property) { s32 __user *fence_ptr = u64_to_user_ptr(val); + drm_dbg_kms(dev, "writeback_out_fence_ptr_property\n"); return set_out_fence_for_connector(state->state, connector, fence_ptr); diff --git a/drivers/gpu/drm/i915/display/intel_wb.c b/drivers/gpu/drm/i915/display/intel_wb.c index d1aec16415a50..cbf7f77753d16 100644 --- a/drivers/gpu/drm/i915/display/intel_wb.c +++ b/drivers/gpu/drm/i915/display/intel_wb.c @@ -14,6 +14,9 @@ #include "intel_de.h" #include "intel_writeback_reg.h" +#define CSC_MAX_COEFF_REG_COUNT 6 +#define CSC_MAX_OFFSET_COUNT 3 + enum { WD_CAPTURE_4_PIX, WD_CAPTURE_2_PIX, @@ -54,6 +57,9 @@ static int intel_wb_get_format(int pixel_format) { int wb_format = -EINVAL; + DRM_INFO("Get format pixel format %x\n", + pixel_format); + switch (pixel_format) { case DRM_FORMAT_XBGR8888: case DRM_FORMAT_XRGB8888: @@ -70,6 +76,8 @@ static int intel_wb_get_format(int pixel_format) DRM_ERROR("unsupported pixel format %x!\n", pixel_format); } + DRM_INFO("Get format wb format %x\n", + wb_format); return wb_format; } @@ -84,7 +92,7 @@ static int intel_wb_verify_pix_format(int format) if (pix_format == wb_fmts[i]) return 0; - return true; + return -EINVAL; } static u32 intel_wb_get_stride(const struct intel_crtc_state *crtc_state, @@ -133,20 +141,28 @@ static int intel_wb_pin_fb(struct intel_wb *intel_wb, static void intel_configure_slicing_strategy(struct drm_i915_private *i915, struct intel_wb *intel_wb, - u32 *tmp) + u32 tmp) { - *tmp &= ~WD_STRAT_MASK; + drm_dbg_kms(&i915->drm, "WD_STREAMCAP_CTL: 0x%8x\n", tmp); + + tmp &= ~WD_STRAT_MASK; + drm_dbg_kms(&i915->drm, "WD_STREAMCAP_CTL: 0x%8x\n", tmp); if (intel_wb->slicing_strategy == 1) - *tmp |= WD_SLICING_STRAT_1_1; + tmp |= WD_SLICING_STRAT_1_1; else if (intel_wb->slicing_strategy == 2) - *tmp |= WD_SLICING_STRAT_2_1; + tmp |= WD_SLICING_STRAT_2_1; else if (intel_wb->slicing_strategy == 3) - *tmp |= WD_SLICING_STRAT_4_1; + tmp |= WD_SLICING_STRAT_4_1; else if (intel_wb->slicing_strategy == 4) - *tmp |= WD_SLICING_STRAT_8_1; + tmp |= WD_SLICING_STRAT_8_1; + + drm_dbg_kms(&i915->drm, "Slicing_strategy WD_STREAMCAP_CTL(0x%05x): 0x%08x\n", WD_STREAMCAP_CTL(intel_wb->trans).reg, tmp); intel_de_write(i915, WD_STREAMCAP_CTL(intel_wb->trans), - *tmp); + tmp); + drm_dbg_kms(&i915->drm, "WD Transocder: %05x, WD_STREAMCAP_CTL = %08x\n", + WD_STREAMCAP_CTL(intel_wb->trans).reg, intel_de_read(i915, WD_STREAMCAP_CTL(intel_wb->trans))); + } static enum drm_mode_status @@ -215,6 +231,7 @@ static bool intel_wb_get_hw_state(struct intel_encoder *encoder, struct intel_crtc *wb_crtc = intel_wb->wb_crtc; intel_wakeref_t wakeref; u32 tmp; + drm_dbg_kms(&dev_priv->drm, "intel_wb_get_hw_state\n"); if (!wb_crtc) return false; @@ -228,12 +245,14 @@ static bool intel_wb_get_hw_state(struct intel_encoder *encoder, tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); ret = tmp & WD_TRANS_ACTIVE; if (ret) { + drm_dbg_kms(&dev_priv->drm, "intel_wb_get_hw_state WD Transcode active\n"); *pipe = wb_crtc->pipe; return true; } out: intel_display_power_put(dev_priv, encoder->power_domain, wakeref); + drm_dbg_kms(&dev_priv->drm, "intel_wb_get_hw_state WD Transcode active fail\n"); return false; } @@ -363,6 +382,7 @@ void intel_wb_init(struct drm_i915_private *i915, enum transcoder trans) intel_wb->trans = trans; intel_wb->triggered_cap_mode = 1; intel_wb->frame_num = 1; + intel_wb->stream_cap = true; intel_wb->slicing_strategy = 1; encoder->get_config = intel_wb_get_config; encoder->compute_config = intel_wb_compute_config; @@ -421,6 +441,64 @@ static void intel_wb_writeback_complete(struct intel_wb *intel_wb, drm_writeback_signal_completion(wb_conn, status); } +static void wd_dump_details(struct intel_crtc *intel_crtc, struct intel_wb *intel_wb) +{ + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + //int wd_pipe = intel_crtc->pipe; + //int i = 0; + drm_dbg_kms(&dev_priv->drm, "\nDumping WD Transcoder details\n"); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_FUNC_CTL(TRANS_WD_FUNC_CTL_0) = %08x\n", + WD_TRANS_FUNC_CTL(intel_wb->trans).reg, intel_de_read(dev_priv, WD_TRANS_FUNC_CTL(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, Stride(WD_STRIDE_0) = %08x\n", + WD_STRIDE(intel_wb->trans).reg, intel_de_read(dev_priv, WD_STRIDE(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, Surf(WD_SURF_0) = %08x\n", + WD_SURF(intel_wb->trans).reg, intel_de_read(dev_priv, WD_SURF(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_TAIL_CFG = %08x\n", + WD_TAIL_CFG(intel_wb->trans).reg, intel_de_read(dev_priv, WD_TAIL_CFG(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_TAIL_CFG2 = %08x\n", + WD_TAIL_CFG2(intel_wb->trans).reg, intel_de_read(dev_priv, WD_TAIL_CFG2(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, IMR(WD_IMR_0) = %08x\n", + WD_IMR(intel_wb->trans).reg, intel_de_read(dev_priv, WD_IMR(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_IIR = %08x\n", + WD_IIR(intel_wb->trans).reg, intel_de_read(dev_priv, WD_IIR(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_FRAME_STATUS = %08x\n", + WD_FRAME_STATUS(intel_wb->trans).reg, intel_de_read(dev_priv, WD_FRAME_STATUS(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, HTotal(TRANS_HTOTAL_WD0) = %08x\n", + HTOTAL(intel_wb->trans).reg, intel_de_read(dev_priv, HTOTAL(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, VTotal(TRANS_VTOTAL_WD0) = %08x\n", + VTOTAL(intel_wb->trans).reg, intel_de_read(dev_priv, VTOTAL(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transcoder: %05x, Trans_Conf(TRANS_CONF_WD0) = %08x\n", + PIPECONF(intel_wb->trans).reg, intel_de_read(dev_priv, PIPECONF(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_27_M_0 = %08x\n", + WD_27_M(intel_wb->trans).reg, intel_de_read(dev_priv, WD_27_M(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_27_N_0 = %08x\n", + WD_27_N(intel_wb->trans).reg, intel_de_read(dev_priv, WD_27_N(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_STREAMCAP_CTL = %08x\n", + WD_STREAMCAP_CTL(intel_wb->trans).reg, intel_de_read(dev_priv, WD_STREAMCAP_CTL(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_VFID = %08x\n", + WD_VFID(intel_wb->trans).reg, intel_de_read(dev_priv, WD_VFID(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_CHICKEN = %08x\n", + WD_CHICKEN(intel_wb->trans).reg, intel_de_read(dev_priv, WD_CHICKEN(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, DEBUG_1 = %08x\n", + WD_DEBUG1(intel_wb->trans).reg, intel_de_read(dev_priv, WD_DEBUG1(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, DEBUG_2 = %08x\n", + WD_DEBUG2(intel_wb->trans).reg, intel_de_read(dev_priv, WD_DEBUG2(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_PERF_CNT = %08x\n", + WD_PERF_CNT(intel_wb->trans).reg, intel_de_read(dev_priv, WD_PERF_CNT(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_TAIL_MSG_DBG = %08x\n", + WD_TAIL_MSG_DBG(intel_wb->trans).reg, intel_de_read(dev_priv, WD_TAIL_MSG_DBG(intel_wb->trans))); + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, Notific(WD_MSG_MASK_0) = %08x\n", + WD_MSG_MASK(intel_wb->trans).reg, intel_de_read(dev_priv, WD_MSG_MASK(intel_wb->trans))); + + drm_dbg_kms(&dev_priv->drm, "WD Transocder: %05x, WD_CTL_MSG_DBG = %08x\n", + WD_CTL_MSG_DBG(intel_wb->trans).reg, intel_de_read(dev_priv, WD_CTL_MSG_DBG(intel_wb->trans))); + +} + +#if WB_DUMP_DEBUG +static int wd_dump_first_time = 1; +#endif + static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state, @@ -434,6 +512,8 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, int ret; u32 stride, tmp; u16 hactive, vactive; + drm_dbg_kms(&dev_priv->drm, + "intel_wb_setup_transcoder start\n"); fb = job->fb; wb_fb_obj = fb->obj[0]; @@ -441,7 +521,15 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, drm_dbg_kms(&dev_priv->drm, "No framebuffer gem object created\n"); return -EINVAL; } - +#if WB_DUMP_DEBUG + if(wd_dump_first_time) + { + drm_dbg_kms(&dev_priv->drm, "wd_go FIRST TIME!!!!!!!!!!!!!!!!!!!!!------------------------->>>>>>>>>>>>> \n"); + wd_dump_details(intel_crtc, intel_wb); + drm_dbg_kms(&dev_priv->drm, "wd_go AFTER FIRST TIME!!!!!!!!!!!!!!!-------------------------<<<<<<<<<<<<< \n"); + wd_dump_first_time = 0; + } +#endif ret = intel_wb_pin_fb(intel_wb, fb); drm_WARN_ON(&dev_priv->drm, ret != 0); /* Write stride and surface registers in that particular order */ @@ -450,32 +538,45 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, tmp = intel_de_read(dev_priv, WD_STRIDE(intel_wb->trans)); tmp &= ~WD_STRIDE_MASK; tmp |= (stride << WD_STRIDE_SHIFT); + drm_dbg_kms(&dev_priv->drm, "WD_STRIDE: 0x%05x, tmp: 0x%08x\n", WD_STRIDE(intel_wb->trans).reg, tmp); intel_de_write(dev_priv, WD_STRIDE(intel_wb->trans), tmp); tmp = intel_de_read(dev_priv, WD_SURF(intel_wb->trans)); + drm_dbg_kms(&dev_priv->drm, "WD_SURF: 0x%05x, tmp: 0x%08x\n", WD_SURF(intel_wb->trans).reg, tmp); intel_de_write(dev_priv, WD_SURF(intel_wb->trans), i915_ggtt_offset(intel_wb->vma)); + drm_dbg_kms(&dev_priv->drm, "WD_SURF: 0x%05x, i915_ggtt_offset: 0x%08x\n", WD_SURF(intel_wb->trans).reg, i915_ggtt_offset(intel_wb->vma)); tmp = intel_de_read_fw(dev_priv, WD_IIR(intel_wb->trans)); + drm_dbg_kms(&dev_priv->drm, "WD_IIR: 0x%05x, tmp: 0x%08x\n", WD_IIR(intel_wb->trans).reg, tmp); + intel_de_write_fw(dev_priv, WD_IIR(intel_wb->trans), tmp); tmp = ~(WD_GTT_FAULT_INT | WD_WRITE_COMPLETE_INT | WD_FRAME_COMPLETE_INT | WD_VBLANK_INT | WD_OVERRUN_INT | WD_CAPTURING_INT); + drm_dbg_kms(&dev_priv->drm, "WD_IMR: 0x%05x, tmp: 0x08%x\n", WD_IMR(intel_wb->trans).reg, tmp); + intel_de_write_fw(dev_priv, WD_IMR(intel_wb->trans), tmp); if (intel_wb->stream_cap) { tmp = intel_de_read(dev_priv, WD_STREAMCAP_CTL(intel_wb->trans)); tmp |= WD_STREAM_CAP_MODE_EN; - intel_configure_slicing_strategy(dev_priv, intel_wb, &tmp); + drm_dbg_kms(&dev_priv->drm, "WD_STREAMCAP_CTL: 0x%8x\n", tmp); + intel_configure_slicing_strategy(dev_priv, intel_wb, tmp); } hactive = pipe_config->uapi.mode.hdisplay; vactive = pipe_config->uapi.mode.vdisplay; tmp = intel_de_read(dev_priv, HTOTAL(intel_wb->trans)); + drm_dbg_kms(&dev_priv->drm, "HTOTAL: 0x%05x, tmp: 0x%08x\n", HTOTAL(intel_wb->trans).reg, tmp); + drm_dbg_kms(&dev_priv->drm, "hactive: 0x%08x\n", hactive); + tmp = intel_de_read(dev_priv, VTOTAL(intel_wb->trans)); + drm_dbg_kms(&dev_priv->drm, "VTOTAL: 0x%05x, tmp: 0x%08x\n", VTOTAL(intel_wb->trans).reg, tmp); + drm_dbg_kms(&dev_priv->drm, "vactive: 0x%08x\n", vactive); /* minimum hactive as per bspec: 64 pixels */ if (hactive < 64) @@ -523,6 +624,7 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, /* select input pipe */ tmp &= ~WD_INPUT_SELECT_MASK; + pipe = PIPE_A; switch (pipe) { default: fallthrough; @@ -543,20 +645,30 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, /* enable DDI buffer */ if (!(tmp & TRANS_WD_FUNC_ENABLE)) tmp |= TRANS_WD_FUNC_ENABLE; + drm_dbg_kms(&dev_priv->drm, "WD_TRANS_FUNC_CTL: 0x%05x, tmp: 0x%08x\n", WD_TRANS_FUNC_CTL(intel_wb->trans).reg, tmp); intel_de_write(dev_priv, WD_TRANS_FUNC_CTL(intel_wb->trans), tmp); +#if WB_DUMP_DEBUG + drm_dbg_kms(&dev_priv->drm, "wd_go5-A1 - Reg Dump Before Enable\n"); + drm_dbg_kms(&dev_priv->drm, "wd_go5-A2 ------------------------------------------------------------\n"); + wd_dump_details(intel_crtc, intel_wb); + drm_dbg_kms(&dev_priv->drm, "wd_go5-A3 ------------------------------------------------------------\n"); +#endif tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); + drm_dbg_kms(&dev_priv->drm, "PIPECONF: 0x%05x\n", PIPECONF(intel_wb->trans).reg); ret = tmp & WD_TRANS_ACTIVE; if (!ret) { /* enable the transcoder */ tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); tmp |= WD_TRANS_ENABLE; + drm_dbg_kms(&dev_priv->drm, "PIPECONF: 0x%08x\n", tmp); + intel_de_write(dev_priv, PIPECONF(intel_wb->trans), tmp); /* wait for transcoder to be enabled */ if (intel_de_wait_for_set(dev_priv, PIPECONF(intel_wb->trans), - WD_TRANS_ACTIVE, 10)) + WD_TRANS_ACTIVE, 100)) drm_err(&dev_priv->drm, "WD transcoder could not be enabled\n"); } @@ -573,6 +685,8 @@ static int intel_wb_capture(struct intel_wb *intel_wb, int ret = 0, status = 0; struct intel_crtc *wb_crtc = intel_wb->wb_crtc; unsigned long flags; + drm_dbg_kms(&i915->drm, + "intel_wb_capture start\n"); if (!job->out_fence) drm_dbg_kms(&i915->drm, "Not able to get out_fence for job\n"); @@ -595,6 +709,7 @@ static int intel_wb_capture(struct intel_wb *intel_wb, tmp |= START_TRIGGER_FRAME; tmp &= ~WD_FRAME_NUMBER_MASK; tmp |= intel_wb->frame_num; + drm_dbg_kms(&i915->drm, "Capture WD_TRANS_FUNC_CTL: 0x%8x, tmp: 0x%8x\n", WD_TRANS_FUNC_CTL(intel_wb->trans).reg, tmp); intel_de_write_fw(i915, WD_TRANS_FUNC_CTL(intel_wb->trans), tmp); if (!intel_de_wait_for_set(i915, WD_IIR(intel_wb->trans), @@ -619,7 +734,7 @@ static int intel_wb_capture(struct intel_wb *intel_wb, wb_crtc->wb.e = NULL; } else { drm_err(&i915->drm, "Event NULL! %p, %p\n", &i915->drm, - wb_crtc); + wb_crtc); } if (!intel_get_writeback_job_from_queue(intel_wb)) intel_wb_disable_capture(intel_wb); diff --git a/drivers/gpu/drm/i915/display/intel_wb.h b/drivers/gpu/drm/i915/display/intel_wb.h index 7719c03bba150..b4049a3b44e85 100644 --- a/drivers/gpu/drm/i915/display/intel_wb.h +++ b/drivers/gpu/drm/i915/display/intel_wb.h @@ -11,6 +11,7 @@ #include "intel_display_types.h" #define I915_MAX_WD_TANSCODERS 2 +#define WB_DUMP_DEBUG 0 struct intel_wb { struct intel_encoder base; diff --git a/drivers/gpu/drm/i915/display/intel_writeback_reg.h b/drivers/gpu/drm/i915/display/intel_writeback_reg.h index 955ad7596726a..9a7e18226dc96 100644 --- a/drivers/gpu/drm/i915/display/intel_writeback_reg.h +++ b/drivers/gpu/drm/i915/display/intel_writeback_reg.h @@ -28,7 +28,7 @@ #define STOP_TRIGGER_FRAME (1 << 28) #define WD_CTL_POINTER_ETEH (0 << 18) #define WD_CTL_POINTER_ETDH (1 << 18) -#define WD_CTL_POINTER_DTDH (2 << 18) +#define WD_CTL_POINTER_DTDH (3 << 18) #define WD_INPUT_SELECT_MASK (7 << 12) #define WD_INPUT_PIPE_A (0 << 12) #define WD_INPUT_PIPE_B (5 << 12) @@ -92,8 +92,8 @@ _WD_IIR_0,\ _WD_IIR_1) -#define _WD_FRAME_STATUS_0 0x6e56b -#define _WD_FRAME_STATUS_1 0x6ed6b +#define _WD_FRAME_STATUS_0 0x6e568 +#define _WD_FRAME_STATUS_1 0x6ed68 #define WD_FRAME_STATUS(tc) _MMIO_WD(tc,\ _WD_FRAME_STATUS_0,\ _WD_FRAME_STATUS_1) @@ -125,4 +125,77 @@ #define WD_TAIL_CFG(tc) _MMIO_WD(tc,\ _WD_TAIL_CFG_0,\ _WD_TAIL_CFG_1) + +#define _WD_TAIL_CFG2_0 0x6e52c +#define _WD_TAIL_CFG2_1 0x6ed2c +#define WD_TAIL_CFG2(tc) _MMIO_WD(tc,\ + _WD_TAIL_CFG2_0,\ + _WD_TAIL_CFG2_1) + +#define _WD_TAIL_CFG_0 0x6e520 +#define _WD_TAIL_CFG_1 0x6ed20 +#define WD_TAIL_CFG(tc) _MMIO_WD(tc,\ + _WD_TAIL_CFG_0,\ + _WD_TAIL_CFG_1) + +#define _WD_TAIL_CFG_0 0x6e520 +#define _WD_TAIL_CFG_1 0x6ed20 +#define WD_TAIL_CFG(tc) _MMIO_WD(tc,\ + _WD_TAIL_CFG_0,\ + _WD_TAIL_CFG_1) + +#define _WD_TAIL_CFG2_0 0x6e52c +#define _WD_TAIL_CFG2_1 0x6ed2c +#define WD_TAIL_CFG2(tc) _MMIO_WD(tc,\ + _WD_TAIL_CFG2_0,\ + _WD_TAIL_CFG2_1) + +#define _WD_VFID_0 0x6e518 +#define _WD_VFID_1 0x6ed18 +#define WD_VFID(tc) _MMIO_WD(tc,\ + _WD_VFID_0,\ + _WD_VFID_1) + +#define _WD_CHICKEN_0 0x6e574 +#define _WD_CHICKEN_1 0x6ed74 +#define WD_CHICKEN(tc) _MMIO_WD(tc,\ + _WD_CHICKEN_0,\ + _WD_CHICKEN_1) + +#define _WD_DEBUG1_0 0x6e544 +#define _WD_DEBUG1_1 0x6ed44 +#define WD_DEBUG1(tc) _MMIO_WD(tc,\ + _WD_DEBUG1_0,\ + _WD_DEBUG1_1) + +#define _WD_DEBUG2_0 0x6e548 +#define _WD_DEBUG2_1 0x6ed48 +#define WD_DEBUG2(tc) _MMIO_WD(tc,\ + _WD_DEBUG2_0,\ + _WD_DEBUG2_1) + +#define _WD_PERF_CNT_0 0x6e55c +#define _WD_PERF_CNT_1 0x6ed5c +#define WD_PERF_CNT(tc) _MMIO_WD(tc,\ + _WD_PERF_CNT_0,\ + _WD_PERF_CNT_1) + +#define _WD_TAIL_MSG_DBG_0 0x6e5c0 +#define _WD_TAIL_MSG_DBG_1 0x6edc0 +#define WD_TAIL_MSG_DBG(tc) _MMIO_WD(tc,\ + _WD_TAIL_MSG_DBG_0,\ + _WD_TAIL_MSG_DBG_1) + +#define _WD_CTL_MSG_DBG_0 0x6e5cc +#define _WD_CTL_MSG_DBG_1 0x6edcc +#define WD_CTL_MSG_DBG(tc) _MMIO_WD(tc,\ + _WD_CTL_MSG_DBG_0,\ + _WD_CTL_MSG_DBG_1) + +#define _WD_MSG_MASK_0 0x6e570 +#define _WD_MSG_MASK_1 0x6ed70 +#define WD_MSG_MASK(tc) _MMIO_WD(tc,\ + _WD_MSG_MASK_0,\ + _WD_MSG_MASK_1) + #endif /* _INTEL_WRITEBACK_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index df82a089d7d33..c447593f632cc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7716,6 +7716,7 @@ enum skl_power_gate { #define _PIPE_B_CSC_POSTOFF_LO 0x49148 #define PIPE_CSC_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_RY_GY_REGIDX(pipe, n) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY+n, _PIPE_B_CSC_COEFF_RY_GY+n) #define PIPE_CSC_COEFF_BY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) #define PIPE_CSC_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) #define PIPE_CSC_COEFF_BU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) @@ -7726,6 +7727,7 @@ enum skl_power_gate { #define PIPE_CSC_PREOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) #define PIPE_CSC_PREOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) #define PIPE_CSC_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_HI_REGIDX(pipe, n) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI+n, _PIPE_B_CSC_POSTOFF_HI+n) #define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) #define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) From 5963de952425306ae95b5461b252899140d9bed2 Mon Sep 17 00:00:00 2001 From: "Jia, Lin A" Date: Thu, 20 Feb 2025 09:42:09 +0800 Subject: [PATCH 5/5] WD writeback dump with one crtc 1. Enable WB enconders cloneable to avoid encoder cloning check fail. 2. Fixed get crtc dpll fault for WB connector. 3. Correct WB TRANS registers address. 4. Add WB capture frame traces. Signed-off-by: Jialin --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 4 +- .../drm/i915/display/intel_display_trace.h | 64 +++++++++ drivers/gpu/drm/i915/display/intel_dpll.c | 6 - drivers/gpu/drm/i915/display/intel_wb.c | 128 +++++++++++++++--- .../drm/i915/display/intel_writeback_reg.h | 7 + 6 files changed, 181 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 63dc653e84e0b..95f9d42145c2b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4364,7 +4364,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->type = INTEL_OUTPUT_DDI; encoder->power_domain = intel_display_power_ddi_lanes_domain(dev_priv, port); encoder->port = port; - encoder->cloneable = 0; + encoder->cloneable = 1 << INTEL_OUTPUT_WB; encoder->pipe_mask = ~0; if (IS_DG2(dev_priv)) { diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 52c1cdcbe37b2..1db69b2b56f40 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1077,7 +1077,9 @@ intel_get_crtc_new_encoder(const struct intel_atomic_state *state, continue; encoder = to_intel_encoder(connector_state->best_encoder); - num_encoders++; + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + num_encoders++; } drm_WARN(encoder->base.dev, num_encoders != 1, diff --git a/drivers/gpu/drm/i915/display/intel_display_trace.h b/drivers/gpu/drm/i915/display/intel_display_trace.h index 2dd5a4b7f5d8a..584c80f02cf24 100644 --- a/drivers/gpu/drm/i915/display/intel_display_trace.h +++ b/drivers/gpu/drm/i915/display/intel_display_trace.h @@ -579,6 +579,70 @@ TRACE_EVENT(intel_frontbuffer_flush, __entry->frontbuffer_bits, __entry->origin) ); +TRACE_EVENT(intel_wb_capture_start, + TP_PROTO(struct intel_crtc *crtc), + TP_ARGS(crtc), + + TP_STRUCT__entry( + __field(enum pipe, pipe) + __field(u32, frame) + __field(u32, scanline) + ), + + TP_fast_assign( + __entry->pipe = crtc->pipe; + __entry->frame = intel_crtc_get_vblank_counter(crtc); + __entry->scanline = intel_get_crtc_scanline(crtc); + ), + + TP_printk("pipe %c, frame=%u, scanline=%u", + pipe_name(__entry->pipe), __entry->frame, + __entry->scanline) +); + +TRACE_EVENT(intel_wb_capture_end, + TP_PROTO(struct intel_crtc *crtc), + TP_ARGS(crtc), + + TP_STRUCT__entry( + __field(enum pipe, pipe) + __field(u32, frame) + __field(u32, scanline) + ), + + TP_fast_assign( + __entry->pipe = crtc->pipe; + __entry->frame = intel_crtc_get_vblank_counter(crtc); + __entry->scanline = intel_get_crtc_scanline(crtc); + ), + + TP_printk("pipe %c, frame=%u, scanline=%u", + pipe_name(__entry->pipe), __entry->frame, + __entry->scanline) +); + +TRACE_EVENT(intel_wb_vblank_event, + TP_PROTO(struct intel_crtc *crtc), + TP_ARGS(crtc), + + TP_STRUCT__entry( + __field(enum pipe, pipe) + __field(u32, frame) + __field(u32, scanline) + ), + + TP_fast_assign( + __entry->pipe = crtc->pipe; + __entry->frame = intel_crtc_get_vblank_counter(crtc); + __entry->scanline = intel_get_crtc_scanline(crtc); + ), + + TP_printk("pipe %c, frame=%u, scanline=%u", + pipe_name(__entry->pipe), __entry->frame, + __entry->scanline) + +); + #endif /* __INTEL_DISPLAY_TRACE_H__ */ /* This part must be outside protection */ diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index fdb104091cf4b..b15ba78d64d62 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -940,9 +940,6 @@ static int hsw_crtc_compute_clock(struct intel_atomic_state *state, intel_get_crtc_new_encoder(state, crtc_state); int ret; - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_WB)) - return 0; - if (DISPLAY_VER(dev_priv) < 11 && intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) return 0; @@ -971,9 +968,6 @@ static int hsw_crtc_get_shared_dpll(struct intel_atomic_state *state, struct intel_encoder *encoder = intel_get_crtc_new_encoder(state, crtc_state); - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_WB)) - return 0; - if (DISPLAY_VER(dev_priv) < 11 && intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) return 0; diff --git a/drivers/gpu/drm/i915/display/intel_wb.c b/drivers/gpu/drm/i915/display/intel_wb.c index cbf7f77753d16..e16ceba8ba6d4 100644 --- a/drivers/gpu/drm/i915/display/intel_wb.c +++ b/drivers/gpu/drm/i915/display/intel_wb.c @@ -13,6 +13,7 @@ #include "intel_fb_pin.h" #include "intel_de.h" #include "intel_writeback_reg.h" +#include "intel_display_trace.h" #define CSC_MAX_COEFF_REG_COUNT 6 #define CSC_MAX_OFFSET_COUNT 3 @@ -22,6 +23,68 @@ enum { WD_CAPTURE_2_PIX, } wb_capture_format; +/* copy from drm_edid.c */ +static const struct drm_display_mode drm_dmt_modes[] = { + /* 640x480@60Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 489, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 800x600@60Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1024x768@60Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, + 1184, 1344, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1280x768@60Hz */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344, + 1472, 1664, 0, 768, 771, 778, 798, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x768@85Hz */ + { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360, + 1496, 1712, 0, 768, 771, 778, 809, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x1024@60Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328, + 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1280x1024@85Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344, + 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1400x1050@60Hz */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488, + 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1400x1050@85Hz */ + { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504, + 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@60Hz */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664, + 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 1600x1200@85Hz */ + { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664, + 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + /* 0x52 - 1920x1080@60Hz */ + { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER|DRM_MODE_TYPE_PREFERRED, + 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1920x1200@60Hz RB */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, + 154000, 1920, 1968, + 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, + /* 1920x1200@60Hz */ + { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056, + 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, +}; + struct drm_writeback_job *intel_get_writeback_job_from_queue(struct intel_wb *intel_wb) { @@ -57,9 +120,6 @@ static int intel_wb_get_format(int pixel_format) { int wb_format = -EINVAL; - DRM_INFO("Get format pixel format %x\n", - pixel_format); - switch (pixel_format) { case DRM_FORMAT_XBGR8888: case DRM_FORMAT_XRGB8888: @@ -174,7 +234,25 @@ intel_wb_mode_valid(struct drm_connector *connector, static int intel_wb_get_modes(struct drm_connector *connector) { - return 0; + int i; + int num_modes = 0; + + connector->status = connector_status_disconnected; + + for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) { + struct drm_display_mode *nmode; + + nmode = drm_mode_duplicate(connector->dev, + &drm_dmt_modes[i]); + if (nmode) { + drm_mode_probed_add(connector, nmode); + num_modes++; + } + else + DRM_ERROR("duplicate mode error!\n"); + } + + return num_modes; } static void intel_wb_get_config(struct intel_encoder *encoder, @@ -231,7 +309,6 @@ static bool intel_wb_get_hw_state(struct intel_encoder *encoder, struct intel_crtc *wb_crtc = intel_wb->wb_crtc; intel_wakeref_t wakeref; u32 tmp; - drm_dbg_kms(&dev_priv->drm, "intel_wb_get_hw_state\n"); if (!wb_crtc) return false; @@ -245,14 +322,14 @@ static bool intel_wb_get_hw_state(struct intel_encoder *encoder, tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); ret = tmp & WD_TRANS_ACTIVE; if (ret) { - drm_dbg_kms(&dev_priv->drm, "intel_wb_get_hw_state WD Transcode active\n"); + drm_dbg_kms(&dev_priv->drm, "WD_ intel_wb_get_hw_state WD Transcode active, wb_crtc->pipe = %d\n", wb_crtc->pipe); *pipe = wb_crtc->pipe; return true; } out: intel_display_power_put(dev_priv, encoder->power_domain, wakeref); - drm_dbg_kms(&dev_priv->drm, "intel_wb_get_hw_state WD Transcode active fail\n"); + drm_dbg_kms(&dev_priv->drm, "WD_ intel_wb_get_hw_state WD Transcode active fail\n"); return false; } @@ -388,7 +465,7 @@ void intel_wb_init(struct drm_i915_private *i915, enum transcoder trans) encoder->compute_config = intel_wb_compute_config; encoder->get_hw_state = intel_wb_get_hw_state; encoder->type = INTEL_OUTPUT_WB; - encoder->cloneable = 0; + encoder->cloneable = 1 << INTEL_OUTPUT_DDI; encoder->pipe_mask = ~0; encoder->power_domain = POWER_DOMAIN_TRANSCODER_B; encoder->get_power_domains = intel_wb_get_power_domains; @@ -512,8 +589,9 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, int ret; u32 stride, tmp; u16 hactive, vactive; + drm_dbg_kms(&dev_priv->drm, - "intel_wb_setup_transcoder start\n"); + "WD_ intel_wb_setup_transcoder pipe =%d start\n", pipe); fb = job->fb; wb_fb_obj = fb->obj[0]; @@ -570,20 +648,20 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, hactive = pipe_config->uapi.mode.hdisplay; vactive = pipe_config->uapi.mode.vdisplay; - tmp = intel_de_read(dev_priv, HTOTAL(intel_wb->trans)); - drm_dbg_kms(&dev_priv->drm, "HTOTAL: 0x%05x, tmp: 0x%08x\n", HTOTAL(intel_wb->trans).reg, tmp); + tmp = intel_de_read(dev_priv, TRANS_HTOTAL_WD0); + drm_dbg_kms(&dev_priv->drm, "HTOTAL: 0x%05x, tmp: 0x%08x\n", TRANS_HTOTAL_WD0.reg, tmp); drm_dbg_kms(&dev_priv->drm, "hactive: 0x%08x\n", hactive); - tmp = intel_de_read(dev_priv, VTOTAL(intel_wb->trans)); - drm_dbg_kms(&dev_priv->drm, "VTOTAL: 0x%05x, tmp: 0x%08x\n", VTOTAL(intel_wb->trans).reg, tmp); + tmp = intel_de_read(dev_priv, TRANS_VTOTAL_WD0); + drm_dbg_kms(&dev_priv->drm, "VTOTAL: 0x%05x, tmp: 0x%08x\n", TRANS_VTOTAL_WD0.reg, tmp); drm_dbg_kms(&dev_priv->drm, "vactive: 0x%08x\n", vactive); /* minimum hactive as per bspec: 64 pixels */ if (hactive < 64) drm_err(&dev_priv->drm, "hactive is less then 64 pixels\n"); - intel_de_write(dev_priv, HTOTAL(intel_wb->trans), hactive - 1); - intel_de_write(dev_priv, VTOTAL(intel_wb->trans), vactive - 1); + intel_de_write(dev_priv, TRANS_HTOTAL_WD0, hactive - 1); + intel_de_write(dev_priv, TRANS_VTOTAL_WD0, vactive - 1); tmp = intel_de_read(dev_priv, WD_TRANS_FUNC_CTL(intel_wb->trans)); /* select pixel format */ @@ -624,7 +702,7 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, /* select input pipe */ tmp &= ~WD_INPUT_SELECT_MASK; - pipe = PIPE_A; + switch (pipe) { default: fallthrough; @@ -655,19 +733,19 @@ static int intel_wb_setup_transcoder(struct intel_wb *intel_wb, wd_dump_details(intel_crtc, intel_wb); drm_dbg_kms(&dev_priv->drm, "wd_go5-A3 ------------------------------------------------------------\n"); #endif - tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); - drm_dbg_kms(&dev_priv->drm, "PIPECONF: 0x%05x\n", PIPECONF(intel_wb->trans).reg); + tmp = intel_de_read(dev_priv, TRANS_CONF_WD0); + drm_dbg_kms(&dev_priv->drm, "PIPECONF: 0x%05x\n", TRANS_CONF_WD0.reg); ret = tmp & WD_TRANS_ACTIVE; if (!ret) { /* enable the transcoder */ - tmp = intel_de_read(dev_priv, PIPECONF(intel_wb->trans)); + tmp = intel_de_read(dev_priv, TRANS_CONF_WD0); tmp |= WD_TRANS_ENABLE; drm_dbg_kms(&dev_priv->drm, "PIPECONF: 0x%08x\n", tmp); - intel_de_write(dev_priv, PIPECONF(intel_wb->trans), tmp); + intel_de_write(dev_priv, TRANS_CONF_WD0, tmp); /* wait for transcoder to be enabled */ - if (intel_de_wait_for_set(dev_priv, PIPECONF(intel_wb->trans), + if (intel_de_wait_for_set(dev_priv, TRANS_CONF_WD0, WD_TRANS_ACTIVE, 100)) drm_err(&dev_priv->drm, "WD transcoder could not be enabled\n"); } @@ -685,8 +763,9 @@ static int intel_wb_capture(struct intel_wb *intel_wb, int ret = 0, status = 0; struct intel_crtc *wb_crtc = intel_wb->wb_crtc; unsigned long flags; + drm_dbg_kms(&i915->drm, - "intel_wb_capture start\n"); + "WD_ intel_wb_capture start\n"); if (!job->out_fence) drm_dbg_kms(&i915->drm, "Not able to get out_fence for job\n"); @@ -725,6 +804,7 @@ static int intel_wb_capture(struct intel_wb *intel_wb, } intel_wb_writeback_complete(intel_wb, job, status); + if (wb_crtc->wb.e) { spin_lock_irqsave(&i915->drm.event_lock, flags); drm_dbg_kms(&i915->drm, "send %p\n", wb_crtc->wb.e); @@ -750,6 +830,7 @@ void intel_wb_enable_capture(struct intel_crtc_state *pipe_config, drm_connector_to_writeback(conn_state->connector); struct intel_wb *intel_wb = wb_conn_to_intel_wb(wb_conn); struct drm_writeback_job *job; + struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->uapi.crtc); job = intel_get_writeback_job_from_queue(intel_wb); if (!job) { @@ -758,8 +839,11 @@ void intel_wb_enable_capture(struct intel_crtc_state *pipe_config, return; } + trace_intel_wb_capture_start(intel_crtc); intel_wb_capture(intel_wb, pipe_config, conn_state, job); + trace_intel_wb_capture_end(intel_crtc); + intel_wb->frame_num += 1; } diff --git a/drivers/gpu/drm/i915/display/intel_writeback_reg.h b/drivers/gpu/drm/i915/display/intel_writeback_reg.h index 9a7e18226dc96..197181ad4bcd9 100644 --- a/drivers/gpu/drm/i915/display/intel_writeback_reg.h +++ b/drivers/gpu/drm/i915/display/intel_writeback_reg.h @@ -46,6 +46,13 @@ #define WD_FRAME_NUMBER_MASK 15 +#define TRANS_HTOTAL_WD0 _MMIO(0x6e000) +#define TRANS_VTOTAL_WD0 _MMIO(0x6e00c) + +#define TRANS_CONF_WD0 _MMIO(0x7e008) +#define TRANS_CONF_WD_ENABLE (1<<31) +#define TRANS_CONF_WD_ENABLED (1<<30) + #define _WD_STRIDE_0 0x6e510 #define _WD_STRIDE_1 0x6ed10 #define WD_STRIDE(tc) _MMIO_WD(tc,\