Skip to content

Commit 2b28bb1

Browse files
rodrigovividanvet
authored andcommitted
drm/i915: Enable/Disable PSR
Adding Enable and Disable PSR functionalities. This includes setting the PSR configuration over AUX, sending SDP VSC DIP over the eDP PIPE config, enabling PSR in the sink via DPCD register and finally enabling PSR on the host. This patch is based on initial PSR code by Sateesh Kavuri and Kumar Shobhit but in a different implementation. v2: * moved functions around and changed its names. * removed VSC DIP unset from disable. * remove FBC wa. * don't mask LSPS anymore. * incorporate new crtc usage after a rebase. v3: Make a clear separation between Sink (Panel) and Source (HW) enabling. v4: Fix identation and other style issues raised by checkpatch (by Paulo). v5: Changes according to Paulo's review: static on write_vsc; avoid using dp_to_dev when already calling dp_to_dig_port; remove unecessary TP default time setting; remove unecessary interrupts disabling; remove unecessary wait_for_vblank when disabling psr; v6: remove unecessary wait_for_vblank when writing vsc; v7: adding setup once function to avoid unnecessarily write to vsc and set debug_ctl every time we enable or disable psr. Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Credits-by: Sateesh Kavuri <sateesh.kavuri@intel.com> Credits-by: Shobhit Kumar <shobhit.kumar@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Shobhit Kumar <shobhit.kumar@intel.com> [danvet: Apply Paulo's suggestion for unconditionally clearing the control register when writing the DIP.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
1 parent b84a1cf commit 2b28bb1

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

drivers/gpu/drm/i915/i915_reg.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,6 +1779,47 @@
17791779
#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
17801780
#define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
17811781

1782+
/* HSW eDP PSR registers */
1783+
#define EDP_PSR_CTL 0x64800
1784+
#define EDP_PSR_ENABLE (1<<31)
1785+
#define EDP_PSR_LINK_DISABLE (0<<27)
1786+
#define EDP_PSR_LINK_STANDBY (1<<27)
1787+
#define EDP_PSR_MIN_LINK_ENTRY_TIME_MASK (3<<25)
1788+
#define EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES (0<<25)
1789+
#define EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES (1<<25)
1790+
#define EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES (2<<25)
1791+
#define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES (3<<25)
1792+
#define EDP_PSR_MAX_SLEEP_TIME_SHIFT 20
1793+
#define EDP_PSR_SKIP_AUX_EXIT (1<<12)
1794+
#define EDP_PSR_TP1_TP2_SEL (0<<11)
1795+
#define EDP_PSR_TP1_TP3_SEL (1<<11)
1796+
#define EDP_PSR_TP2_TP3_TIME_500us (0<<8)
1797+
#define EDP_PSR_TP2_TP3_TIME_100us (1<<8)
1798+
#define EDP_PSR_TP2_TP3_TIME_2500us (2<<8)
1799+
#define EDP_PSR_TP2_TP3_TIME_0us (3<<8)
1800+
#define EDP_PSR_TP1_TIME_500us (0<<4)
1801+
#define EDP_PSR_TP1_TIME_100us (1<<4)
1802+
#define EDP_PSR_TP1_TIME_2500us (2<<4)
1803+
#define EDP_PSR_TP1_TIME_0us (3<<4)
1804+
#define EDP_PSR_IDLE_FRAME_SHIFT 0
1805+
1806+
#define EDP_PSR_AUX_CTL 0x64810
1807+
#define EDP_PSR_AUX_DATA1 0x64814
1808+
#define EDP_PSR_DPCD_COMMAND 0x80060000
1809+
#define EDP_PSR_AUX_DATA2 0x64818
1810+
#define EDP_PSR_DPCD_NORMAL_OPERATION (1<<24)
1811+
#define EDP_PSR_AUX_DATA3 0x6481c
1812+
#define EDP_PSR_AUX_DATA4 0x64820
1813+
#define EDP_PSR_AUX_DATA5 0x64824
1814+
1815+
#define EDP_PSR_STATUS_CTL 0x64840
1816+
#define EDP_PSR_STATUS_STATE_MASK (7<<29)
1817+
1818+
#define EDP_PSR_DEBUG_CTL 0x64860
1819+
#define EDP_PSR_DEBUG_MASK_LPSP (1<<27)
1820+
#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26)
1821+
#define EDP_PSR_DEBUG_MASK_HPD (1<<25)
1822+
17821823
/* VGA port control */
17831824
#define ADPA 0x61100
17841825
#define PCH_ADPA 0xe1100
@@ -2048,6 +2089,7 @@
20482089
* (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
20492090
* of the infoframe structure specified by CEA-861. */
20502091
#define VIDEO_DIP_DATA_SIZE 32
2092+
#define VIDEO_DIP_VSC_DATA_SIZE 36
20512093
#define VIDEO_DIP_CTL 0x61170
20522094
/* Pre HSW: */
20532095
#define VIDEO_DIP_ENABLE (1 << 31)

drivers/gpu/drm/i915/intel_dp.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,153 @@ static bool is_edp_psr(struct intel_dp *intel_dp)
13781378
intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
13791379
}
13801380

1381+
static bool intel_edp_is_psr_enabled(struct drm_device *dev)
1382+
{
1383+
struct drm_i915_private *dev_priv = dev->dev_private;
1384+
1385+
if (!IS_HASWELL(dev))
1386+
return false;
1387+
1388+
return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
1389+
}
1390+
1391+
static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
1392+
struct edp_vsc_psr *vsc_psr)
1393+
{
1394+
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
1395+
struct drm_device *dev = dig_port->base.base.dev;
1396+
struct drm_i915_private *dev_priv = dev->dev_private;
1397+
struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
1398+
u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
1399+
u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
1400+
uint32_t *data = (uint32_t *) vsc_psr;
1401+
unsigned int i;
1402+
1403+
/* As per BSPec (Pipe Video Data Island Packet), we need to disable
1404+
the video DIP being updated before program video DIP data buffer
1405+
registers for DIP being updated. */
1406+
I915_WRITE(ctl_reg, 0);
1407+
POSTING_READ(ctl_reg);
1408+
1409+
for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
1410+
if (i < sizeof(struct edp_vsc_psr))
1411+
I915_WRITE(data_reg + i, *data++);
1412+
else
1413+
I915_WRITE(data_reg + i, 0);
1414+
}
1415+
1416+
I915_WRITE(ctl_reg, VIDEO_DIP_ENABLE_VSC_HSW);
1417+
POSTING_READ(ctl_reg);
1418+
}
1419+
1420+
static void intel_edp_psr_setup(struct intel_dp *intel_dp)
1421+
{
1422+
struct drm_device *dev = intel_dp_to_dev(intel_dp);
1423+
struct drm_i915_private *dev_priv = dev->dev_private;
1424+
struct edp_vsc_psr psr_vsc;
1425+
1426+
if (intel_dp->psr_setup_done)
1427+
return;
1428+
1429+
/* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
1430+
memset(&psr_vsc, 0, sizeof(psr_vsc));
1431+
psr_vsc.sdp_header.HB0 = 0;
1432+
psr_vsc.sdp_header.HB1 = 0x7;
1433+
psr_vsc.sdp_header.HB2 = 0x2;
1434+
psr_vsc.sdp_header.HB3 = 0x8;
1435+
intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
1436+
1437+
/* Avoid continuous PSR exit by masking memup and hpd */
1438+
I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
1439+
EDP_PSR_DEBUG_MASK_HPD);
1440+
1441+
intel_dp->psr_setup_done = true;
1442+
}
1443+
1444+
static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
1445+
{
1446+
struct drm_device *dev = intel_dp_to_dev(intel_dp);
1447+
struct drm_i915_private *dev_priv = dev->dev_private;
1448+
uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp);
1449+
int precharge = 0x3;
1450+
int msg_size = 5; /* Header(4) + Message(1) */
1451+
1452+
/* Enable PSR in sink */
1453+
if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
1454+
intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
1455+
DP_PSR_ENABLE &
1456+
~DP_PSR_MAIN_LINK_ACTIVE);
1457+
else
1458+
intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
1459+
DP_PSR_ENABLE |
1460+
DP_PSR_MAIN_LINK_ACTIVE);
1461+
1462+
/* Setup AUX registers */
1463+
I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND);
1464+
I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION);
1465+
I915_WRITE(EDP_PSR_AUX_CTL,
1466+
DP_AUX_CH_CTL_TIME_OUT_400us |
1467+
(msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
1468+
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
1469+
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
1470+
}
1471+
1472+
static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
1473+
{
1474+
struct drm_device *dev = intel_dp_to_dev(intel_dp);
1475+
struct drm_i915_private *dev_priv = dev->dev_private;
1476+
uint32_t max_sleep_time = 0x1f;
1477+
uint32_t idle_frames = 1;
1478+
uint32_t val = 0x0;
1479+
1480+
if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) {
1481+
val |= EDP_PSR_LINK_STANDBY;
1482+
val |= EDP_PSR_TP2_TP3_TIME_0us;
1483+
val |= EDP_PSR_TP1_TIME_0us;
1484+
val |= EDP_PSR_SKIP_AUX_EXIT;
1485+
} else
1486+
val |= EDP_PSR_LINK_DISABLE;
1487+
1488+
I915_WRITE(EDP_PSR_CTL, val |
1489+
EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES |
1490+
max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
1491+
idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
1492+
EDP_PSR_ENABLE);
1493+
}
1494+
1495+
void intel_edp_psr_enable(struct intel_dp *intel_dp)
1496+
{
1497+
struct drm_device *dev = intel_dp_to_dev(intel_dp);
1498+
1499+
if (!is_edp_psr(intel_dp) || intel_edp_is_psr_enabled(dev))
1500+
return;
1501+
1502+
/* Setup PSR once */
1503+
intel_edp_psr_setup(intel_dp);
1504+
1505+
/* Enable PSR on the panel */
1506+
intel_edp_psr_enable_sink(intel_dp);
1507+
1508+
/* Enable PSR on the host */
1509+
intel_edp_psr_enable_source(intel_dp);
1510+
}
1511+
1512+
void intel_edp_psr_disable(struct intel_dp *intel_dp)
1513+
{
1514+
struct drm_device *dev = intel_dp_to_dev(intel_dp);
1515+
struct drm_i915_private *dev_priv = dev->dev_private;
1516+
1517+
if (!intel_edp_is_psr_enabled(dev))
1518+
return;
1519+
1520+
I915_WRITE(EDP_PSR_CTL, I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
1521+
1522+
/* Wait till PSR is idle */
1523+
if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
1524+
EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
1525+
DRM_ERROR("Timed out waiting for PSR Idle State\n");
1526+
}
1527+
13811528
static void intel_disable_dp(struct intel_encoder *encoder)
13821529
{
13831530
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -3189,6 +3336,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
31893336
WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
31903337
error, port_name(port));
31913338

3339+
intel_dp->psr_setup_done = false;
3340+
31923341
if (!intel_edp_init_connector(intel_dp, intel_connector)) {
31933342
i2c_del_adapter(&intel_dp->adapter);
31943343
if (is_edp(intel_dp)) {

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ struct intel_dp {
499499
int backlight_off_delay;
500500
struct delayed_work panel_vdd_work;
501501
bool want_panel_vdd;
502+
bool psr_setup_done;
502503
struct intel_connector *attached_connector;
503504
};
504505

@@ -834,4 +835,7 @@ extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
834835
enum transcoder pch_transcoder,
835836
bool enable);
836837

838+
extern void intel_edp_psr_enable(struct intel_dp *intel_dp);
839+
extern void intel_edp_psr_disable(struct intel_dp *intel_dp);
840+
837841
#endif /* __INTEL_DRV_H__ */

0 commit comments

Comments
 (0)