Skip to content

Commit 470022b

Browse files
committed
drm/i915/flipq: Provide the nuts and bolts code for flip queue
Provide the lower level code for PIPEDMC based flip queue. We'll use the so called semi-full flip queue mode where the PIPEDMC will start the provided DSB on a scanline a little ahead of the vblank. We need to program the triggering scanline early enough so that the DSB has enough time to complete writing all the double buffered registers before they get latched (at start of vblank). The firmware implements several queues: - 3 "plane queues" which execute a single DSB per entry - 1 "general queue" which can apparently execute 2 DSBs per entry - 1 vestigial "fast queue" that replaced the "simple flip queue" on ADL+, but this isn't supposed to be used due to issues. But we only need a single plane queue really, and we won't actually use it as a real queue because we don't allow queueing multiple commits ahead of time. So the whole thing is perhaps useless. I suppose there migth be some power saving benefits if we would get the flip scheduled by userspace early and then could keep some hardware powered off a bit longer until the DMC kicks off the flipq programming. But that is pure speculation at this time and needs to be proven. The code to hook up the flip queue into the actual atomic commit path will follow later. TODO: need to think how to do the "wait for DMC firmware load" nicely need to think about VRR and PSR etc. v2: Don't write DMC_FQ_W2_PTS_CFG_SEL on pre-lnl Don't oops at flipq init if there is no dmc v3: Adapt to PTL+ flipq changes (different queue entry layout, different trigger event, need VRR TG) Use the actual CDCLK frequency Ask the DSB code how long things are expected to take v3: Adjust the cdclk rounding (docs are 100% vague, Windows rounds like this) Initialize some undocumented magic DMC variables on PTL v4: Use PIPEDMC_FQ_STATUS for busy check (the busy bit in PIPEDMC_FQ_CTRL is apparently gone on LNL+) Based the preempt timeout on the max exec time Preempt before disabling the flip queue Order the PIPEDMC_SCANLINECMP* writes a bit more carefully Fix some typos v5: Try to deal with some clang-20 div-by-zero false positive (Nathan) Add some docs (Jani) Cc: Nathan Chancellor <[email protected]> Reviewed-by: Uma Shankar <[email protected]> Signed-off-by: Ville Syrjälä <[email protected]> epr Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 141b954 commit 470022b

File tree

9 files changed

+521
-0
lines changed

9 files changed

+521
-0
lines changed

Documentation/gpu/i915.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ DMC Firmware Support
204204
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c
205205
:internal:
206206

207+
DMC Flip Queue
208+
--------------------
209+
210+
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_flipq.c
211+
:doc: DMC Flip Queue
212+
207213
DMC wakelock support
208214
--------------------
209215

drivers/gpu/drm/i915/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ i915-y += \
264264
display/intel_fbc.o \
265265
display/intel_fdi.o \
266266
display/intel_fifo_underrun.o \
267+
display/intel_flipq.o \
267268
display/intel_frontbuffer.o \
268269
display/intel_global_state.o \
269270
display/intel_hdcp.o \

drivers/gpu/drm/i915/display/intel_display_driver.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "intel_fbc.h"
4545
#include "intel_fbdev.h"
4646
#include "intel_fdi.h"
47+
#include "intel_flipq.h"
4748
#include "intel_gmbus.h"
4849
#include "intel_hdcp.h"
4950
#include "intel_hotplug.h"
@@ -537,6 +538,8 @@ int intel_display_driver_probe(struct intel_display *display)
537538
*/
538539
intel_hdcp_component_init(display);
539540

541+
intel_flipq_init(display);
542+
540543
/*
541544
* Force all active planes to recompute their states. So that on
542545
* mode_setcrtc after probe, all the intel_plane_state variables

drivers/gpu/drm/i915/display/intel_display_types.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,21 @@ struct intel_pipe_crc {
13711371
enum intel_pipe_crc_source source;
13721372
};
13731373

1374+
enum intel_flipq_id {
1375+
INTEL_FLIPQ_PLANE_1,
1376+
INTEL_FLIPQ_PLANE_2,
1377+
INTEL_FLIPQ_PLANE_3,
1378+
INTEL_FLIPQ_GENERAL,
1379+
INTEL_FLIPQ_FAST,
1380+
MAX_INTEL_FLIPQ,
1381+
};
1382+
1383+
struct intel_flipq {
1384+
u32 start_mmioaddr;
1385+
enum intel_flipq_id flipq_id;
1386+
u8 tail;
1387+
};
1388+
13741389
struct intel_crtc {
13751390
struct drm_crtc base;
13761391
enum pipe pipe;
@@ -1402,6 +1417,8 @@ struct intel_crtc {
14021417
bool cpu_fifo_underrun_disabled;
14031418
bool pch_fifo_underrun_disabled;
14041419

1420+
struct intel_flipq flipq[MAX_INTEL_FLIPQ];
1421+
14051422
/* per-pipe watermark state */
14061423
struct {
14071424
/* watermarks currently being used */

drivers/gpu/drm/i915/display/intel_dmc.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <linux/debugfs.h>
2626
#include <linux/firmware.h>
27+
#include <drm/drm_vblank.h>
2728

2829
#include "i915_drv.h"
2930
#include "i915_reg.h"
@@ -35,6 +36,7 @@
3536
#include "intel_display_types.h"
3637
#include "intel_dmc.h"
3738
#include "intel_dmc_regs.h"
39+
#include "intel_flipq.h"
3840
#include "intel_step.h"
3941

4042
/**
@@ -737,6 +739,8 @@ void intel_dmc_enable_pipe(const struct intel_crtc_state *crtc_state)
737739
assert_dmc_loaded(display, dmc_id);
738740

739741
if (DISPLAY_VER(display) >= 20) {
742+
intel_flipq_reset(display, pipe);
743+
740744
intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display));
741745
intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~pipedmc_interrupt_mask(display));
742746
}
@@ -765,6 +769,8 @@ void intel_dmc_disable_pipe(const struct intel_crtc_state *crtc_state)
765769
if (DISPLAY_VER(display) >= 20) {
766770
intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~0);
767771
intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display));
772+
773+
intel_flipq_reset(display, pipe);
768774
}
769775
}
770776

@@ -853,6 +859,13 @@ void intel_dmc_load_program(struct intel_display *display)
853859
assert_dmc_loaded(display, dmc_id);
854860
}
855861

862+
if (DISPLAY_VER(display) >= 20)
863+
intel_de_write(display, DMC_FQ_W2_PTS_CFG_SEL,
864+
PIPE_D_DMC_W2_PTS_CONFIG_SELECT(PIPE_D) |
865+
PIPE_C_DMC_W2_PTS_CONFIG_SELECT(PIPE_C) |
866+
PIPE_B_DMC_W2_PTS_CONFIG_SELECT(PIPE_B) |
867+
PIPE_A_DMC_W2_PTS_CONFIG_SELECT(PIPE_A));
868+
856869
power_domains->dc_state = 0;
857870

858871
gen9_set_dc_state_debugmask(display);
@@ -1371,6 +1384,17 @@ void intel_dmc_suspend(struct intel_display *display)
13711384
intel_dmc_runtime_pm_put(display);
13721385
}
13731386

1387+
void intel_dmc_wait_fw_load(struct intel_display *display)
1388+
{
1389+
struct intel_dmc *dmc = display_to_dmc(display);
1390+
1391+
if (!HAS_DMC(display))
1392+
return;
1393+
1394+
if (dmc)
1395+
flush_work(&dmc->work);
1396+
}
1397+
13741398
/**
13751399
* intel_dmc_resume() - init DMC firmware during system resume
13761400
* @display: display instance
@@ -1606,3 +1630,30 @@ void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe)
16061630
drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC interrupt vector 0x%x\n",
16071631
crtc->base.base.id, crtc->base.name, tmp);
16081632
}
1633+
1634+
void intel_pipedmc_enable_event(struct intel_crtc *crtc,
1635+
enum pipedmc_event_id event)
1636+
{
1637+
struct intel_display *display = to_intel_display(crtc);
1638+
enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(crtc->pipe);
1639+
1640+
dmc_configure_event(display, dmc_id, event, true);
1641+
}
1642+
1643+
void intel_pipedmc_disable_event(struct intel_crtc *crtc,
1644+
enum pipedmc_event_id event)
1645+
{
1646+
struct intel_display *display = to_intel_display(crtc);
1647+
enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(crtc->pipe);
1648+
1649+
dmc_configure_event(display, dmc_id, event, false);
1650+
}
1651+
1652+
u32 intel_pipedmc_start_mmioaddr(struct intel_crtc *crtc)
1653+
{
1654+
struct intel_display *display = to_intel_display(crtc);
1655+
struct intel_dmc *dmc = display_to_dmc(display);
1656+
enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(crtc->pipe);
1657+
1658+
return dmc ? dmc->dmc_info[dmc_id].start_mmioaddr : 0;
1659+
}

drivers/gpu/drm/i915/display/intel_dmc.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
#include <linux/types.h>
1010

1111
enum pipe;
12+
enum pipedmc_event_id;
1213
struct drm_printer;
14+
struct intel_crtc;
1315
struct intel_crtc_state;
1416
struct intel_display;
1517
struct intel_dmc_snapshot;
1618

1719
void intel_dmc_init(struct intel_display *display);
1820
void intel_dmc_load_program(struct intel_display *display);
21+
void intel_dmc_wait_fw_load(struct intel_display *display);
1922
void intel_dmc_disable_program(struct intel_display *display);
2023
void intel_dmc_enable_pipe(const struct intel_crtc_state *crtc_state);
2124
void intel_dmc_disable_pipe(const struct intel_crtc_state *crtc_state);
@@ -37,4 +40,12 @@ void assert_main_dmc_loaded(struct intel_display *display);
3740

3841
void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe);
3942

43+
u32 intel_pipedmc_start_mmioaddr(struct intel_crtc *crtc);
44+
void intel_pipedmc_enable_event(struct intel_crtc *crtc,
45+
enum pipedmc_event_id event);
46+
void intel_pipedmc_disable_event(struct intel_crtc *crtc,
47+
enum pipedmc_event_id event);
48+
49+
void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe);
50+
4051
#endif /* __INTEL_DMC_H__ */

0 commit comments

Comments
 (0)