Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ca20305 authored by Thierry Reding's avatar Thierry Reding Committed by Christian König
Browse files

drm/tegra: dp: Support address-only I2C-over-AUX transactions



Certain types of I2C-over-AUX transactions require that only the address
is transferred. Detect this by looking at the AUX message's size and set
the address-only bit appropriately.

Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent c39b0695
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -99,55 +99,73 @@ static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer,
static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
				    struct drm_dp_aux_msg *msg)
{
	unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ;
	unsigned long timeout = msecs_to_jiffies(250);
	struct tegra_dpaux *dpaux = to_dpaux(aux);
	unsigned long status;
	ssize_t ret = 0;
	u32 value;

	if (msg->size < 1 || msg->size > 16)
	/* Tegra has 4x4 byte DP AUX transmit and receive FIFOs. */
	if (msg->size > 16)
		return -EINVAL;

	tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);
	/*
	 * Allow zero-sized messages only for I2C, in which case they specify
	 * address-only transactions.
	 */
	if (msg->size < 1) {
		switch (msg->request & ~DP_AUX_I2C_MOT) {
		case DP_AUX_I2C_WRITE:
		case DP_AUX_I2C_READ:
			value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY;
			break;

		default:
			return -EINVAL;
		}
	} else {
		/* For non-zero-sized messages, set the CMDLEN field. */
		value = DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1);
	}

	switch (msg->request & ~DP_AUX_I2C_MOT) {
	case DP_AUX_I2C_WRITE:
		if (msg->request & DP_AUX_I2C_MOT)
			value = DPAUX_DP_AUXCTL_CMD_MOT_WR;
			value |= DPAUX_DP_AUXCTL_CMD_MOT_WR;
		else
			value = DPAUX_DP_AUXCTL_CMD_I2C_WR;
			value |= DPAUX_DP_AUXCTL_CMD_I2C_WR;

		break;

	case DP_AUX_I2C_READ:
		if (msg->request & DP_AUX_I2C_MOT)
			value = DPAUX_DP_AUXCTL_CMD_MOT_RD;
			value |= DPAUX_DP_AUXCTL_CMD_MOT_RD;
		else
			value = DPAUX_DP_AUXCTL_CMD_I2C_RD;
			value |= DPAUX_DP_AUXCTL_CMD_I2C_RD;

		break;

	case DP_AUX_I2C_STATUS:
		if (msg->request & DP_AUX_I2C_MOT)
			value = DPAUX_DP_AUXCTL_CMD_MOT_RQ;
			value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ;
		else
			value = DPAUX_DP_AUXCTL_CMD_I2C_RQ;
			value |= DPAUX_DP_AUXCTL_CMD_I2C_RQ;

		break;

	case DP_AUX_NATIVE_WRITE:
		value = DPAUX_DP_AUXCTL_CMD_AUX_WR;
		value |= DPAUX_DP_AUXCTL_CMD_AUX_WR;
		break;

	case DP_AUX_NATIVE_READ:
		value = DPAUX_DP_AUXCTL_CMD_AUX_RD;
		value |= DPAUX_DP_AUXCTL_CMD_AUX_RD;
		break;

	default:
		return -EINVAL;
	}

	value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1);
	tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);
	tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);

	if ((msg->request & DP_AUX_I2C_READ) == 0) {
@@ -198,7 +216,7 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
		break;
	}

	if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) {
	if ((msg->size > 0) && (msg->reply == DP_AUX_NATIVE_REPLY_ACK)) {
		if (msg->request & DP_AUX_I2C_READ) {
			size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK;

+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12)
#define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12)
#define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12)
#define DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY (1 << 8)
#define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff)

#define DPAUX_DP_AUXSTAT 0x31