MLK-24491: drm: bridge: cdns: Add support of i2c-over-aux
Port the i2c over aux feature from 4.19.35 to the 5.4.x kernel. Add the the i2c read/write functions. The i2c features in the FW have been introduced in version 1.0.62. Signed-off-by: Julien Jayat <julien.jayat@nxp.com> Signed-off-by: Oliver Brown <oliver.brown@nxp.com> (cherry picked from commit b6181a1aea9ade244efb2ca001e14adb5cbe23eb) Signed-off-by: Andrey Zhizhikin <andrey.zhizhikin@leica-geosystems.com>
This commit is contained in:
parent
fbff4c5cf8
commit
422e20fe90
|
@ -35,22 +35,16 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
|
|||
bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
|
||||
int ret;
|
||||
|
||||
/* Ignore address only message */
|
||||
if ((msg->size == 0) || (msg->buffer == NULL)) {
|
||||
msg->reply = native ?
|
||||
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
|
||||
/* Ignore address only message , for native */
|
||||
if ((native == true) && ((msg->size == 0) || (msg->buffer == NULL))) {
|
||||
msg->reply = DP_AUX_NATIVE_REPLY_ACK;
|
||||
return msg->size;
|
||||
}
|
||||
|
||||
if (!native) {
|
||||
dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* msg sanity check */
|
||||
if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
|
||||
dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
|
||||
__func__, msg->size, (unsigned int)msg->request);
|
||||
__func__, msg->size, (unsigned int)msg->request);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -72,12 +66,96 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
|
|||
}
|
||||
|
||||
if (msg->request == DP_AUX_NATIVE_READ) {
|
||||
ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
|
||||
ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer,
|
||||
msg->size);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
msg->reply = DP_AUX_NATIVE_REPLY_ACK;
|
||||
return msg->size;
|
||||
}
|
||||
|
||||
if (((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE)
|
||||
|| ((msg->request & ~DP_AUX_I2C_MOT) ==
|
||||
DP_AUX_I2C_WRITE_STATUS_UPDATE)) {
|
||||
|
||||
u8 i2c_status = 0u;
|
||||
u16 respSize = 0u;
|
||||
|
||||
ret = cdns_mhdp_i2c_write(mhdp, msg->address,
|
||||
msg->buffer,
|
||||
!!(msg->request & DP_AUX_I2C_MOT),
|
||||
msg->size, &respSize);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(aux->dev, "cdns_mhdp_i2c_write status %d\n",
|
||||
ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = cdns_mhdp_get_last_i2c_status(mhdp, &i2c_status);
|
||||
if (ret < 0) {
|
||||
dev_err(aux->dev,
|
||||
"cdns_mhdp_get_last_i2c_status status %d\n",
|
||||
ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (i2c_status) {
|
||||
case 0u:
|
||||
msg->reply = DP_AUX_I2C_REPLY_ACK;
|
||||
break;
|
||||
case 1u:
|
||||
msg->reply = DP_AUX_I2C_REPLY_NACK;
|
||||
break;
|
||||
case 2u:
|
||||
msg->reply = DP_AUX_I2C_REPLY_DEFER;
|
||||
break;
|
||||
default:
|
||||
msg->reply = DP_AUX_I2C_REPLY_NACK;
|
||||
break;
|
||||
}
|
||||
|
||||
return respSize;
|
||||
}
|
||||
|
||||
if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ) {
|
||||
|
||||
u8 i2c_status = 0u;
|
||||
u16 respSize = 0u;
|
||||
|
||||
ret = cdns_mhdp_i2c_read(mhdp, msg->address, msg->buffer,
|
||||
msg->size,
|
||||
!!(msg->request & DP_AUX_I2C_MOT),
|
||||
&respSize);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
|
||||
ret = cdns_mhdp_get_last_i2c_status(mhdp, &i2c_status);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(aux->dev,
|
||||
"cdns_mhdp_get_last_i2c_status ret %d\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (i2c_status) {
|
||||
case 0u:
|
||||
msg->reply = DP_AUX_I2C_REPLY_ACK;
|
||||
break;
|
||||
case 1u:
|
||||
msg->reply = DP_AUX_I2C_REPLY_NACK;
|
||||
break;
|
||||
case 2u:
|
||||
msg->reply = DP_AUX_I2C_REPLY_DEFER;
|
||||
break;
|
||||
default:
|
||||
msg->reply = DP_AUX_I2C_REPLY_NACK;
|
||||
break;
|
||||
}
|
||||
|
||||
return respSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,41 @@ err_dpcd_read:
|
|||
}
|
||||
EXPORT_SYMBOL(cdns_mhdp_dpcd_read);
|
||||
|
||||
int cdns_mhdp_i2c_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data,
|
||||
u16 len, u8 mot, u16 *respLength)
|
||||
{
|
||||
u8 msg[5], reg[3];
|
||||
int ret;
|
||||
|
||||
put_unaligned_be16(len, msg);
|
||||
msg[2] = addr;
|
||||
msg[3] = mot;
|
||||
|
||||
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
||||
DPTX_I2C_READ, sizeof(msg), msg);
|
||||
if (ret)
|
||||
goto err_i2c_read;
|
||||
|
||||
ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
|
||||
DPTX_I2C_READ,
|
||||
sizeof(reg) + len);
|
||||
if (ret)
|
||||
goto err_i2c_read;
|
||||
|
||||
ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
|
||||
if (ret)
|
||||
goto err_i2c_read;
|
||||
|
||||
ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
|
||||
*respLength = (reg[0] << 8u) + reg[1];
|
||||
|
||||
err_i2c_read:
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(mhdp->dev, "i2c read failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cdns_mhdp_i2c_read);
|
||||
|
||||
int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
|
||||
{
|
||||
u8 msg[6], reg[5];
|
||||
|
@ -88,6 +123,75 @@ err_dpcd_write:
|
|||
}
|
||||
EXPORT_SYMBOL(cdns_mhdp_dpcd_write);
|
||||
|
||||
int cdns_mhdp_i2c_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 *value,
|
||||
u8 mot, u16 len, u16 *respLength)
|
||||
{
|
||||
u8 msg[4+DP_AUX_MAX_PAYLOAD_BYTES], reg[3];
|
||||
int ret;
|
||||
|
||||
put_unaligned_be16(len, msg);
|
||||
msg[2] = addr;
|
||||
msg[3] = mot;
|
||||
memcpy(&msg[4], value, len);
|
||||
|
||||
|
||||
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
||||
DPTX_I2C_WRITE, sizeof(msg), msg);
|
||||
if (ret)
|
||||
goto err_i2c_write;
|
||||
|
||||
ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
|
||||
DPTX_I2C_WRITE, sizeof(reg));
|
||||
if (ret)
|
||||
goto err_i2c_write;
|
||||
|
||||
ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
|
||||
if (ret)
|
||||
goto err_i2c_write;
|
||||
|
||||
if (addr != reg[2])
|
||||
ret = -EINVAL;
|
||||
|
||||
*respLength = (reg[0]<<8u) + reg[1];
|
||||
|
||||
err_i2c_write:
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(mhdp->dev, "i2c write failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cdns_mhdp_i2c_write);
|
||||
|
||||
|
||||
int cdns_mhdp_get_last_i2c_status(struct cdns_mhdp_device *mhdp, u8 *resp)
|
||||
{
|
||||
u8 status[1];
|
||||
int ret;
|
||||
|
||||
ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
|
||||
DPTX_GET_LAST_I2C_STATUS, 0, NULL);
|
||||
if (ret)
|
||||
goto err_get_i2c_status;
|
||||
|
||||
ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
|
||||
DPTX_GET_LAST_I2C_STATUS,
|
||||
sizeof(status));
|
||||
if (ret)
|
||||
goto err_get_i2c_status;
|
||||
|
||||
ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
|
||||
if (ret)
|
||||
goto err_get_i2c_status;
|
||||
|
||||
*resp = status[0];
|
||||
|
||||
err_get_i2c_status:
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(mhdp->dev, "get i2c status failed: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cdns_mhdp_get_last_i2c_status);
|
||||
|
||||
static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
|
|
@ -376,6 +376,11 @@
|
|||
#define DPTX_FORCE_LANES 0x10
|
||||
#define DPTX_HPD_STATE 0x11
|
||||
#define DPTX_ADJUST_LT 0x12
|
||||
#define DPTX_I2C_READ 0x15
|
||||
#define DPTX_I2C_WRITE 0x16
|
||||
#define DPTX_GET_LAST_I2C_STATUS 0x17
|
||||
|
||||
|
||||
|
||||
/* HDMI TX opcode */
|
||||
#define HDMI_TX_READ 0x00
|
||||
|
@ -734,6 +739,12 @@ u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
|
|||
int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value);
|
||||
int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
|
||||
u32 addr, u8 *data, u16 len);
|
||||
|
||||
int cdns_mhdp_get_last_i2c_status(struct cdns_mhdp_device *mhdp, u8 *resp);
|
||||
int cdns_mhdp_i2c_write(struct cdns_mhdp_device *mhdp, u8 addr,
|
||||
u8 *value, u8 mot, u16 len, u16 *respLength);
|
||||
int cdns_mhdp_i2c_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data,
|
||||
u16 len, u8 mot, u16 *respLength);
|
||||
int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
|
||||
unsigned int block, size_t length);
|
||||
int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
|
||||
|
|
Loading…
Reference in New Issue