1470022b5SVille Syrjälä // SPDX-License-Identifier: MIT 2470022b5SVille Syrjälä /* 3470022b5SVille Syrjälä * Copyright © 2025 Intel Corporation 4470022b5SVille Syrjälä */ 5470022b5SVille Syrjälä 6470022b5SVille Syrjälä #include <linux/pci.h> 7470022b5SVille Syrjälä 8470022b5SVille Syrjälä #include <drm/drm_print.h> 9470022b5SVille Syrjälä 10470022b5SVille Syrjälä #include "i915_utils.h" 11470022b5SVille Syrjälä #include "intel_step.h" 12470022b5SVille Syrjälä #include "intel_crtc.h" 13470022b5SVille Syrjälä #include "intel_de.h" 14470022b5SVille Syrjälä #include "intel_display_core.h" 15470022b5SVille Syrjälä #include "intel_display_types.h" 16470022b5SVille Syrjälä #include "intel_flipq.h" 17470022b5SVille Syrjälä #include "intel_dmc.h" 18470022b5SVille Syrjälä #include "intel_dmc_regs.h" 19470022b5SVille Syrjälä #include "intel_dsb.h" 20470022b5SVille Syrjälä #include "intel_vblank.h" 21470022b5SVille Syrjälä #include "intel_vrr.h" 22470022b5SVille Syrjälä 23470022b5SVille Syrjälä /** 24470022b5SVille Syrjälä * DOC: DMC Flip Queue 25470022b5SVille Syrjälä * 26470022b5SVille Syrjälä * A flip queue is a ring buffer implemented by the pipe DMC firmware. 27470022b5SVille Syrjälä * The driver inserts entries into the queues to be executed by the 28470022b5SVille Syrjälä * pipe DMC at a specified presentation timestamp (PTS). 29470022b5SVille Syrjälä * 30470022b5SVille Syrjälä * Each pipe DMC provides several queues: 31470022b5SVille Syrjälä * 32470022b5SVille Syrjälä * - 1 general queue (two DSB buffers executed per entry) 33470022b5SVille Syrjälä * - 3 plane queues (one DSB buffer executed per entry) 34470022b5SVille Syrjälä * - 1 fast queue (deprecated) 35470022b5SVille Syrjälä */ 36470022b5SVille Syrjälä 37470022b5SVille Syrjälä #define for_each_flipq(flipq_id) \ 38470022b5SVille Syrjälä for ((flipq_id) = INTEL_FLIPQ_PLANE_1; (flipq_id) < MAX_INTEL_FLIPQ; (flipq_id)++) 39470022b5SVille Syrjälä 40470022b5SVille Syrjälä static int intel_flipq_offset(enum intel_flipq_id flipq_id) 41470022b5SVille Syrjälä { 42470022b5SVille Syrjälä switch (flipq_id) { 43470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_1: 44470022b5SVille Syrjälä return 0x008; 45470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_2: 46470022b5SVille Syrjälä return 0x108; 47470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_3: 48470022b5SVille Syrjälä return 0x208; 49470022b5SVille Syrjälä case INTEL_FLIPQ_GENERAL: 50470022b5SVille Syrjälä return 0x308; 51470022b5SVille Syrjälä case INTEL_FLIPQ_FAST: 52470022b5SVille Syrjälä return 0x3c8; 53470022b5SVille Syrjälä default: 54470022b5SVille Syrjälä MISSING_CASE(flipq_id); 55470022b5SVille Syrjälä return 0; 56470022b5SVille Syrjälä } 57470022b5SVille Syrjälä } 58470022b5SVille Syrjälä 59470022b5SVille Syrjälä static int intel_flipq_size_dw(enum intel_flipq_id flipq_id) 60470022b5SVille Syrjälä { 61470022b5SVille Syrjälä switch (flipq_id) { 62470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_1: 63470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_2: 64470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_3: 65470022b5SVille Syrjälä return 64; 66470022b5SVille Syrjälä case INTEL_FLIPQ_GENERAL: 67470022b5SVille Syrjälä case INTEL_FLIPQ_FAST: 68470022b5SVille Syrjälä return 48; 69470022b5SVille Syrjälä default: 70470022b5SVille Syrjälä MISSING_CASE(flipq_id); 71470022b5SVille Syrjälä return 1; 72470022b5SVille Syrjälä } 73470022b5SVille Syrjälä } 74470022b5SVille Syrjälä 75470022b5SVille Syrjälä static int intel_flipq_elem_size_dw(enum intel_flipq_id flipq_id) 76470022b5SVille Syrjälä { 77470022b5SVille Syrjälä switch (flipq_id) { 78470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_1: 79470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_2: 80470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_3: 81470022b5SVille Syrjälä return 4; 82470022b5SVille Syrjälä case INTEL_FLIPQ_GENERAL: 83470022b5SVille Syrjälä case INTEL_FLIPQ_FAST: 84470022b5SVille Syrjälä return 6; 85470022b5SVille Syrjälä default: 86470022b5SVille Syrjälä MISSING_CASE(flipq_id); 87470022b5SVille Syrjälä return 1; 88470022b5SVille Syrjälä } 89470022b5SVille Syrjälä } 90470022b5SVille Syrjälä 91470022b5SVille Syrjälä static int intel_flipq_size_entries(enum intel_flipq_id flipq_id) 92470022b5SVille Syrjälä { 93470022b5SVille Syrjälä return intel_flipq_size_dw(flipq_id) / intel_flipq_elem_size_dw(flipq_id); 94470022b5SVille Syrjälä } 95470022b5SVille Syrjälä 96470022b5SVille Syrjälä static void intel_flipq_crtc_init(struct intel_crtc *crtc) 97470022b5SVille Syrjälä { 98470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 99470022b5SVille Syrjälä enum intel_flipq_id flipq_id; 100470022b5SVille Syrjälä 101470022b5SVille Syrjälä for_each_flipq(flipq_id) { 102470022b5SVille Syrjälä struct intel_flipq *flipq = &crtc->flipq[flipq_id]; 103470022b5SVille Syrjälä 104470022b5SVille Syrjälä flipq->start_mmioaddr = intel_pipedmc_start_mmioaddr(crtc) + intel_flipq_offset(flipq_id); 105470022b5SVille Syrjälä flipq->flipq_id = flipq_id; 106470022b5SVille Syrjälä 107470022b5SVille Syrjälä drm_dbg_kms(display->drm, "[CRTC:%d:%s] FQ %d: start 0x%x\n", 108470022b5SVille Syrjälä crtc->base.base.id, crtc->base.name, 109470022b5SVille Syrjälä flipq_id, flipq->start_mmioaddr); 110470022b5SVille Syrjälä } 111470022b5SVille Syrjälä } 112470022b5SVille Syrjälä 113470022b5SVille Syrjälä bool intel_flipq_supported(struct intel_display *display) 114470022b5SVille Syrjälä { 115ec3a347bSVille Syrjälä if (!display->params.enable_flipq) 116ec3a347bSVille Syrjälä return false; 117ec3a347bSVille Syrjälä 118470022b5SVille Syrjälä if (!display->dmc.dmc) 119470022b5SVille Syrjälä return false; 120470022b5SVille Syrjälä 121470022b5SVille Syrjälä if (DISPLAY_VER(display) == 20) 122470022b5SVille Syrjälä return true; 123470022b5SVille Syrjälä 124470022b5SVille Syrjälä /* DMC firmware expects VRR timing generator to be used */ 125470022b5SVille Syrjälä return DISPLAY_VER(display) >= 30 && intel_vrr_always_use_vrr_tg(display); 126470022b5SVille Syrjälä } 127470022b5SVille Syrjälä 128470022b5SVille Syrjälä void intel_flipq_init(struct intel_display *display) 129470022b5SVille Syrjälä { 130470022b5SVille Syrjälä struct intel_crtc *crtc; 131470022b5SVille Syrjälä 132470022b5SVille Syrjälä intel_dmc_wait_fw_load(display); 133470022b5SVille Syrjälä 134470022b5SVille Syrjälä for_each_intel_crtc(display->drm, crtc) 135470022b5SVille Syrjälä intel_flipq_crtc_init(crtc); 136470022b5SVille Syrjälä } 137470022b5SVille Syrjälä 138470022b5SVille Syrjälä static int cdclk_factor(struct intel_display *display) 139470022b5SVille Syrjälä { 140470022b5SVille Syrjälä if (DISPLAY_VER(display) >= 30) 141470022b5SVille Syrjälä return 120; 142470022b5SVille Syrjälä else 143470022b5SVille Syrjälä return 280; 144470022b5SVille Syrjälä } 145470022b5SVille Syrjälä 146ec3a347bSVille Syrjälä int intel_flipq_exec_time_us(struct intel_display *display) 147470022b5SVille Syrjälä { 148470022b5SVille Syrjälä return intel_dsb_exec_time_us() + 149470022b5SVille Syrjälä DIV_ROUND_UP(display->cdclk.hw.cdclk * cdclk_factor(display), 540000) + 150470022b5SVille Syrjälä display->sagv.block_time_us; 151470022b5SVille Syrjälä } 152470022b5SVille Syrjälä 153470022b5SVille Syrjälä static int intel_flipq_preempt_timeout_ms(struct intel_display *display) 154470022b5SVille Syrjälä { 155470022b5SVille Syrjälä return DIV_ROUND_UP(intel_flipq_exec_time_us(display), 1000); 156470022b5SVille Syrjälä } 157470022b5SVille Syrjälä 158470022b5SVille Syrjälä static void intel_flipq_preempt(struct intel_crtc *crtc, bool preempt) 159470022b5SVille Syrjälä { 160470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 161470022b5SVille Syrjälä 162470022b5SVille Syrjälä intel_de_rmw(display, PIPEDMC_FQ_CTRL(crtc->pipe), 163470022b5SVille Syrjälä PIPEDMC_FQ_CTRL_PREEMPT, preempt ? PIPEDMC_FQ_CTRL_PREEMPT : 0); 164470022b5SVille Syrjälä 165470022b5SVille Syrjälä if (preempt && 166470022b5SVille Syrjälä intel_de_wait_for_clear(display, 167470022b5SVille Syrjälä PIPEDMC_FQ_STATUS(crtc->pipe), 168470022b5SVille Syrjälä PIPEDMC_FQ_STATUS_BUSY, 169470022b5SVille Syrjälä intel_flipq_preempt_timeout_ms(display))) 170470022b5SVille Syrjälä drm_err(display->drm, "[CRTC:%d:%s] flip queue preempt timeout\n", 171470022b5SVille Syrjälä crtc->base.base.id, crtc->base.name); 172470022b5SVille Syrjälä } 173470022b5SVille Syrjälä 174470022b5SVille Syrjälä static int intel_flipq_current_head(struct intel_crtc *crtc, enum intel_flipq_id flipq_id) 175470022b5SVille Syrjälä { 176470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 177470022b5SVille Syrjälä 178470022b5SVille Syrjälä return intel_de_read(display, PIPEDMC_FPQ_CHP(crtc->pipe, flipq_id)); 179470022b5SVille Syrjälä } 180470022b5SVille Syrjälä 181470022b5SVille Syrjälä static void intel_flipq_write_tail(struct intel_crtc *crtc) 182470022b5SVille Syrjälä { 183470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 184470022b5SVille Syrjälä 185470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FPQ_ATOMIC_TP(crtc->pipe), 186470022b5SVille Syrjälä PIPEDMC_FPQ_PLANEQ_3_TP(crtc->flipq[INTEL_FLIPQ_PLANE_3].tail) | 187470022b5SVille Syrjälä PIPEDMC_FPQ_PLANEQ_2_TP(crtc->flipq[INTEL_FLIPQ_PLANE_2].tail) | 188470022b5SVille Syrjälä PIPEDMC_FPQ_PLANEQ_1_TP(crtc->flipq[INTEL_FLIPQ_PLANE_1].tail) | 189470022b5SVille Syrjälä PIPEDMC_FPQ_FASTQ_TP(crtc->flipq[INTEL_FLIPQ_FAST].tail) | 190470022b5SVille Syrjälä PIPEDMC_FPQ_GENERALQ_TP(crtc->flipq[INTEL_FLIPQ_GENERAL].tail)); 191470022b5SVille Syrjälä } 192470022b5SVille Syrjälä 193470022b5SVille Syrjälä static void intel_flipq_sw_dmc_wake(struct intel_crtc *crtc) 194470022b5SVille Syrjälä { 195470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 196470022b5SVille Syrjälä 197470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FPQ_CTL1(crtc->pipe), PIPEDMC_SW_DMC_WAKE); 198470022b5SVille Syrjälä } 199470022b5SVille Syrjälä 200470022b5SVille Syrjälä static int intel_flipq_exec_time_lines(const struct intel_crtc_state *crtc_state) 201470022b5SVille Syrjälä { 202470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc_state); 203470022b5SVille Syrjälä 204470022b5SVille Syrjälä return intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, 205470022b5SVille Syrjälä intel_flipq_exec_time_us(display)); 206470022b5SVille Syrjälä } 207470022b5SVille Syrjälä 208*82458736SVille Syrjälä void intel_flipq_dump(struct intel_crtc *crtc, 209*82458736SVille Syrjälä enum intel_flipq_id flipq_id) 210*82458736SVille Syrjälä { 211*82458736SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 212*82458736SVille Syrjälä struct intel_flipq *flipq = &crtc->flipq[flipq_id]; 213*82458736SVille Syrjälä u32 tmp; 214*82458736SVille Syrjälä 215*82458736SVille Syrjälä drm_dbg_kms(display->drm, 216*82458736SVille Syrjälä "[CRTC:%d:%s] FQ %d @ 0x%x: ", 217*82458736SVille Syrjälä crtc->base.base.id, crtc->base.name, flipq_id, 218*82458736SVille Syrjälä flipq->start_mmioaddr); 219*82458736SVille Syrjälä for (int i = 0 ; i < intel_flipq_size_dw(flipq_id); i++) { 220*82458736SVille Syrjälä printk(KERN_CONT " 0x%08x", 221*82458736SVille Syrjälä intel_de_read(display, PIPEDMC_FQ_RAM(flipq->start_mmioaddr, i))); 222*82458736SVille Syrjälä if (i % intel_flipq_elem_size_dw(flipq_id) == intel_flipq_elem_size_dw(flipq_id) - 1) 223*82458736SVille Syrjälä printk(KERN_CONT "\n"); 224*82458736SVille Syrjälä } 225*82458736SVille Syrjälä 226*82458736SVille Syrjälä drm_dbg_kms(display->drm, 227*82458736SVille Syrjälä "[CRTC:%d:%s] FQ %d: chp=0x%x, hp=0x%x\n", 228*82458736SVille Syrjälä crtc->base.base.id, crtc->base.name, flipq_id, 229*82458736SVille Syrjälä intel_de_read(display, PIPEDMC_FPQ_CHP(crtc->pipe, flipq_id)), 230*82458736SVille Syrjälä intel_de_read(display, PIPEDMC_FPQ_HP(crtc->pipe, flipq_id))); 231*82458736SVille Syrjälä 232*82458736SVille Syrjälä drm_dbg_kms(display->drm, 233*82458736SVille Syrjälä "[CRTC:%d:%s] FQ %d: current head %d\n", 234*82458736SVille Syrjälä crtc->base.base.id, crtc->base.name, flipq_id, 235*82458736SVille Syrjälä intel_flipq_current_head(crtc, flipq_id)); 236*82458736SVille Syrjälä 237*82458736SVille Syrjälä drm_dbg_kms(display->drm, 238*82458736SVille Syrjälä "[CRTC:%d:%s] flip queue timestamp: 0x%x\n", 239*82458736SVille Syrjälä crtc->base.base.id, crtc->base.name, 240*82458736SVille Syrjälä intel_de_read(display, PIPEDMC_FPQ_TS(crtc->pipe))); 241*82458736SVille Syrjälä 242*82458736SVille Syrjälä tmp = intel_de_read(display, PIPEDMC_FPQ_ATOMIC_TP(crtc->pipe)); 243*82458736SVille Syrjälä 244*82458736SVille Syrjälä drm_dbg_kms(display->drm, 245*82458736SVille Syrjälä "[CRTC:%d:%s] flip queue atomic tails: P3 %d, P2 %d, P1 %d, G %d, F %d\n", 246*82458736SVille Syrjälä crtc->base.base.id, crtc->base.name, 247*82458736SVille Syrjälä REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_3_TP_MASK, tmp), 248*82458736SVille Syrjälä REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_2_TP_MASK, tmp), 249*82458736SVille Syrjälä REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_1_TP_MASK, tmp), 250*82458736SVille Syrjälä REG_FIELD_GET(PIPEDMC_FPQ_GENERALQ_TP_MASK, tmp), 251*82458736SVille Syrjälä REG_FIELD_GET(PIPEDMC_FPQ_FASTQ_TP_MASK, tmp)); 252*82458736SVille Syrjälä } 253*82458736SVille Syrjälä 254470022b5SVille Syrjälä void intel_flipq_reset(struct intel_display *display, enum pipe pipe) 255470022b5SVille Syrjälä { 256470022b5SVille Syrjälä struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); 257470022b5SVille Syrjälä enum intel_flipq_id flipq_id; 258470022b5SVille Syrjälä 259470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FQ_CTRL(pipe), 0); 260470022b5SVille Syrjälä 261470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(pipe), 0); 262470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(pipe), 0); 263470022b5SVille Syrjälä 264470022b5SVille Syrjälä for_each_flipq(flipq_id) { 265470022b5SVille Syrjälä struct intel_flipq *flipq = &crtc->flipq[flipq_id]; 266470022b5SVille Syrjälä 267470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FPQ_HP(pipe, flipq_id), 0); 268470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FPQ_CHP(pipe, flipq_id), 0); 269470022b5SVille Syrjälä 270470022b5SVille Syrjälä flipq->tail = 0; 271470022b5SVille Syrjälä } 272470022b5SVille Syrjälä 273470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FPQ_ATOMIC_TP(pipe), 0); 274470022b5SVille Syrjälä } 275470022b5SVille Syrjälä 276470022b5SVille Syrjälä static enum pipedmc_event_id flipq_event_id(struct intel_display *display) 277470022b5SVille Syrjälä { 278470022b5SVille Syrjälä if (DISPLAY_VER(display) >= 30) 279470022b5SVille Syrjälä return PIPEDMC_EVENT_FULL_FQ_WAKE_TRIGGER; 280470022b5SVille Syrjälä else 281470022b5SVille Syrjälä return PIPEDMC_EVENT_SCANLINE_INRANGE_FQ_TRIGGER; 282470022b5SVille Syrjälä } 283470022b5SVille Syrjälä 284470022b5SVille Syrjälä void intel_flipq_enable(const struct intel_crtc_state *crtc_state) 285470022b5SVille Syrjälä { 286470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc_state); 287470022b5SVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 288470022b5SVille Syrjälä /* FIXME what to do with VRR? */ 289470022b5SVille Syrjälä int scanline = intel_mode_vblank_start(&crtc_state->hw.adjusted_mode) - 290470022b5SVille Syrjälä intel_flipq_exec_time_lines(crtc_state); 291470022b5SVille Syrjälä 292470022b5SVille Syrjälä if (DISPLAY_VER(display) >= 30) { 293470022b5SVille Syrjälä u32 start_mmioaddr = intel_pipedmc_start_mmioaddr(crtc); 294470022b5SVille Syrjälä 295470022b5SVille Syrjälä /* undocumented magic DMC variables */ 296470022b5SVille Syrjälä intel_de_write(display, PTL_PIPEDMC_EXEC_TIME_LINES(start_mmioaddr), 297470022b5SVille Syrjälä intel_flipq_exec_time_lines(crtc_state)); 298470022b5SVille Syrjälä intel_de_write(display, PTL_PIPEDMC_END_OF_EXEC_GB(start_mmioaddr), 299470022b5SVille Syrjälä 100); 300470022b5SVille Syrjälä } 301470022b5SVille Syrjälä 302470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(crtc->pipe), 303470022b5SVille Syrjälä PIPEDMC_SCANLINE_UPPER(scanline)); 304470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(crtc->pipe), 305470022b5SVille Syrjälä PIPEDMC_SCANLINEINRANGECMP_EN | 306470022b5SVille Syrjälä PIPEDMC_SCANLINE_LOWER(scanline - 2)); 307470022b5SVille Syrjälä 308470022b5SVille Syrjälä intel_pipedmc_enable_event(crtc, flipq_event_id(display)); 309470022b5SVille Syrjälä 310470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FQ_CTRL(crtc->pipe), PIPEDMC_FQ_CTRL_ENABLE); 311470022b5SVille Syrjälä } 312470022b5SVille Syrjälä 313470022b5SVille Syrjälä void intel_flipq_disable(const struct intel_crtc_state *crtc_state) 314470022b5SVille Syrjälä { 315470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc_state); 316470022b5SVille Syrjälä struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); 317470022b5SVille Syrjälä 318470022b5SVille Syrjälä intel_flipq_preempt(crtc, true); 319470022b5SVille Syrjälä 320470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FQ_CTRL(crtc->pipe), 0); 321470022b5SVille Syrjälä 322470022b5SVille Syrjälä intel_pipedmc_disable_event(crtc, flipq_event_id(display)); 323470022b5SVille Syrjälä 324470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(crtc->pipe), 0); 325470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(crtc->pipe), 0); 326470022b5SVille Syrjälä } 327470022b5SVille Syrjälä 328470022b5SVille Syrjälä static bool assert_flipq_has_room(struct intel_crtc *crtc, 329470022b5SVille Syrjälä enum intel_flipq_id flipq_id) 330470022b5SVille Syrjälä { 331470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 332470022b5SVille Syrjälä struct intel_flipq *flipq = &crtc->flipq[flipq_id]; 333470022b5SVille Syrjälä int head, size = intel_flipq_size_entries(flipq_id); 334470022b5SVille Syrjälä 335470022b5SVille Syrjälä head = intel_flipq_current_head(crtc, flipq_id); 336470022b5SVille Syrjälä 337470022b5SVille Syrjälä return !drm_WARN(display->drm, 338470022b5SVille Syrjälä (flipq->tail + size - head) % size >= size - 1, 339470022b5SVille Syrjälä "[CRTC:%d:%s] FQ %d overflow (head %d, tail %d, size %d)\n", 340470022b5SVille Syrjälä crtc->base.base.id, crtc->base.name, flipq_id, 341470022b5SVille Syrjälä head, flipq->tail, size); 342470022b5SVille Syrjälä } 343470022b5SVille Syrjälä 344470022b5SVille Syrjälä static void intel_flipq_write(struct intel_display *display, 345470022b5SVille Syrjälä struct intel_flipq *flipq, u32 data, int i) 346470022b5SVille Syrjälä { 347470022b5SVille Syrjälä intel_de_write(display, PIPEDMC_FQ_RAM(flipq->start_mmioaddr, flipq->tail * 348470022b5SVille Syrjälä intel_flipq_elem_size_dw(flipq->flipq_id) + i), data); 349470022b5SVille Syrjälä } 350470022b5SVille Syrjälä 351470022b5SVille Syrjälä static void lnl_flipq_add(struct intel_display *display, 352470022b5SVille Syrjälä struct intel_flipq *flipq, 353470022b5SVille Syrjälä unsigned int pts, 354470022b5SVille Syrjälä enum intel_dsb_id dsb_id, 355470022b5SVille Syrjälä struct intel_dsb *dsb) 356470022b5SVille Syrjälä { 357470022b5SVille Syrjälä int i = 0; 358470022b5SVille Syrjälä 359470022b5SVille Syrjälä switch (flipq->flipq_id) { 360470022b5SVille Syrjälä case INTEL_FLIPQ_GENERAL: 361470022b5SVille Syrjälä intel_flipq_write(display, flipq, pts, i++); 362470022b5SVille Syrjälä intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); 363470022b5SVille Syrjälä intel_flipq_write(display, flipq, LNL_FQ_INTERRUPT | 364470022b5SVille Syrjälä LNL_FQ_DSB_ID(dsb_id) | 365470022b5SVille Syrjälä LNL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); 366470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); 367470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); /* head for second DSB */ 368470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); /* DSB engine + size for second DSB */ 369470022b5SVille Syrjälä break; 370470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_1: 371470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_2: 372470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_3: 373470022b5SVille Syrjälä intel_flipq_write(display, flipq, pts, i++); 374470022b5SVille Syrjälä intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); 375470022b5SVille Syrjälä intel_flipq_write(display, flipq, LNL_FQ_INTERRUPT | 376470022b5SVille Syrjälä LNL_FQ_DSB_ID(dsb_id) | 377470022b5SVille Syrjälä LNL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); 378470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); 379470022b5SVille Syrjälä break; 380470022b5SVille Syrjälä default: 381470022b5SVille Syrjälä MISSING_CASE(flipq->flipq_id); 382470022b5SVille Syrjälä return; 383470022b5SVille Syrjälä } 384470022b5SVille Syrjälä } 385470022b5SVille Syrjälä 386470022b5SVille Syrjälä static void ptl_flipq_add(struct intel_display *display, 387470022b5SVille Syrjälä struct intel_flipq *flipq, 388470022b5SVille Syrjälä unsigned int pts, 389470022b5SVille Syrjälä enum intel_dsb_id dsb_id, 390470022b5SVille Syrjälä struct intel_dsb *dsb) 391470022b5SVille Syrjälä { 392470022b5SVille Syrjälä int i = 0; 393470022b5SVille Syrjälä 394470022b5SVille Syrjälä switch (flipq->flipq_id) { 395470022b5SVille Syrjälä case INTEL_FLIPQ_GENERAL: 396470022b5SVille Syrjälä intel_flipq_write(display, flipq, pts, i++); 397470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); 398470022b5SVille Syrjälä intel_flipq_write(display, flipq, PTL_FQ_INTERRUPT | 399470022b5SVille Syrjälä PTL_FQ_DSB_ID(dsb_id) | 400470022b5SVille Syrjälä PTL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); 401470022b5SVille Syrjälä intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); 402470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); /* DSB engine + size for second DSB */ 403470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); /* head for second DSB */ 404470022b5SVille Syrjälä break; 405470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_1: 406470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_2: 407470022b5SVille Syrjälä case INTEL_FLIPQ_PLANE_3: 408470022b5SVille Syrjälä intel_flipq_write(display, flipq, pts, i++); 409470022b5SVille Syrjälä intel_flipq_write(display, flipq, 0, i++); 410470022b5SVille Syrjälä intel_flipq_write(display, flipq, PTL_FQ_INTERRUPT | 411470022b5SVille Syrjälä PTL_FQ_DSB_ID(dsb_id) | 412470022b5SVille Syrjälä PTL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++); 413470022b5SVille Syrjälä intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++); 414470022b5SVille Syrjälä break; 415470022b5SVille Syrjälä default: 416470022b5SVille Syrjälä MISSING_CASE(flipq->flipq_id); 417470022b5SVille Syrjälä return; 418470022b5SVille Syrjälä } 419470022b5SVille Syrjälä } 420470022b5SVille Syrjälä 421470022b5SVille Syrjälä void intel_flipq_add(struct intel_crtc *crtc, 422470022b5SVille Syrjälä enum intel_flipq_id flipq_id, 423470022b5SVille Syrjälä unsigned int pts, 424470022b5SVille Syrjälä enum intel_dsb_id dsb_id, 425470022b5SVille Syrjälä struct intel_dsb *dsb) 426470022b5SVille Syrjälä { 427470022b5SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 428470022b5SVille Syrjälä struct intel_flipq *flipq = &crtc->flipq[flipq_id]; 429470022b5SVille Syrjälä 430470022b5SVille Syrjälä if (!assert_flipq_has_room(crtc, flipq_id)) 431470022b5SVille Syrjälä return; 432470022b5SVille Syrjälä 433470022b5SVille Syrjälä pts += intel_de_read(display, PIPEDMC_FPQ_TS(crtc->pipe)); 434470022b5SVille Syrjälä 435470022b5SVille Syrjälä intel_flipq_preempt(crtc, true); 436470022b5SVille Syrjälä 437470022b5SVille Syrjälä if (DISPLAY_VER(display) >= 30) 438470022b5SVille Syrjälä ptl_flipq_add(display, flipq, pts, dsb_id, dsb); 439470022b5SVille Syrjälä else 440470022b5SVille Syrjälä lnl_flipq_add(display, flipq, pts, dsb_id, dsb); 441470022b5SVille Syrjälä 442470022b5SVille Syrjälä flipq->tail = (flipq->tail + 1) % intel_flipq_size_entries(flipq->flipq_id); 443470022b5SVille Syrjälä intel_flipq_write_tail(crtc); 444470022b5SVille Syrjälä 445470022b5SVille Syrjälä intel_flipq_preempt(crtc, false); 446470022b5SVille Syrjälä 447470022b5SVille Syrjälä intel_flipq_sw_dmc_wake(crtc); 448470022b5SVille Syrjälä } 449a47828f3SVille Syrjälä 450a47828f3SVille Syrjälä /* Wa_18034343758 */ 451a47828f3SVille Syrjälä static bool need_dmc_halt_wa(struct intel_display *display) 452a47828f3SVille Syrjälä { 453a47828f3SVille Syrjälä return DISPLAY_VER(display) == 20 || 454a47828f3SVille Syrjälä (display->platform.pantherlake && 455a47828f3SVille Syrjälä IS_DISPLAY_STEP(display, STEP_A0, STEP_B0)); 456a47828f3SVille Syrjälä } 457a47828f3SVille Syrjälä 458a47828f3SVille Syrjälä void intel_flipq_wait_dmc_halt(struct intel_dsb *dsb, struct intel_crtc *crtc) 459a47828f3SVille Syrjälä { 460a47828f3SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 461a47828f3SVille Syrjälä 462a47828f3SVille Syrjälä if (need_dmc_halt_wa(display)) 463a47828f3SVille Syrjälä intel_dsb_wait_usec(dsb, 2); 464a47828f3SVille Syrjälä } 465a47828f3SVille Syrjälä 466a47828f3SVille Syrjälä void intel_flipq_unhalt_dmc(struct intel_dsb *dsb, struct intel_crtc *crtc) 467a47828f3SVille Syrjälä { 468a47828f3SVille Syrjälä struct intel_display *display = to_intel_display(crtc); 469a47828f3SVille Syrjälä 470a47828f3SVille Syrjälä if (need_dmc_halt_wa(display)) 471a47828f3SVille Syrjälä intel_dsb_reg_write(dsb, PIPEDMC_CTL(crtc->pipe), 0); 472a47828f3SVille Syrjälä } 473