Skip to content

Commit ad7c53a

Browse files
C-Prime90mariobalanica
authored andcommitted
DisplayLib: Implement DisplayPort HPD, EDID and link probing
detect(), get_edid() and disable() were stubs, so the GOP always fell back to a blind PHY configuration at RBR with no link training and no picture unless Force Output was set by hand. Implement HPD detection from DPTX_HPD_STATUS, EDID retrieval over I2C-over-AUX (segment/offset addressing, 16-byte chunking, DEFER retries), and a proper power-down on disable(). Wire dw_dp_link_probe() in so a real sink now gets real link training, with the old blind path kept as a fallback for boards whose HPD isn't usable. Also implement AnalogixDpConnectorGetEdid() for eDP, though eDP still can't be enabled anywhere since EdpEnableBacklight() has no platform implementation.
1 parent d01545f commit ad7c53a

2 files changed

Lines changed: 294 additions & 7 deletions

File tree

‎edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.c‎

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,8 +1306,74 @@ AnalogixDpConnectorGetEdid (
13061306
OUT DISPLAY_STATE *DisplayState
13071307
)
13081308
{
1309-
// Todo
1310-
return 0;
1309+
struct AnalogixDpDevice *Dp;
1310+
CONNECTOR_STATE *ConnectorState;
1311+
EFI_STATUS Status;
1312+
UINT32 BlockIndex;
1313+
UINT32 Extensions;
1314+
UINT8 *Buffer;
1315+
UINTN Retry;
1316+
INTN Ret;
1317+
1318+
Dp = ANALOGIX_DP_FROM_CONNECTOR_PROTOCOL (This);
1319+
ConnectorState = &DisplayState->ConnectorState;
1320+
1321+
//
1322+
// The AUX I2C helper has no E-DDC segment support, so only the first two
1323+
// blocks are reachable. eDP panels virtually always report a single block.
1324+
//
1325+
for (BlockIndex = 0, Extensions = 0; BlockIndex <= Extensions; BlockIndex++) {
1326+
if (BlockIndex > 1) {
1327+
DEBUG ((
1328+
DEBUG_WARN,
1329+
"%a: Ignoring EDID block %u, segment addressing is unsupported.\n",
1330+
__func__,
1331+
BlockIndex
1332+
));
1333+
break;
1334+
}
1335+
1336+
Buffer = EDID_BLOCK (ConnectorState->Edid, BlockIndex);
1337+
1338+
for (Retry = 3; Retry > 0; Retry--) {
1339+
Ret = AnalogixDpReadBytesFromI2c (
1340+
Dp,
1341+
I2C_EDID_DEVICE_ADDR,
1342+
BlockIndex * EDID_BLOCK_LENGTH,
1343+
EDID_BLOCK_LENGTH,
1344+
Buffer
1345+
);
1346+
if (Ret != 0) {
1347+
DEBUG ((
1348+
DEBUG_ERROR,
1349+
"%a: Failed to read EDID block %u over AUX.\n",
1350+
__func__,
1351+
BlockIndex
1352+
));
1353+
return EFI_DEVICE_ERROR;
1354+
}
1355+
1356+
Status = CheckEdidBlock (Buffer, BlockIndex);
1357+
if (!EFI_ERROR (Status)) {
1358+
break;
1359+
}
1360+
1361+
/* Might be corrupted due to a bus condition, try again. */
1362+
}
1363+
1364+
if (Retry == 0) {
1365+
return Status;
1366+
}
1367+
1368+
if (BlockIndex == 0) {
1369+
Extensions = ((EDID_BASE *)ConnectorState->Edid)->ExtensionFlag;
1370+
if (Extensions > EDID_MAX_EXTENSION_BLOCKS) {
1371+
Extensions = EDID_MAX_EXTENSION_BLOCKS;
1372+
}
1373+
}
1374+
}
1375+
1376+
return EFI_SUCCESS;
13111377
}
13121378

13131379
EFI_STATUS

‎edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.c‎

Lines changed: 226 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,29 @@ static int dw_dp_link_power_up(struct dw_dp *dp)
554554
return 0;
555555
}
556556

557+
static int dw_dp_link_power_down(struct dw_dp *dp)
558+
{
559+
struct dw_dp_link *link = &dp->link;
560+
u8 value;
561+
int ret;
562+
563+
if (link->revision < 0x11)
564+
return 0;
565+
566+
ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value);
567+
if (ret < 0)
568+
return ret;
569+
570+
value &= ~DP_SET_POWER_MASK;
571+
value |= DP_SET_POWER_D3;
572+
573+
ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value);
574+
if (ret < 0)
575+
return ret;
576+
577+
return 0;
578+
}
579+
557580
static int dw_dp_link_probe(struct dw_dp *dp)
558581
{
559582
struct dw_dp_link *link = &dp->link;
@@ -1423,8 +1446,143 @@ static int dw_dp_connector_init(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE
14231446
return ret;
14241447
}
14251448

1449+
/*
1450+
* I2C-over-AUX, used to reach the sink's DDC bus for EDID. The controller can
1451+
* move at most 16 bytes (AUX_LEN_REQ is 4 bits wide, and there are only four
1452+
* DPTX_AUX_DATA registers) per transaction, so larger reads are chunked.
1453+
*/
1454+
#define DDC_ADDR 0x50
1455+
#define DDC_SEGMENT_ADDR 0x30
1456+
#define AUX_I2C_MAX_TRANSFER_SIZE 16
1457+
#define AUX_I2C_RETRIES 7
1458+
#define AUX_I2C_RETRY_INTERVAL 500 /* us */
1459+
1460+
static int dw_dp_aux_i2c_xfer(struct dw_dp *dp, u8 address, u8 request,
1461+
void *buffer, size_t size)
1462+
{
1463+
struct drm_dp_aux_msg msg;
1464+
unsigned int retry;
1465+
ssize_t ret = -EIO;
1466+
1467+
memset(&msg, 0, sizeof(msg));
1468+
msg.address = address;
1469+
msg.request = request;
1470+
msg.buffer = buffer;
1471+
msg.size = size;
1472+
1473+
for (retry = 0; retry < AUX_I2C_RETRIES; retry++) {
1474+
ret = dp->aux.transfer(&dp->aux, &msg);
1475+
if (ret < 0) {
1476+
/*
1477+
* A short read is reported as -EBUSY and is worth
1478+
* another attempt; anything else is fatal.
1479+
*/
1480+
if (ret == -EBUSY)
1481+
continue;
1482+
return ret;
1483+
}
1484+
1485+
if ((msg.reply & DP_AUX_NATIVE_REPLY_MASK) !=
1486+
DP_AUX_NATIVE_REPLY_ACK)
1487+
return -EIO;
1488+
1489+
switch (msg.reply & DP_AUX_I2C_REPLY_MASK) {
1490+
case DP_AUX_I2C_REPLY_ACK:
1491+
if (size > 0 && (size_t)ret != size)
1492+
return -EPROTO;
1493+
return 0;
1494+
case DP_AUX_I2C_REPLY_DEFER:
1495+
udelay(AUX_I2C_RETRY_INTERVAL);
1496+
continue;
1497+
default:
1498+
return -EIO;
1499+
}
1500+
}
1501+
1502+
return -ETIMEDOUT;
1503+
}
1504+
1505+
/* Terminate the DDC transaction with an address-only cycle, MOT cleared. */
1506+
static void dw_dp_aux_i2c_stop(struct dw_dp *dp)
1507+
{
1508+
dw_dp_aux_i2c_xfer(dp, DDC_ADDR, DP_AUX_I2C_WRITE, NULL, 0);
1509+
}
1510+
1511+
static int dw_dp_read_edid_block(struct dw_dp *dp, u8 block, u8 *buffer)
1512+
{
1513+
u8 segment = block >> 1;
1514+
u8 offset = (block & 1) * EDID_BLOCK_SIZE;
1515+
size_t done;
1516+
int ret;
1517+
1518+
/*
1519+
* E-DDC segment select. Sinks with two blocks or fewer don't implement
1520+
* it and are allowed to NAK the address, so only send it when a segment
1521+
* beyond the first is actually needed.
1522+
*/
1523+
if (segment) {
1524+
ret = dw_dp_aux_i2c_xfer(dp, DDC_SEGMENT_ADDR,
1525+
DP_AUX_I2C_WRITE | DP_AUX_I2C_MOT,
1526+
&segment, 1);
1527+
if (ret < 0)
1528+
goto out;
1529+
}
1530+
1531+
ret = dw_dp_aux_i2c_xfer(dp, DDC_ADDR,
1532+
DP_AUX_I2C_WRITE | DP_AUX_I2C_MOT,
1533+
&offset, 1);
1534+
if (ret < 0)
1535+
goto out;
1536+
1537+
for (done = 0; done < EDID_BLOCK_SIZE; done += AUX_I2C_MAX_TRANSFER_SIZE) {
1538+
ret = dw_dp_aux_i2c_xfer(dp, DDC_ADDR,
1539+
DP_AUX_I2C_READ | DP_AUX_I2C_MOT,
1540+
buffer + done,
1541+
AUX_I2C_MAX_TRANSFER_SIZE);
1542+
if (ret < 0)
1543+
goto out;
1544+
}
1545+
1546+
out:
1547+
dw_dp_aux_i2c_stop(dp);
1548+
return ret;
1549+
}
1550+
14261551
static int dw_dp_connector_get_edid(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state)
14271552
{
1553+
CONNECTOR_STATE *conn_state = &state->ConnectorState;
1554+
struct dw_dp *dp = DW_DP_FROM_CONNECTOR_PROTOCOL (conn);
1555+
u32 block, extensions;
1556+
u8 *buffer;
1557+
int retry, ret = -EIO;
1558+
1559+
for (block = 0, extensions = 0; block <= extensions; block++) {
1560+
buffer = EDID_BLOCK (conn_state->Edid, block);
1561+
1562+
for (retry = AUX_I2C_RETRIES; retry > 0; retry--) {
1563+
ret = dw_dp_read_edid_block(dp, block, buffer);
1564+
if (ret < 0)
1565+
return ret;
1566+
1567+
/* Might be corrupted due to a bus condition, try again. */
1568+
if (EFI_ERROR (CheckEdidBlock (buffer, block)))
1569+
continue;
1570+
1571+
break;
1572+
}
1573+
1574+
if (retry == 0) {
1575+
printf("EDID block %u is invalid\n", block);
1576+
return -EINVAL;
1577+
}
1578+
1579+
if (block == 0) {
1580+
extensions = ((EDID_BASE *)conn_state->Edid)->ExtensionFlag;
1581+
if (extensions > EDID_MAX_EXTENSION_BLOCKS)
1582+
extensions = EDID_MAX_EXTENSION_BLOCKS;
1583+
}
1584+
}
1585+
14281586
return 0;
14291587
}
14301588

@@ -1480,8 +1638,19 @@ static int dw_dp_connector_enable(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STA
14801638
} else {
14811639
ret = dw_dp_link_enable(dp);
14821640
if (ret < 0) {
1483-
printf("failed to enable link: %d\n", ret);
1484-
return ret;
1641+
/*
1642+
* Training failed against a sink that did answer on
1643+
* AUX. Rather than leaving the user with no picture,
1644+
* fall back to the blind configuration.
1645+
*/
1646+
printf("failed to enable link: %d, forcing output\n", ret);
1647+
1648+
dp->force_output = true;
1649+
ret = dw_dp_set_phy_default_config(dp);
1650+
if (ret < 0) {
1651+
printf("failed to set phy_default config: %d\n", ret);
1652+
return ret;
1653+
}
14851654
}
14861655
}
14871656

@@ -1496,15 +1665,57 @@ static int dw_dp_connector_enable(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STA
14961665

14971666
static int dw_dp_connector_disable(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state)
14981667
{
1499-
/* TODO */
1668+
struct dw_dp *dp = DW_DP_FROM_CONNECTOR_PROTOCOL (conn);
1669+
1670+
/* Stop the video stream. */
1671+
regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE,
1672+
FIELD_PREP(VIDEO_STREAM_ENABLE, 0));
1673+
1674+
/* Stop the link and park the PHY in P3. */
1675+
dw_dp_phy_xmit_enable(dp, 0);
1676+
regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
1677+
FIELD_PREP(PHY_POWERDOWN, 0x3));
1678+
1679+
/*
1680+
* Put the sink back into D3. Only meaningful once we've talked DPCD to
1681+
* it, which doesn't happen when the link was forced up blindly.
1682+
*/
1683+
if (!dp->force_output)
1684+
dw_dp_link_power_down(dp);
1685+
1686+
dp->phy->PowerOff (dp->phy);
15001687

15011688
return 0;
15021689
}
15031690

15041691
static int dw_dp_connector_detect(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state)
15051692
{
1506-
/* TODO */
1507-
return -ENODEV;
1693+
struct dw_dp *dp = DW_DP_FROM_CONNECTOR_PROTOCOL (conn);
1694+
u32 value;
1695+
int ret;
1696+
1697+
if (!dp->force_hpd) {
1698+
regmap_read(dp->regmap, DPTX_HPD_STATUS, &value);
1699+
1700+
if (FIELD_GET(HPD_STATE, value) != SOURCE_STATE_PLUG)
1701+
return -ENODEV;
1702+
}
1703+
1704+
/*
1705+
* A sink is there, so read its capabilities over AUX. Succeeding here
1706+
* is what lets us train the link properly; if the sink won't talk, we
1707+
* leave force_output set and fall back to the blind configuration that
1708+
* this driver has always used.
1709+
*/
1710+
ret = dw_dp_link_probe(dp);
1711+
if (ret < 0) {
1712+
printf("failed to probe DP link: %d\n", ret);
1713+
return 0;
1714+
}
1715+
1716+
dp->force_output = false;
1717+
1718+
return 0;
15081719
}
15091720

15101721
static int dw_dp_ddc_init(struct dw_dp *dp)
@@ -1674,6 +1885,16 @@ DpPhyRegistrationEventHandler (
16741885
if (DwDp->id == DpPhy->Id && (PcdGet32 (PcdDisplayConnectorsMask) & DwDp->output_if)) {
16751886
DwDp->Signature = DW_DP_SIGNATURE;
16761887
DwDp->phy = DpPhy;
1888+
/*
1889+
* Assume HBR3 and let dw_dp_link_probe() clamp
1890+
* it down to what the PHY and the sink support.
1891+
*/
1892+
DwDp->max_link_rate = 810000;
1893+
/*
1894+
* Cleared by a successful detect. Until then we
1895+
* keep the historical blind-output behaviour, so
1896+
* boards whose HPD isn't usable are unaffected.
1897+
*/
16771898
DwDp->force_output = TRUE;
16781899
CopyMem (&DwDp->connector, &mDpConnectorOps, sizeof (ROCKCHIP_CONNECTOR_PROTOCOL));
16791900
dw_dp_ddc_init (DwDp);

0 commit comments

Comments
 (0)