Skip to content

Commit 6a4500c

Browse files
coxuintelzhenyw
authored andcommitted
drm/i915/gvt: Get accurate vGPU virtual display refresh rate from vreg
Guest OS builds up its timing mode list based on the virtual EDID as simulated by GVT. However since there are several timings supported in the virtual EDID, and each timing can also support several modes (resolution and refresh rate), current emulated vblank period (16ms) may not always be correct and could lead to miss-sync behavior in guest. Guest driver will setup new resolution and program vregs accordingly and it should always follows GEN PRM. Based on the simulated display regs by GVT, it's safe to decode the actual refresh rate using by guest from vreg only. Current implementation only enables PIPE_A and PIPE_A is always tied to TRANSCODER_A in HW. GVT may simulate DP monitor on PORT_B or PORT_D based on the caller. So we can find out which DPLL is used by PORT_x which connected to TRANSCODER_A and calculate the DP bit rate from the DPLL frequency. Then DP stream clock (pixel clock) can be calculated from DP link M/N and DP bit rate. Finally, get the refresh rate from pixel clock, H total and V total. The per-vGPU accurate refresh rate is not used yet but only stored, until per-vGPU vblank timer is enabled. Then each vGPU can have different and accurate refresh rate per-guest driver configuration. Refer to PRM for GEN display and VESA timing standard for more details. V2: Rebase to 5.11. Correctly calculate DP link rate for BDW and BXT. Use GVT_DEFAULT_REFRESH_RATE instead of hardcoded to 60 as init refresh. Typo fix. (zhenyu) Signed-off-by: Colin Xu <[email protected]> Signed-off-by: Zhenyu Wang <[email protected]> Link: http://patchwork.freedesktop.org/patch/msgid/[email protected] Reviewed-by: Zhenyu Wang <[email protected]>
1 parent c739271 commit 6a4500c

File tree

4 files changed

+260
-2
lines changed

4 files changed

+260
-2
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
529529
port->dpcd->data[DPCD_SINK_COUNT] = 0x1;
530530
port->type = type;
531531
port->id = resolution;
532+
port->vrefresh_k = GVT_DEFAULT_REFRESH_RATE * MSEC_PER_SEC;
533+
vgpu->display.port_num = port_num;
532534

533535
emulate_monitor_status_change(vgpu);
534536

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,16 @@ enum intel_vgpu_edid {
157157
GVT_EDID_NUM,
158158
};
159159

160+
#define GVT_DEFAULT_REFRESH_RATE 60
160161
struct intel_vgpu_port {
161162
/* per display EDID information */
162163
struct intel_vgpu_edid_data *edid;
163164
/* per display DPCD information */
164165
struct intel_vgpu_dpcd_data *dpcd;
165166
int type;
166167
enum intel_vgpu_edid id;
168+
/* x1000 to get accurate 59.94, 24.976, 29.94, etc. in timing std. */
169+
u32 vrefresh_k;
167170
};
168171

169172
static inline char *vgpu_edid_str(enum intel_vgpu_edid id)

drivers/gpu/drm/i915/gvt/gvt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct intel_vgpu_display {
133133
struct intel_vgpu_i2c_edid i2c_edid;
134134
struct intel_vgpu_port ports[I915_MAX_PORTS];
135135
struct intel_vgpu_sbi sbi;
136+
enum port port_num;
136137
};
137138

138139
struct vgpu_sched_ctl {

drivers/gpu/drm/i915/gvt/handlers.c

Lines changed: 254 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "i915_drv.h"
4040
#include "gvt.h"
4141
#include "i915_pvinfo.h"
42+
#include "display/intel_display_types.h"
4243

4344
/* XXX FIXME i915 has changed PP_XXX definition */
4445
#define PCH_PP_STATUS _MMIO(0xc7200)
@@ -443,6 +444,254 @@ static int dpy_reg_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
443444
return 0;
444445
}
445446

447+
/*
448+
* Only PIPE_A is enabled in current vGPU display and PIPE_A is tied to
449+
* TRANSCODER_A in HW. DDI/PORT could be PORT_x depends on
450+
* setup_virtual_dp_monitor().
451+
* emulate_monitor_status_change() set up PLL for PORT_x as the initial enabled
452+
* DPLL. Later guest driver may setup a different DPLLx when setting mode.
453+
* So the correct sequence to find DP stream clock is:
454+
* Check TRANS_DDI_FUNC_CTL on TRANSCODER_A to get PORT_x.
455+
* Check correct PLLx for PORT_x to get PLL frequency and DP bitrate.
456+
* Then Refresh rate then can be calculated based on follow equations:
457+
* Pixel clock = h_total * v_total * refresh_rate
458+
* stream clock = Pixel clock
459+
* ls_clk = DP bitrate
460+
* Link M/N = strm_clk / ls_clk
461+
*/
462+
463+
static u32 bdw_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port)
464+
{
465+
u32 dp_br = 0;
466+
u32 ddi_pll_sel = vgpu_vreg_t(vgpu, PORT_CLK_SEL(port));
467+
468+
switch (ddi_pll_sel) {
469+
case PORT_CLK_SEL_LCPLL_2700:
470+
dp_br = 270000 * 2;
471+
break;
472+
case PORT_CLK_SEL_LCPLL_1350:
473+
dp_br = 135000 * 2;
474+
break;
475+
case PORT_CLK_SEL_LCPLL_810:
476+
dp_br = 81000 * 2;
477+
break;
478+
case PORT_CLK_SEL_SPLL:
479+
{
480+
switch (vgpu_vreg_t(vgpu, SPLL_CTL) & SPLL_FREQ_MASK) {
481+
case SPLL_FREQ_810MHz:
482+
dp_br = 81000 * 2;
483+
break;
484+
case SPLL_FREQ_1350MHz:
485+
dp_br = 135000 * 2;
486+
break;
487+
case SPLL_FREQ_2700MHz:
488+
dp_br = 270000 * 2;
489+
break;
490+
default:
491+
gvt_dbg_dpy("vgpu-%d PORT_%c can't get freq from SPLL 0x%08x\n",
492+
vgpu->id, port_name(port), vgpu_vreg_t(vgpu, SPLL_CTL));
493+
break;
494+
}
495+
break;
496+
}
497+
case PORT_CLK_SEL_WRPLL1:
498+
case PORT_CLK_SEL_WRPLL2:
499+
{
500+
u32 wrpll_ctl;
501+
int refclk, n, p, r;
502+
503+
if (ddi_pll_sel == PORT_CLK_SEL_WRPLL1)
504+
wrpll_ctl = vgpu_vreg_t(vgpu, WRPLL_CTL(DPLL_ID_WRPLL1));
505+
else
506+
wrpll_ctl = vgpu_vreg_t(vgpu, WRPLL_CTL(DPLL_ID_WRPLL2));
507+
508+
switch (wrpll_ctl & WRPLL_REF_MASK) {
509+
case WRPLL_REF_PCH_SSC:
510+
refclk = vgpu->gvt->gt->i915->dpll.ref_clks.ssc;
511+
break;
512+
case WRPLL_REF_LCPLL:
513+
refclk = 2700000;
514+
break;
515+
default:
516+
gvt_dbg_dpy("vgpu-%d PORT_%c WRPLL can't get refclk 0x%08x\n",
517+
vgpu->id, port_name(port), wrpll_ctl);
518+
goto out;
519+
}
520+
521+
r = wrpll_ctl & WRPLL_DIVIDER_REF_MASK;
522+
p = (wrpll_ctl & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT;
523+
n = (wrpll_ctl & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
524+
525+
dp_br = (refclk * n / 10) / (p * r) * 2;
526+
break;
527+
}
528+
default:
529+
gvt_dbg_dpy("vgpu-%d PORT_%c has invalid clock select 0x%08x\n",
530+
vgpu->id, port_name(port), vgpu_vreg_t(vgpu, PORT_CLK_SEL(port)));
531+
break;
532+
}
533+
534+
out:
535+
return dp_br;
536+
}
537+
538+
static u32 bxt_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port)
539+
{
540+
u32 dp_br = 0;
541+
int refclk = vgpu->gvt->gt->i915->dpll.ref_clks.nssc;
542+
enum dpio_phy phy = DPIO_PHY0;
543+
enum dpio_channel ch = DPIO_CH0;
544+
struct dpll clock = {0};
545+
u32 temp;
546+
547+
/* Port to PHY mapping is fixed, see bxt_ddi_phy_info{} */
548+
switch (port) {
549+
case PORT_A:
550+
phy = DPIO_PHY1;
551+
ch = DPIO_CH0;
552+
break;
553+
case PORT_B:
554+
phy = DPIO_PHY0;
555+
ch = DPIO_CH0;
556+
break;
557+
case PORT_C:
558+
phy = DPIO_PHY0;
559+
ch = DPIO_CH1;
560+
break;
561+
default:
562+
gvt_dbg_dpy("vgpu-%d no PHY for PORT_%c\n", vgpu->id, port_name(port));
563+
goto out;
564+
}
565+
566+
temp = vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(port));
567+
if (!(temp & PORT_PLL_ENABLE) || !(temp & PORT_PLL_LOCK)) {
568+
gvt_dbg_dpy("vgpu-%d PORT_%c PLL_ENABLE 0x%08x isn't enabled or locked\n",
569+
vgpu->id, port_name(port), temp);
570+
goto out;
571+
}
572+
573+
clock.m1 = 2;
574+
clock.m2 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 0)) & PORT_PLL_M2_MASK) << 22;
575+
if (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 3)) & PORT_PLL_M2_FRAC_ENABLE)
576+
clock.m2 |= vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 2)) & PORT_PLL_M2_FRAC_MASK;
577+
clock.n = (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 1)) & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT;
578+
clock.p1 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch)) & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT;
579+
clock.p2 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch)) & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT;
580+
clock.m = clock.m1 * clock.m2;
581+
clock.p = clock.p1 * clock.p2;
582+
583+
if (clock.n == 0 || clock.p == 0) {
584+
gvt_dbg_dpy("vgpu-%d PORT_%c PLL has invalid divider\n", vgpu->id, port_name(port));
585+
goto out;
586+
}
587+
588+
clock.vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock.m), clock.n << 22);
589+
clock.dot = DIV_ROUND_CLOSEST(clock.vco, clock.p);
590+
591+
dp_br = clock.dot / 5;
592+
593+
out:
594+
return dp_br;
595+
}
596+
597+
static u32 skl_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port)
598+
{
599+
u32 dp_br = 0;
600+
enum intel_dpll_id dpll_id = DPLL_ID_SKL_DPLL0;
601+
602+
/* Find the enabled DPLL for the DDI/PORT */
603+
if (!(vgpu_vreg_t(vgpu, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_OFF(port)) &&
604+
(vgpu_vreg_t(vgpu, DPLL_CTRL2) & DPLL_CTRL2_DDI_SEL_OVERRIDE(port))) {
605+
dpll_id += (vgpu_vreg_t(vgpu, DPLL_CTRL2) &
606+
DPLL_CTRL2_DDI_CLK_SEL_MASK(port)) >>
607+
DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port);
608+
} else {
609+
gvt_dbg_dpy("vgpu-%d DPLL for PORT_%c isn't turned on\n",
610+
vgpu->id, port_name(port));
611+
return dp_br;
612+
}
613+
614+
/* Find PLL output frequency from correct DPLL, and get bir rate */
615+
switch ((vgpu_vreg_t(vgpu, DPLL_CTRL1) &
616+
DPLL_CTRL1_LINK_RATE_MASK(dpll_id)) >>
617+
DPLL_CTRL1_LINK_RATE_SHIFT(dpll_id)) {
618+
case DPLL_CTRL1_LINK_RATE_810:
619+
dp_br = 81000 * 2;
620+
break;
621+
case DPLL_CTRL1_LINK_RATE_1080:
622+
dp_br = 108000 * 2;
623+
break;
624+
case DPLL_CTRL1_LINK_RATE_1350:
625+
dp_br = 135000 * 2;
626+
break;
627+
case DPLL_CTRL1_LINK_RATE_1620:
628+
dp_br = 162000 * 2;
629+
break;
630+
case DPLL_CTRL1_LINK_RATE_2160:
631+
dp_br = 216000 * 2;
632+
break;
633+
case DPLL_CTRL1_LINK_RATE_2700:
634+
dp_br = 270000 * 2;
635+
break;
636+
default:
637+
dp_br = 0;
638+
gvt_dbg_dpy("vgpu-%d PORT_%c fail to get DPLL-%d freq\n",
639+
vgpu->id, port_name(port), dpll_id);
640+
}
641+
642+
return dp_br;
643+
}
644+
645+
static void vgpu_update_refresh_rate(struct intel_vgpu *vgpu)
646+
{
647+
struct drm_i915_private *dev_priv = vgpu->gvt->gt->i915;
648+
enum port port;
649+
u32 dp_br, link_m, link_n, htotal, vtotal;
650+
651+
/* Find DDI/PORT assigned to TRANSCODER_A, expect B or D */
652+
port = (vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &
653+
TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
654+
if (port != PORT_B && port != PORT_D) {
655+
gvt_dbg_dpy("vgpu-%d unsupported PORT_%c\n", vgpu->id, port_name(port));
656+
return;
657+
}
658+
659+
/* Calculate DP bitrate from PLL */
660+
if (IS_BROADWELL(dev_priv))
661+
dp_br = bdw_vgpu_get_dp_bitrate(vgpu, port);
662+
else if (IS_BROXTON(dev_priv))
663+
dp_br = bxt_vgpu_get_dp_bitrate(vgpu, port);
664+
else
665+
dp_br = skl_vgpu_get_dp_bitrate(vgpu, port);
666+
667+
/* Get DP link symbol clock M/N */
668+
link_m = vgpu_vreg_t(vgpu, PIPE_LINK_M1(TRANSCODER_A));
669+
link_n = vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A));
670+
671+
/* Get H/V total from transcoder timing */
672+
htotal = (vgpu_vreg_t(vgpu, HTOTAL(TRANSCODER_A)) >> TRANS_HTOTAL_SHIFT) + 1;
673+
vtotal = (vgpu_vreg_t(vgpu, VTOTAL(TRANSCODER_A)) >> TRANS_VTOTAL_SHIFT) + 1;
674+
675+
if (dp_br && link_n && htotal && vtotal) {
676+
u64 pixel_clk = 0;
677+
u32 new_rate = 0;
678+
u32 *old_rate = &(intel_vgpu_port(vgpu, vgpu->display.port_num)->vrefresh_k);
679+
680+
/* Calcuate pixel clock by (ls_clk * M / N) */
681+
pixel_clk = div_u64(mul_u32_u32(link_m, dp_br), link_n);
682+
pixel_clk *= MSEC_PER_SEC;
683+
684+
/* Calcuate refresh rate by (pixel_clk / (h_total * v_total)) */
685+
new_rate = DIV64_U64_ROUND_CLOSEST(pixel_clk, div64_u64(mul_u32_u32(htotal, vtotal), MSEC_PER_SEC));
686+
687+
if (*old_rate != new_rate)
688+
*old_rate = new_rate;
689+
690+
gvt_dbg_dpy("vgpu-%d PIPE_%c refresh rate updated to %d\n",
691+
vgpu->id, pipe_name(PIPE_A), new_rate);
692+
}
693+
}
694+
446695
static int pipeconf_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
447696
void *p_data, unsigned int bytes)
448697
{
@@ -451,10 +700,13 @@ static int pipeconf_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
451700
write_vreg(vgpu, offset, p_data, bytes);
452701
data = vgpu_vreg(vgpu, offset);
453702

454-
if (data & PIPECONF_ENABLE)
703+
if (data & PIPECONF_ENABLE) {
455704
vgpu_vreg(vgpu, offset) |= I965_PIPECONF_ACTIVE;
456-
else
705+
vgpu_update_refresh_rate(vgpu);
706+
707+
} else {
457708
vgpu_vreg(vgpu, offset) &= ~I965_PIPECONF_ACTIVE;
709+
}
458710
/* vgpu_lock already hold by emulate mmio r/w */
459711
mutex_unlock(&vgpu->vgpu_lock);
460712
intel_gvt_check_vblank_emulation(vgpu->gvt);

0 commit comments

Comments
 (0)