|
@@ -31,6 +31,7 @@
|
|
|
|
|
|
|
|
#include <linux/irq.h>
|
|
#include <linux/irq.h>
|
|
|
#include <linux/of_irq.h>
|
|
#include <linux/of_irq.h>
|
|
|
|
|
+#include <linux/of_device.h>
|
|
|
|
|
|
|
|
#include <asm/unaligned.h>
|
|
#include <asm/unaligned.h>
|
|
|
|
|
|
|
@@ -84,6 +85,11 @@
|
|
|
#define FW_STANDBY 0
|
|
#define FW_STANDBY 0
|
|
|
#define FW_ACTIVE 1
|
|
#define FW_ACTIVE 1
|
|
|
|
|
|
|
|
|
|
+#define DPTX_READ_EVENT_HPD_TO_HIGH BIT(0)
|
|
|
|
|
+#define DPTX_READ_EVENT_HPD_TO_LOW BIT(1)
|
|
|
|
|
+#define DPTX_READ_EVENT_HPD_PULSE BIT(2)
|
|
|
|
|
+#define DPTX_READ_EVENT_HPD_STATE BIT(3)
|
|
|
|
|
+
|
|
|
static inline u32 get_unaligned_be24(const void *p)
|
|
static inline u32 get_unaligned_be24(const void *p)
|
|
|
{
|
|
{
|
|
|
const u8 *_p = p;
|
|
const u8 *_p = p;
|
|
@@ -104,6 +110,8 @@ static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
|
|
|
{
|
|
{
|
|
|
int val, ret;
|
|
int val, ret;
|
|
|
|
|
|
|
|
|
|
+ WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
|
|
|
|
|
+
|
|
|
ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_EMPTY,
|
|
ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_EMPTY,
|
|
|
val, !val, MAILBOX_RETRY_US,
|
|
val, !val, MAILBOX_RETRY_US,
|
|
|
MAILBOX_TIMEOUT_US);
|
|
MAILBOX_TIMEOUT_US);
|
|
@@ -117,6 +125,8 @@ static int cdp_dp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)
|
|
|
{
|
|
{
|
|
|
int ret, full;
|
|
int ret, full;
|
|
|
|
|
|
|
|
|
|
+ WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex));
|
|
|
|
|
+
|
|
|
ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_FULL,
|
|
ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_FULL,
|
|
|
full, !full, MAILBOX_RETRY_US,
|
|
full, !full, MAILBOX_RETRY_US,
|
|
|
MAILBOX_TIMEOUT_US);
|
|
MAILBOX_TIMEOUT_US);
|
|
@@ -218,6 +228,8 @@ int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr, u32 *value)
|
|
|
|
|
|
|
|
put_unaligned_be32(addr, msg);
|
|
put_unaligned_be32(addr, msg);
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
|
|
|
GENERAL_REGISTER_READ,
|
|
GENERAL_REGISTER_READ,
|
|
|
sizeof(msg), msg);
|
|
sizeof(msg), msg);
|
|
@@ -243,6 +255,7 @@ int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr, u32 *value)
|
|
|
*value = get_unaligned_be32(resp + 4);
|
|
*value = get_unaligned_be32(resp + 4);
|
|
|
|
|
|
|
|
err_reg_read:
|
|
err_reg_read:
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
if (ret) {
|
|
if (ret) {
|
|
|
DRM_DEV_ERROR(mhdp->dev, "Failed to read register.\n");
|
|
DRM_DEV_ERROR(mhdp->dev, "Failed to read register.\n");
|
|
|
*value = 0;
|
|
*value = 0;
|
|
@@ -255,12 +268,19 @@ static
|
|
|
int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val)
|
|
int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val)
|
|
|
{
|
|
{
|
|
|
u8 msg[6];
|
|
u8 msg[6];
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
|
|
put_unaligned_be16(addr, msg);
|
|
put_unaligned_be16(addr, msg);
|
|
|
put_unaligned_be32(val, msg + 2);
|
|
put_unaligned_be32(val, msg + 2);
|
|
|
|
|
|
|
|
- return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
|
|
- DPTX_WRITE_REGISTER, sizeof(msg), msg);
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
|
|
+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
|
|
+ DPTX_WRITE_REGISTER, sizeof(msg), msg);
|
|
|
|
|
+
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
|
|
+ return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static
|
|
static
|
|
@@ -268,14 +288,21 @@ int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
|
|
|
u8 start_bit, u8 bits_no, u32 val)
|
|
u8 start_bit, u8 bits_no, u32 val)
|
|
|
{
|
|
{
|
|
|
u8 field[8];
|
|
u8 field[8];
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
|
|
put_unaligned_be16(addr, field);
|
|
put_unaligned_be16(addr, field);
|
|
|
field[2] = start_bit;
|
|
field[2] = start_bit;
|
|
|
field[3] = bits_no;
|
|
field[3] = bits_no;
|
|
|
put_unaligned_be32(val, field + 4);
|
|
put_unaligned_be32(val, field + 4);
|
|
|
|
|
|
|
|
- return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
|
|
- DPTX_WRITE_FIELD, sizeof(field), field);
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
|
|
+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
|
|
+ DPTX_WRITE_FIELD, sizeof(field), field);
|
|
|
|
|
+
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
|
|
+ return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static
|
|
static
|
|
@@ -288,6 +315,8 @@ int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
|
|
|
put_unaligned_be16(len, msg);
|
|
put_unaligned_be16(len, msg);
|
|
|
put_unaligned_be24(addr, msg + 2);
|
|
put_unaligned_be24(addr, msg + 2);
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
DPTX_READ_DPCD, sizeof(msg), msg);
|
|
DPTX_READ_DPCD, sizeof(msg), msg);
|
|
|
if (ret)
|
|
if (ret)
|
|
@@ -306,6 +335,8 @@ int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
|
|
|
ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
|
|
ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
|
|
|
|
|
|
|
|
err_dpcd_read:
|
|
err_dpcd_read:
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -319,6 +350,8 @@ int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
|
|
|
put_unaligned_be24(addr, msg + 2);
|
|
put_unaligned_be24(addr, msg + 2);
|
|
|
msg[5] = value;
|
|
msg[5] = value;
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
DPTX_WRITE_DPCD, sizeof(msg), msg);
|
|
DPTX_WRITE_DPCD, sizeof(msg), msg);
|
|
|
if (ret)
|
|
if (ret)
|
|
@@ -337,6 +370,8 @@ int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
|
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
|
|
|
|
|
|
err_dpcd_write:
|
|
err_dpcd_write:
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
if (ret)
|
|
if (ret)
|
|
|
DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
|
|
DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
|
|
|
return ret;
|
|
return ret;
|
|
@@ -354,6 +389,8 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
|
|
|
msg[3] = 1;
|
|
msg[3] = 1;
|
|
|
msg[4] = enable ? FW_ACTIVE : FW_STANDBY;
|
|
msg[4] = enable ? FW_ACTIVE : FW_STANDBY;
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
for (i = 0; i < sizeof(msg); i++) {
|
|
for (i = 0; i < sizeof(msg); i++) {
|
|
|
ret = cdp_dp_mailbox_write(mhdp, msg[i]);
|
|
ret = cdp_dp_mailbox_write(mhdp, msg[i]);
|
|
|
if (ret)
|
|
if (ret)
|
|
@@ -372,6 +409,8 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
|
|
|
ret = 0;
|
|
ret = 0;
|
|
|
|
|
|
|
|
err_set_firmware_active:
|
|
err_set_firmware_active:
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
|
DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
|
|
DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
|
|
|
return ret;
|
|
return ret;
|
|
@@ -383,6 +422,8 @@ int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp)
|
|
|
u8 status;
|
|
u8 status;
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
DPTX_HPD_STATE, 0, NULL);
|
|
DPTX_HPD_STATE, 0, NULL);
|
|
|
if (ret)
|
|
if (ret)
|
|
@@ -398,9 +439,13 @@ int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp)
|
|
|
if (ret)
|
|
if (ret)
|
|
|
goto err_get_hpd;
|
|
goto err_get_hpd;
|
|
|
|
|
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
return status;
|
|
return status;
|
|
|
|
|
|
|
|
err_get_hpd:
|
|
err_get_hpd:
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
DRM_DEV_ERROR(mhdp->dev, "get hpd status failed: %d\n", ret);
|
|
DRM_DEV_ERROR(mhdp->dev, "get hpd status failed: %d\n", ret);
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
@@ -413,6 +458,8 @@ int cdns_mhdp_get_edid_block(void *data, u8 *edid,
|
|
|
u8 msg[2], reg[2], i;
|
|
u8 msg[2], reg[2], i;
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
for (i = 0; i < 4; i++) {
|
|
for (i = 0; i < 4; i++) {
|
|
|
msg[0] = block / 2;
|
|
msg[0] = block / 2;
|
|
|
msg[1] = block % 2;
|
|
msg[1] = block % 2;
|
|
@@ -441,6 +488,8 @@ int cdns_mhdp_get_edid_block(void *data, u8 *edid,
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
if (ret)
|
|
if (ret)
|
|
|
DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n",
|
|
DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n",
|
|
|
block, ret);
|
|
block, ret);
|
|
@@ -448,26 +497,31 @@ int cdns_mhdp_get_edid_block(void *data, u8 *edid,
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static __maybe_unused
|
|
|
|
|
|
|
+static
|
|
|
int cdns_mhdp_read_event(struct cdns_mhdp_device *mhdp)
|
|
int cdns_mhdp_read_event(struct cdns_mhdp_device *mhdp)
|
|
|
{
|
|
{
|
|
|
u8 event = 0;
|
|
u8 event = 0;
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
DPTX_READ_EVENT, 0, NULL);
|
|
DPTX_READ_EVENT, 0, NULL);
|
|
|
if (ret)
|
|
if (ret)
|
|
|
- return ret;
|
|
|
|
|
|
|
+ goto out;
|
|
|
|
|
|
|
|
ret = cdns_mhdp_mailbox_validate_receive(mhdp,
|
|
ret = cdns_mhdp_mailbox_validate_receive(mhdp,
|
|
|
MB_MODULE_ID_DP_TX,
|
|
MB_MODULE_ID_DP_TX,
|
|
|
DPTX_READ_EVENT,
|
|
DPTX_READ_EVENT,
|
|
|
sizeof(event));
|
|
sizeof(event));
|
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
|
- return ret;
|
|
|
|
|
|
|
+ goto out;
|
|
|
|
|
|
|
|
ret = cdns_mhdp_mailbox_read_receive(mhdp, &event,
|
|
ret = cdns_mhdp_mailbox_read_receive(mhdp, &event,
|
|
|
sizeof(event));
|
|
sizeof(event));
|
|
|
|
|
+out:
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
|
@@ -476,7 +530,7 @@ int cdns_mhdp_read_event(struct cdns_mhdp_device *mhdp)
|
|
|
|
|
|
|
|
static
|
|
static
|
|
|
int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp,
|
|
int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp,
|
|
|
- u8 nlanes, u16 udelay, u8 *lanes_data, u8 *dpcd)
|
|
|
|
|
|
|
+ u8 nlanes, u16 udelay, u8 *lanes_data, u8 *link_status)
|
|
|
{
|
|
{
|
|
|
u8 payload[7];
|
|
u8 payload[7];
|
|
|
u8 hdr[5]; /* For DPCD read response header */
|
|
u8 hdr[5]; /* For DPCD read response header */
|
|
@@ -495,6 +549,8 @@ int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp,
|
|
|
put_unaligned_be16(udelay, payload + 1);
|
|
put_unaligned_be16(udelay, payload + 1);
|
|
|
memcpy(payload + 3, lanes_data, nlanes);
|
|
memcpy(payload + 3, lanes_data, nlanes);
|
|
|
|
|
|
|
|
|
|
+ mutex_lock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
|
|
DPTX_ADJUST_LT,
|
|
DPTX_ADJUST_LT,
|
|
|
sizeof(payload), payload);
|
|
sizeof(payload), payload);
|
|
@@ -516,9 +572,11 @@ int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp,
|
|
|
if (addr != DP_LANE0_1_STATUS)
|
|
if (addr != DP_LANE0_1_STATUS)
|
|
|
goto err_adjust_lt;
|
|
goto err_adjust_lt;
|
|
|
|
|
|
|
|
- ret = cdns_mhdp_mailbox_read_receive(mhdp, dpcd, nregs);
|
|
|
|
|
|
|
+ ret = cdns_mhdp_mailbox_read_receive(mhdp, link_status, nregs);
|
|
|
|
|
|
|
|
err_adjust_lt:
|
|
err_adjust_lt:
|
|
|
|
|
+ mutex_unlock(&mhdp->mbox_mutex);
|
|
|
|
|
+
|
|
|
if (ret)
|
|
if (ret)
|
|
|
DRM_DEV_ERROR(mhdp->dev, "Failed to adjust Link Training.\n");
|
|
DRM_DEV_ERROR(mhdp->dev, "Failed to adjust Link Training.\n");
|
|
|
|
|
|
|
@@ -534,8 +592,20 @@ err_adjust_lt:
|
|
|
|
|
|
|
|
#define CDNS_KEEP_ALIVE_TIMEOUT 2000
|
|
#define CDNS_KEEP_ALIVE_TIMEOUT 2000
|
|
|
|
|
|
|
|
|
|
+#ifdef CONFIG_DRM_CDNS_MHDP_J721E
|
|
|
|
|
+static const struct mhdp_platform_ops mhdp_ti_j721e_ops = {
|
|
|
|
|
+ .init = cdns_mhdp_j721e_init,
|
|
|
|
|
+ .exit = cdns_mhdp_j721e_fini,
|
|
|
|
|
+ .enable = cdns_mhdp_j721e_enable,
|
|
|
|
|
+ .disable = cdns_mhdp_j721e_disable,
|
|
|
|
|
+};
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
static const struct of_device_id mhdp_ids[] = {
|
|
static const struct of_device_id mhdp_ids[] = {
|
|
|
{ .compatible = "cdns,mhdp8546", },
|
|
{ .compatible = "cdns,mhdp8546", },
|
|
|
|
|
+#ifdef CONFIG_DRM_CDNS_MHDP_J721E
|
|
|
|
|
+ { .compatible = "ti,j721e-mhdp8546", .data = &mhdp_ti_j721e_ops },
|
|
|
|
|
+#endif
|
|
|
{ /* sentinel */ }
|
|
{ /* sentinel */ }
|
|
|
};
|
|
};
|
|
|
MODULE_DEVICE_TABLE(of, mhdp_ids);
|
|
MODULE_DEVICE_TABLE(of, mhdp_ids);
|
|
@@ -713,6 +783,53 @@ static int load_firmware(struct cdns_mhdp_device *mhdp)
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void mhdp_check_link(struct cdns_mhdp_device *mhdp)
|
|
|
|
|
+{
|
|
|
|
|
+ struct drm_connector *conn = &mhdp->connector;
|
|
|
|
|
+ u8 status[DP_LINK_STATUS_SIZE];
|
|
|
|
|
+ bool hpd_state;
|
|
|
|
|
+ int hpd_event;
|
|
|
|
|
+ int ret;
|
|
|
|
|
+
|
|
|
|
|
+ /* Nothing to check if there is no link */
|
|
|
|
|
+ if (!mhdp->link_up)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ hpd_event = cdns_mhdp_read_event(mhdp);
|
|
|
|
|
+
|
|
|
|
|
+ /* Geting event bits failed, bail out */
|
|
|
|
|
+ if (hpd_event < 0) {
|
|
|
|
|
+ dev_warn(mhdp->dev, "%s: read event failed: %d\n",
|
|
|
|
|
+ __func__, hpd_event);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ hpd_state = !!(hpd_event & DPTX_READ_EVENT_HPD_STATE);
|
|
|
|
|
+
|
|
|
|
|
+ /* No point the check the link if HPD is down (cable is unplugged) */
|
|
|
|
|
+ if (!hpd_state)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Prevent display reconfiguration between link check and link
|
|
|
|
|
+ * status property setting. We must use the legacy giant-lock
|
|
|
|
|
+ * since drm_connector_set_link_status_property()'s fine
|
|
|
|
|
+ * grained DRM locking implementation is broken.
|
|
|
|
|
+ */
|
|
|
|
|
+ mutex_lock(&conn->dev->mode_config.mutex);
|
|
|
|
|
+
|
|
|
|
|
+ /* Check if the link is still up */
|
|
|
|
|
+ ret = drm_dp_dpcd_read_link_status(&mhdp->aux, status);
|
|
|
|
|
+
|
|
|
|
|
+ if (ret < 0 || /* If dpcd read fails, assume the link is down too */
|
|
|
|
|
+ !drm_dp_channel_eq_ok(status, mhdp->link.num_lanes) ||
|
|
|
|
|
+ !drm_dp_clock_recovery_ok(status, mhdp->link.num_lanes))
|
|
|
|
|
+ /* Link is broken, indicate it with the link status property */
|
|
|
|
|
+ drm_connector_set_link_status_property(conn, DRM_MODE_LINK_STATUS_BAD);
|
|
|
|
|
+
|
|
|
|
|
+ mutex_unlock(&conn->dev->mode_config.mutex);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static irqreturn_t mhdp_irq_handler(int irq, void *data)
|
|
static irqreturn_t mhdp_irq_handler(int irq, void *data)
|
|
|
{
|
|
{
|
|
|
struct cdns_mhdp_device *mhdp = (struct cdns_mhdp_device *)data;
|
|
struct cdns_mhdp_device *mhdp = (struct cdns_mhdp_device *)data;
|
|
@@ -738,8 +855,11 @@ static irqreturn_t mhdp_irq_handler(int irq, void *data)
|
|
|
bridge_attached = mhdp->bridge_attached;
|
|
bridge_attached = mhdp->bridge_attached;
|
|
|
spin_unlock(&mhdp->start_lock);
|
|
spin_unlock(&mhdp->start_lock);
|
|
|
|
|
|
|
|
- if (bridge_attached && (sw_ev0 & CDNS_DPTX_HPD))
|
|
|
|
|
|
|
+ if (bridge_attached && (sw_ev0 & CDNS_DPTX_HPD)) {
|
|
|
|
|
+ mhdp_check_link(mhdp);
|
|
|
|
|
+
|
|
|
drm_kms_helper_hotplug_event(mhdp->bridge.dev);
|
|
drm_kms_helper_hotplug_event(mhdp->bridge.dev);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
}
|
|
@@ -802,13 +922,15 @@ static int cdns_mhdp_get_modes(struct drm_connector *connector)
|
|
|
* HACK: Warn about unsupported display formats until we deal
|
|
* HACK: Warn about unsupported display formats until we deal
|
|
|
* with them correctly.
|
|
* with them correctly.
|
|
|
*/
|
|
*/
|
|
|
- if (!(connector->display_info.color_formats &
|
|
|
|
|
|
|
+ if (connector->display_info.color_formats &&
|
|
|
|
|
+ !(connector->display_info.color_formats &
|
|
|
mhdp->display_fmt.color_format))
|
|
mhdp->display_fmt.color_format))
|
|
|
dev_warn(mhdp->dev,
|
|
dev_warn(mhdp->dev,
|
|
|
"%s: No supported color_format found (0x%08x)\n",
|
|
"%s: No supported color_format found (0x%08x)\n",
|
|
|
__func__, connector->display_info.color_formats);
|
|
__func__, connector->display_info.color_formats);
|
|
|
|
|
|
|
|
- if (connector->display_info.bpc < mhdp->display_fmt.bpc)
|
|
|
|
|
|
|
+ if (connector->display_info.bpc &&
|
|
|
|
|
+ connector->display_info.bpc < mhdp->display_fmt.bpc)
|
|
|
dev_warn(mhdp->dev, "%s: Display bpc only %d < %d\n",
|
|
dev_warn(mhdp->dev, "%s: Display bpc only %d < %d\n",
|
|
|
__func__, connector->display_info.bpc,
|
|
__func__, connector->display_info.bpc,
|
|
|
mhdp->display_fmt.bpc);
|
|
mhdp->display_fmt.bpc);
|
|
@@ -848,9 +970,46 @@ static int cdns_mhdp_detect(struct drm_connector *conn,
|
|
|
return connector_status_disconnected;
|
|
return connector_status_disconnected;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static
|
|
|
|
|
+bool cdns_mhdp_bandwidth_ok(struct cdns_mhdp_device *mhdp,
|
|
|
|
|
+ const struct drm_display_mode *mode,
|
|
|
|
|
+ int lanes, int rate)
|
|
|
|
|
+{
|
|
|
|
|
+ u32 max_bw, req_bw, bpp;
|
|
|
|
|
+
|
|
|
|
|
+ bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt);
|
|
|
|
|
+ req_bw = mode->clock * bpp / 8;
|
|
|
|
|
+
|
|
|
|
|
+ max_bw = lanes * rate;
|
|
|
|
|
+
|
|
|
|
|
+ if (req_bw > max_bw) {
|
|
|
|
|
+ dev_dbg(mhdp->dev, "%s: %s (%u * %u/8 =) %u > %u (= %u * %u)\n",
|
|
|
|
|
+ __func__, mode->name, mode->clock, bpp, req_bw,
|
|
|
|
|
+ max_bw, lanes, rate);
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static
|
|
|
|
|
+enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn,
|
|
|
|
|
+ struct drm_display_mode *mode)
|
|
|
|
|
+{
|
|
|
|
|
+ struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn);
|
|
|
|
|
+
|
|
|
|
|
+ if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->host.lanes_cnt,
|
|
|
|
|
+ mhdp->host.link_rate))
|
|
|
|
|
+ return MODE_CLOCK_HIGH;
|
|
|
|
|
+
|
|
|
|
|
+ return MODE_OK;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = {
|
|
static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = {
|
|
|
.detect_ctx = cdns_mhdp_detect,
|
|
.detect_ctx = cdns_mhdp_detect,
|
|
|
.get_modes = cdns_mhdp_get_modes,
|
|
.get_modes = cdns_mhdp_get_modes,
|
|
|
|
|
+ .mode_valid = cdns_mhdp_mode_valid,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static const struct drm_connector_funcs cdns_mhdp_conn_funcs = {
|
|
static const struct drm_connector_funcs cdns_mhdp_conn_funcs = {
|
|
@@ -1062,7 +1221,7 @@ static bool mhdp_link_training_channel_eq(struct cdns_mhdp_device *mhdp,
|
|
|
unsigned int training_interval)
|
|
unsigned int training_interval)
|
|
|
{
|
|
{
|
|
|
u8 lanes_data[CDNS_DP_MAX_NUM_LANES], fail_counter_short = 0;
|
|
u8 lanes_data[CDNS_DP_MAX_NUM_LANES], fail_counter_short = 0;
|
|
|
- u8 dpcd[DP_LINK_STATUS_SIZE];
|
|
|
|
|
|
|
+ u8 link_status[DP_LINK_STATUS_SIZE];
|
|
|
u32 reg32;
|
|
u32 reg32;
|
|
|
union phy_configure_opts phy_cfg;
|
|
union phy_configure_opts phy_cfg;
|
|
|
|
|
|
|
@@ -1079,10 +1238,10 @@ static bool mhdp_link_training_channel_eq(struct cdns_mhdp_device *mhdp,
|
|
|
(eq_tps != 4) ? eq_tps | DP_LINK_SCRAMBLING_DISABLE :
|
|
(eq_tps != 4) ? eq_tps | DP_LINK_SCRAMBLING_DISABLE :
|
|
|
CDNS_DP_TRAINING_PATTERN_4);
|
|
CDNS_DP_TRAINING_PATTERN_4);
|
|
|
|
|
|
|
|
- drm_dp_dpcd_read_link_status(&mhdp->aux, dpcd);
|
|
|
|
|
|
|
+ drm_dp_dpcd_read_link_status(&mhdp->aux, link_status);
|
|
|
|
|
|
|
|
do {
|
|
do {
|
|
|
- mhdp_get_adjust_train(mhdp, dpcd, lanes_data, &phy_cfg);
|
|
|
|
|
|
|
+ mhdp_get_adjust_train(mhdp, link_status, lanes_data, &phy_cfg);
|
|
|
phy_cfg.dp.lanes = (mhdp->link.num_lanes);
|
|
phy_cfg.dp.lanes = (mhdp->link.num_lanes);
|
|
|
phy_cfg.dp.ssc = false;
|
|
phy_cfg.dp.ssc = false;
|
|
|
phy_cfg.dp.set_lanes = false;
|
|
phy_cfg.dp.set_lanes = false;
|
|
@@ -1091,19 +1250,19 @@ static bool mhdp_link_training_channel_eq(struct cdns_mhdp_device *mhdp,
|
|
|
phy_configure(mhdp->phy, &phy_cfg);
|
|
phy_configure(mhdp->phy, &phy_cfg);
|
|
|
|
|
|
|
|
cdns_mhdp_adjust_lt(mhdp, mhdp->link.num_lanes,
|
|
cdns_mhdp_adjust_lt(mhdp, mhdp->link.num_lanes,
|
|
|
- training_interval, lanes_data, dpcd);
|
|
|
|
|
|
|
+ training_interval, lanes_data, link_status);
|
|
|
|
|
|
|
|
- if (!drm_dp_clock_recovery_ok(dpcd, mhdp->link.num_lanes))
|
|
|
|
|
|
|
+ if (!drm_dp_clock_recovery_ok(link_status, mhdp->link.num_lanes))
|
|
|
goto err;
|
|
goto err;
|
|
|
|
|
|
|
|
- if (drm_dp_channel_eq_ok(dpcd, mhdp->link.num_lanes)) {
|
|
|
|
|
|
|
+ if (drm_dp_channel_eq_ok(link_status, mhdp->link.num_lanes)) {
|
|
|
dev_dbg(mhdp->dev, "EQ phase succeeded\n");
|
|
dev_dbg(mhdp->dev, "EQ phase succeeded\n");
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fail_counter_short++;
|
|
fail_counter_short++;
|
|
|
|
|
|
|
|
- mhdp_adjust_requested_eq(mhdp, dpcd);
|
|
|
|
|
|
|
+ mhdp_adjust_requested_eq(mhdp, link_status);
|
|
|
} while (fail_counter_short < 5);
|
|
} while (fail_counter_short < 5);
|
|
|
|
|
|
|
|
err:
|
|
err:
|
|
@@ -1174,11 +1333,11 @@ static void mhdp_validate_cr(struct cdns_mhdp_device *mhdp, bool *cr_done,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static bool mhdp_link_training_clock_recovery(struct cdns_mhdp_device *mhdp)
|
|
|
|
|
|
|
+static bool mhdp_link_training_cr(struct cdns_mhdp_device *mhdp)
|
|
|
{
|
|
{
|
|
|
u8 lanes_data[CDNS_DP_MAX_NUM_LANES],
|
|
u8 lanes_data[CDNS_DP_MAX_NUM_LANES],
|
|
|
fail_counter_short = 0, fail_counter_cr_long = 0;
|
|
fail_counter_short = 0, fail_counter_cr_long = 0;
|
|
|
- u8 dpcd[DP_LINK_STATUS_SIZE];
|
|
|
|
|
|
|
+ u8 link_status[DP_LINK_STATUS_SIZE];
|
|
|
bool cr_done;
|
|
bool cr_done;
|
|
|
union phy_configure_opts phy_cfg;
|
|
union phy_configure_opts phy_cfg;
|
|
|
|
|
|
|
@@ -1186,14 +1345,14 @@ static bool mhdp_link_training_clock_recovery(struct cdns_mhdp_device *mhdp)
|
|
|
|
|
|
|
|
mhdp_link_training_init(mhdp);
|
|
mhdp_link_training_init(mhdp);
|
|
|
|
|
|
|
|
- drm_dp_dpcd_read_link_status(&mhdp->aux, dpcd);
|
|
|
|
|
|
|
+ drm_dp_dpcd_read_link_status(&mhdp->aux, link_status);
|
|
|
|
|
|
|
|
do {
|
|
do {
|
|
|
- u8 requested_adjust_volt_swing[CDNS_DP_MAX_NUM_LANES] = {},
|
|
|
|
|
- requested_adjust_pre_emphasis[CDNS_DP_MAX_NUM_LANES] = {};
|
|
|
|
|
|
|
+ u8 requested_adjust_volt_swing[CDNS_DP_MAX_NUM_LANES] = {};
|
|
|
|
|
+ u8 requested_adjust_pre_emphasis[CDNS_DP_MAX_NUM_LANES] = {};
|
|
|
bool same_before_adjust, max_swing_reached;
|
|
bool same_before_adjust, max_swing_reached;
|
|
|
|
|
|
|
|
- mhdp_get_adjust_train(mhdp, dpcd, lanes_data, &phy_cfg);
|
|
|
|
|
|
|
+ mhdp_get_adjust_train(mhdp, link_status, lanes_data, &phy_cfg);
|
|
|
phy_cfg.dp.lanes = (mhdp->link.num_lanes);
|
|
phy_cfg.dp.lanes = (mhdp->link.num_lanes);
|
|
|
phy_cfg.dp.ssc = false;
|
|
phy_cfg.dp.ssc = false;
|
|
|
phy_cfg.dp.set_lanes = false;
|
|
phy_cfg.dp.set_lanes = false;
|
|
@@ -1202,10 +1361,10 @@ static bool mhdp_link_training_clock_recovery(struct cdns_mhdp_device *mhdp)
|
|
|
phy_configure(mhdp->phy, &phy_cfg);
|
|
phy_configure(mhdp->phy, &phy_cfg);
|
|
|
|
|
|
|
|
cdns_mhdp_adjust_lt(mhdp, mhdp->link.num_lanes, 100,
|
|
cdns_mhdp_adjust_lt(mhdp, mhdp->link.num_lanes, 100,
|
|
|
- lanes_data, dpcd);
|
|
|
|
|
|
|
+ lanes_data, link_status);
|
|
|
|
|
|
|
|
mhdp_validate_cr(mhdp, &cr_done, &same_before_adjust,
|
|
mhdp_validate_cr(mhdp, &cr_done, &same_before_adjust,
|
|
|
- &max_swing_reached, lanes_data, dpcd,
|
|
|
|
|
|
|
+ &max_swing_reached, lanes_data, link_status,
|
|
|
requested_adjust_volt_swing,
|
|
requested_adjust_volt_swing,
|
|
|
requested_adjust_pre_emphasis);
|
|
requested_adjust_pre_emphasis);
|
|
|
|
|
|
|
@@ -1232,7 +1391,7 @@ static bool mhdp_link_training_clock_recovery(struct cdns_mhdp_device *mhdp)
|
|
|
* Voltage swing/pre-emphasis adjust requested
|
|
* Voltage swing/pre-emphasis adjust requested
|
|
|
* during CR phase
|
|
* during CR phase
|
|
|
*/
|
|
*/
|
|
|
- mhdp_adjust_requested_cr(mhdp, dpcd,
|
|
|
|
|
|
|
+ mhdp_adjust_requested_cr(mhdp, link_status,
|
|
|
requested_adjust_volt_swing,
|
|
requested_adjust_volt_swing,
|
|
|
requested_adjust_pre_emphasis);
|
|
requested_adjust_pre_emphasis);
|
|
|
} while (fail_counter_short < 5 && fail_counter_cr_long < 10);
|
|
} while (fail_counter_short < 5 && fail_counter_cr_long < 10);
|
|
@@ -1267,7 +1426,7 @@ static int mhdp_link_training(struct cdns_mhdp_device *mhdp,
|
|
|
const u8 eq_tps = eq_training_pattern_supported(mhdp->host, mhdp->sink);
|
|
const u8 eq_tps = eq_training_pattern_supported(mhdp->host, mhdp->sink);
|
|
|
|
|
|
|
|
while (1) {
|
|
while (1) {
|
|
|
- if (!mhdp_link_training_clock_recovery(mhdp)) {
|
|
|
|
|
|
|
+ if (!mhdp_link_training_cr(mhdp)) {
|
|
|
if (drm_dp_link_rate_to_bw_code(mhdp->link.rate) !=
|
|
if (drm_dp_link_rate_to_bw_code(mhdp->link.rate) !=
|
|
|
DP_LINK_BW_1_62) {
|
|
DP_LINK_BW_1_62) {
|
|
|
dev_dbg(mhdp->dev,
|
|
dev_dbg(mhdp->dev,
|
|
@@ -1398,7 +1557,8 @@ static void cdns_mhdp_disable(struct drm_bridge *bridge)
|
|
|
cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR,
|
|
cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR,
|
|
|
resp & ~(CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN));
|
|
resp & ~(CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN));
|
|
|
|
|
|
|
|
- cdns_mhdp_j721e_disable(mhdp);
|
|
|
|
|
|
|
+ if (mhdp->ops && mhdp->ops->disable)
|
|
|
|
|
+ mhdp->ops->disable(mhdp);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static u32 get_training_interval_us(struct cdns_mhdp_device *mhdp,
|
|
static u32 get_training_interval_us(struct cdns_mhdp_device *mhdp,
|
|
@@ -1528,6 +1688,14 @@ static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)
|
|
|
|
|
|
|
|
bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt);
|
|
bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt);
|
|
|
|
|
|
|
|
|
|
+ if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes,
|
|
|
|
|
+ mhdp->link.rate)) {
|
|
|
|
|
+ dev_err(mhdp->dev, "%s: Not enough BW for %s (%u lanes at %u Mbps)\n",
|
|
|
|
|
+ __func__, mode->name, mhdp->link.num_lanes,
|
|
|
|
|
+ mhdp->link.rate / 100);
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/* find optimal tu_size */
|
|
/* find optimal tu_size */
|
|
|
required_bandwidth = pxlclock * bpp / 8;
|
|
required_bandwidth = pxlclock * bpp / 8;
|
|
|
available_bandwidth = mhdp->link.num_lanes * rate;
|
|
available_bandwidth = mhdp->link.num_lanes * rate;
|
|
@@ -1544,8 +1712,13 @@ static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)
|
|
|
} while ((vs == 1 || ((vs_f > 850 || vs_f < 100) && vs_f != 0) ||
|
|
} while ((vs == 1 || ((vs_f > 850 || vs_f < 100) && vs_f != 0) ||
|
|
|
tu_size - vs < 2) && tu_size < 64);
|
|
tu_size - vs < 2) && tu_size < 64);
|
|
|
|
|
|
|
|
- if (vs > 64)
|
|
|
|
|
|
|
+ if (vs > 64) {
|
|
|
|
|
+ dev_err(mhdp->dev,
|
|
|
|
|
+ "%s: No space for framing %s (%u lanes at %u Mbps)\n",
|
|
|
|
|
+ __func__, mode->name, mhdp->link.num_lanes,
|
|
|
|
|
+ mhdp->link.rate / 100);
|
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_TU,
|
|
cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_TU,
|
|
|
CDNS_DP_FRAMER_TU_VS(vs) |
|
|
CDNS_DP_FRAMER_TU_VS(vs) |
|
|
@@ -1743,7 +1916,8 @@ void cdns_mhdp_enable(struct drm_bridge *bridge)
|
|
|
|
|
|
|
|
dev_dbg(mhdp->dev, "bridge enable\n");
|
|
dev_dbg(mhdp->dev, "bridge enable\n");
|
|
|
|
|
|
|
|
- cdns_mhdp_j721e_enable(mhdp);
|
|
|
|
|
|
|
+ if (mhdp->ops && mhdp->ops->enable)
|
|
|
|
|
+ mhdp->ops->enable(mhdp);
|
|
|
|
|
|
|
|
/* Enable VIF clock for stream 0 */
|
|
/* Enable VIF clock for stream 0 */
|
|
|
cdns_mhdp_reg_read(mhdp, CDNS_DPTX_CAR, &resp);
|
|
cdns_mhdp_reg_read(mhdp, CDNS_DPTX_CAR, &resp);
|
|
@@ -1781,6 +1955,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = {
|
|
|
|
|
|
|
|
static int mhdp_probe(struct platform_device *pdev)
|
|
static int mhdp_probe(struct platform_device *pdev)
|
|
|
{
|
|
{
|
|
|
|
|
+ const struct of_device_id *match;
|
|
|
struct resource *regs;
|
|
struct resource *regs;
|
|
|
struct cdns_mhdp_device *mhdp;
|
|
struct cdns_mhdp_device *mhdp;
|
|
|
struct clk *clk;
|
|
struct clk *clk;
|
|
@@ -1802,6 +1977,7 @@ static int mhdp_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
mhdp->clk = clk;
|
|
mhdp->clk = clk;
|
|
|
mhdp->dev = &pdev->dev;
|
|
mhdp->dev = &pdev->dev;
|
|
|
|
|
+ mutex_init(&mhdp->mbox_mutex);
|
|
|
spin_lock_init(&mhdp->start_lock);
|
|
spin_lock_init(&mhdp->start_lock);
|
|
|
dev_set_drvdata(&pdev->dev, mhdp);
|
|
dev_set_drvdata(&pdev->dev, mhdp);
|
|
|
|
|
|
|
@@ -1824,19 +2000,26 @@ static int mhdp_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
clk_prepare_enable(clk);
|
|
clk_prepare_enable(clk);
|
|
|
|
|
|
|
|
|
|
+ match = of_match_device(mhdp_ids, &pdev->dev);
|
|
|
|
|
+ if (!match)
|
|
|
|
|
+ return -ENODEV;
|
|
|
|
|
+ mhdp->ops = (struct mhdp_platform_ops *)match->data;
|
|
|
|
|
+
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
ret = pm_runtime_get_sync(&pdev->dev);
|
|
ret = pm_runtime_get_sync(&pdev->dev);
|
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
|
dev_err(&pdev->dev, "pm_runtime_get_sync failed\n");
|
|
dev_err(&pdev->dev, "pm_runtime_get_sync failed\n");
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
- return ret;
|
|
|
|
|
|
|
+ goto clk_disable;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ret = cdns_mhdp_j721e_init(mhdp);
|
|
|
|
|
- if (ret != 0) {
|
|
|
|
|
- dev_err(&pdev->dev, "J721E Wrapper initialization failed: %d\n",
|
|
|
|
|
- ret);
|
|
|
|
|
- goto runtime_put;
|
|
|
|
|
|
|
+ if (mhdp->ops && mhdp->ops->init) {
|
|
|
|
|
+ ret = mhdp->ops->init(mhdp);
|
|
|
|
|
+ if (ret != 0) {
|
|
|
|
|
+ dev_err(&pdev->dev, "MHDP platform initialization failed: %d\n",
|
|
|
|
|
+ ret);
|
|
|
|
|
+ goto runtime_put;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
rate = clk_get_rate(clk);
|
|
rate = clk_get_rate(clk);
|
|
@@ -1852,10 +2035,9 @@ static int mhdp_probe(struct platform_device *pdev)
|
|
|
ret = devm_request_threaded_irq(mhdp->dev, irq, NULL, mhdp_irq_handler,
|
|
ret = devm_request_threaded_irq(mhdp->dev, irq, NULL, mhdp_irq_handler,
|
|
|
IRQF_ONESHOT, "mhdp8546", mhdp);
|
|
IRQF_ONESHOT, "mhdp8546", mhdp);
|
|
|
if (ret) {
|
|
if (ret) {
|
|
|
- dev_err(&pdev->dev,
|
|
|
|
|
- "cannot install IRQ %d\n", irq);
|
|
|
|
|
|
|
+ dev_err(&pdev->dev, "cannot install IRQ %d\n", irq);
|
|
|
ret = -EIO;
|
|
ret = -EIO;
|
|
|
- goto runtime_put;
|
|
|
|
|
|
|
+ goto j721e_fini;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Read source capabilities, based on PHY's device tree properties. */
|
|
/* Read source capabilities, based on PHY's device tree properties. */
|
|
@@ -1909,9 +2091,13 @@ static int mhdp_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
phy_exit:
|
|
phy_exit:
|
|
|
phy_exit(mhdp->phy);
|
|
phy_exit(mhdp->phy);
|
|
|
|
|
+j721e_fini:
|
|
|
|
|
+ cdns_mhdp_j721e_fini(mhdp);
|
|
|
runtime_put:
|
|
runtime_put:
|
|
|
pm_runtime_put_sync(&pdev->dev);
|
|
pm_runtime_put_sync(&pdev->dev);
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
|
|
+clk_disable:
|
|
|
|
|
+ clk_disable_unprepare(mhdp->clk);
|
|
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
@@ -1925,6 +2111,9 @@ static int mhdp_remove(struct platform_device *pdev)
|
|
|
bool stop_fw = false;
|
|
bool stop_fw = false;
|
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
+ if (mhdp->ops && mhdp->ops->exit)
|
|
|
|
|
+ mhdp->ops->exit(mhdp);
|
|
|
|
|
+
|
|
|
drm_bridge_remove(&mhdp->bridge);
|
|
drm_bridge_remove(&mhdp->bridge);
|
|
|
|
|
|
|
|
wait_loading:
|
|
wait_loading:
|
|
@@ -1953,6 +2142,8 @@ wait_loading:
|
|
|
|
|
|
|
|
phy_exit(mhdp->phy);
|
|
phy_exit(mhdp->phy);
|
|
|
|
|
|
|
|
|
|
+ cdns_mhdp_j721e_fini(mhdp);
|
|
|
|
|
+
|
|
|
pm_runtime_put_sync(&pdev->dev);
|
|
pm_runtime_put_sync(&pdev->dev);
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
|
|
|