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

Commit b510e800 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm: msm: dp: align DP driver with DRM upstream framework"

parents bb574bf1 d84b38b2
Loading
Loading
Loading
Loading
+139 −312
Original line number Diff line number Diff line
@@ -20,14 +20,8 @@

#define DP_AUX_ENUM_STR(x)		#x

struct aux_buf {
	u8 *start;      /* buffer start addr */
	u8 *end;	/* buffer end addr */
	u8 *data;       /* data pou32er */
	u32 size;       /* size of buffer */
	u32 len;	/* dara length */
	u8 trans_num;   /* transaction number */
	enum aux_tx_mode tx_mode;
enum {
	DP_AUX_DATA_INDEX_WRITE = BIT(31),
};

struct dp_aux_private {
@@ -38,15 +32,12 @@ struct dp_aux_private {
	struct mutex mutex;
	struct completion comp;

	struct aux_cmd *cmds;
	struct aux_buf txp;
	struct aux_buf rxp;

	u32 aux_error_num;
	bool cmd_busy;
	bool native;
	bool read;

	u8 txbuf[256];
	u8 rxbuf[256];
	struct drm_dp_aux drm_aux;
};

static char *dp_aux_get_error(u32 aux_error)
@@ -69,159 +60,104 @@ static char *dp_aux_get_error(u32 aux_error)
	}
}

static void dp_aux_buf_init(struct aux_buf *buf, u8 *data, u32 size)
{
	buf->start     = data;
	buf->size      = size;
	buf->data      = buf->start;
	buf->end       = buf->start + buf->size;
	buf->len       = 0;
	buf->trans_num = 0;
	buf->tx_mode   = AUX_NATIVE;
}

static void dp_aux_buf_set(struct dp_aux_private *aux)
{
	init_completion(&aux->comp);
	aux->cmd_busy = false;
	mutex_init(&aux->mutex);

	dp_aux_buf_init(&aux->txp, aux->txbuf, sizeof(aux->txbuf));
	dp_aux_buf_init(&aux->rxp, aux->rxbuf, sizeof(aux->rxbuf));
}

static void dp_aux_buf_reset(struct aux_buf *buf)
{
	buf->data      = buf->start;
	buf->len       = 0;
	buf->trans_num = 0;
	buf->tx_mode   = AUX_NATIVE;

	memset(buf->start, 0x0, 256);
}

static void dp_aux_buf_push(struct aux_buf *buf, u32 len)
{
	buf->data += len;
	buf->len  += len;
}

static u32 dp_aux_buf_trailing(struct aux_buf *buf)
{
	return (u32)(buf->end - buf->data);
}

static u32 dp_aux_add_cmd(struct aux_buf *buf, struct aux_cmd *cmd)
static u32 dp_aux_write(struct dp_aux_private *aux,
		struct drm_dp_aux_msg *msg)
{
	u8 data;
	u8 *bp, *cp;
	u32 i, len;
	u32 data[4], reg, len;
	u8 *msgdata = msg->buffer;
	int const aux_cmd_fifo_len = 128;
	int i = 0;

	if (cmd->ex_mode == AUX_READ)
	if (aux->read)
		len = 4;
	else
		len = cmd->len + 4;

	if (dp_aux_buf_trailing(buf) < len) {
		pr_err("buf trailing error\n");
		return 0;
	}
		len = msg->size + 4;

	/*
	 * cmd fifo only has depth of 144 bytes
	 * limit buf length to 128 bytes here
	 */
	if ((buf->len + len) > 128) {
	if (len > aux_cmd_fifo_len) {
		pr_err("buf len error\n");
		return 0;
	}

	bp = buf->data;
	data = cmd->addr >> 16;
	data &= 0x0f;  /* 4 addr bits */

	if (cmd->ex_mode == AUX_READ)
		data |=  BIT(4);

	*bp++ = data;
	*bp++ = cmd->addr >> 8;
	*bp++ = cmd->addr;
	*bp++ = cmd->len - 1;
	/* Pack cmd and write to HW */
	data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
	if (aux->read)
		data[0] |=  BIT(4); /* R/W */

	if (cmd->ex_mode == AUX_WRITE) {
		cp = cmd->buf;
	data[1] = (msg->address >> 8) & 0xff;	/* addr[15:8] */
	data[2] = msg->address & 0xff;		/* addr[7:0] */
	data[3] = (msg->size - 1) & 0xff;	/* len[7:0] */

		for (i = 0; i < cmd->len; i++)
			*bp++ = *cp++;
	for (i = 0; i < len; i++) {
		reg = (i < 4) ? data[i] : msgdata[i - 4];
		reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */
		if (i == 0)
			reg |= DP_AUX_DATA_INDEX_WRITE;
		aux->catalog->data = reg;
		aux->catalog->write_data(aux->catalog);
	}

	dp_aux_buf_push(buf, len);

	buf->tx_mode = cmd->tx_mode;
	reg = 0; /* Transaction number == 1 */
	if (!aux->native) /* i2c */
		reg |= (BIT(8) | BIT(10) | BIT(11));

	buf->trans_num++;
	reg |= BIT(9);
	aux->catalog->data = reg;
	aux->catalog->write_trans(aux->catalog);

	return cmd->len - 1;
	return len;
}

static u32 dp_aux_cmd_fifo_tx(struct dp_aux_private *aux)
static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
		struct drm_dp_aux_msg *msg)
{
	u8 *dp;
	u32 data, len, cnt;
	struct aux_buf *tp = &aux->txp;
	u32 ret = 0, len = 0, timeout;
	int const aux_timeout_ms = HZ/4;

	reinit_completion(&aux->comp);

	len = tp->len;
	len = dp_aux_write(aux, msg);
	if (len == 0) {
		pr_err("invalid len\n");
		return 0;
		pr_err("DP AUX write failed\n");
		return -EINVAL;
	}

	cnt = 0;
	dp = tp->start;

	while (cnt < len) {
		data = *dp;
		data <<= 8;
		data &= 0x00ff00;
		if (cnt == 0)
			data |= BIT(31);

		aux->catalog->data = data;
		aux->catalog->write_data(aux->catalog);

		cnt++;
		dp++;
	timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
	if (!timeout) {
		pr_err("aux write timeout\n");
		return -ETIMEDOUT;
	}

	data = (tp->trans_num - 1);
	if (tp->tx_mode == AUX_I2C) {
		data |= BIT(8); /* I2C */
		data |= BIT(10); /* NO SEND ADDR */
		data |= BIT(11); /* NO SEND STOP */
	}
	pr_debug("aux status %s\n",
		dp_aux_get_error(aux->aux_error_num));

	data |= BIT(9); /* GO */
	aux->catalog->data = data;
	aux->catalog->write_trans(aux->catalog);
	if (aux->aux_error_num == DP_AUX_ERR_NONE)
		ret = len;
	else
		ret = -EINVAL;

	return tp->len;
	return ret;
}

static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len)
static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
		struct drm_dp_aux_msg *msg)
{
	u32 data;
	u8 *dp;
	u32 i;
	struct aux_buf *rp = &aux->rxp;
	u32 len = msg->size;

	data = 0;
	data |= BIT(31); /* INDEX_WRITE */
	data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
	data |= BIT(0);  /* read */

	aux->catalog->data = data;
	aux->catalog->write_data(aux->catalog);

	dp = rp->data;
	dp = msg->buffer;

	/* discard first byte */
	data = aux->catalog->read_data(aux->catalog);
@@ -230,9 +166,6 @@ static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len)
		data = aux->catalog->read_data(aux->catalog);
		*dp++ = (u8)((data >> 8) & 0xff);
	}

	rp->len = len;
	return len;
}

static void dp_aux_native_handler(struct dp_aux_private *aux)
@@ -292,236 +225,133 @@ static void dp_aux_isr(struct dp_aux *dp_aux)
	if (!aux->cmd_busy)
		return;

	if (aux->cmds->tx_mode == AUX_NATIVE)
	if (aux->native)
		dp_aux_native_handler(aux);
	else
		dp_aux_i2c_handler(aux);
}



static int dp_aux_write(struct dp_aux_private *aux)
/*
 * This function does the real job to process an AUX transaction.
 * It will call aux_reset() function to reset the AUX channel,
 * if the waiting is timeout.
 */
static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
		struct drm_dp_aux_msg *msg)
{
	struct aux_cmd *cm;
	struct aux_buf *tp;
	u32 len, ret, timeout;
	ssize_t ret;
	int const aux_cmd_native_max = 16;
	int const aux_cmd_i2c_max = 128;
	struct dp_aux_private *aux = container_of(drm_aux,
		struct dp_aux_private, drm_aux);

	mutex_lock(&aux->mutex);

	tp = &aux->txp;
	dp_aux_buf_reset(tp);

	cm = aux->cmds;
	while (cm) {
		ret = dp_aux_add_cmd(tp, cm);
		if (ret <= 0)
			break;

		if (!cm->next)
			break;
		cm++;
	}

	reinit_completion(&aux->comp);
	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
	aux->cmd_busy = true;

	len = dp_aux_cmd_fifo_tx(aux);

	timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
	if (!timeout)
		pr_err("aux write timeout\n");

	pr_debug("aux status %s\n",
		dp_aux_get_error(aux->aux_error_num));

	if (aux->aux_error_num == DP_AUX_ERR_NONE)
		ret = len;
	else
		ret = aux->aux_error_num;

	aux->cmd_busy = false;
	mutex_unlock(&aux->mutex);
	return  ret;
	/* Ignore address only message */
	if ((msg->size == 0) || (msg->buffer == NULL)) {
		msg->reply = aux->native ?
			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
		ret = msg->size;
		goto unlock_exit;
	}

static int dp_aux_read(struct dp_aux_private *aux)
{
	struct aux_cmd *cm;
	struct aux_buf *tp, *rp;
	u32 len, ret, timeout;

	mutex_lock(&aux->mutex);

	tp = &aux->txp;
	rp = &aux->rxp;

	dp_aux_buf_reset(tp);
	dp_aux_buf_reset(rp);

	cm = aux->cmds;
	len = 0;

	while (cm) {
		ret = dp_aux_add_cmd(tp, cm);
		len += cm->len;

		if (ret <= 0)
			break;

		if (!cm->next)
			break;
		cm++;
	/* msg sanity check */
	if ((aux->native && (msg->size > aux_cmd_native_max)) ||
		(msg->size > aux_cmd_i2c_max)) {
		pr_err("%s: invalid msg: size(%zu), request(%x)\n",
			__func__, msg->size, msg->request);
		ret = -EINVAL;
		goto unlock_exit;
	}

	reinit_completion(&aux->comp);
	aux->cmd_busy = true;

	dp_aux_cmd_fifo_tx(aux);
	ret = dp_aux_cmd_fifo_tx(aux, msg);
	if (ret < 0) {
		aux->catalog->reset(aux->catalog); /* reset aux */
		goto unlock_exit;
	}

	timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
	if (!timeout)
		pr_err("aux read timeout\n");
	if (aux->aux_error_num == DP_AUX_ERR_NONE) {
		if (aux->read)
			dp_aux_cmd_fifo_rx(aux, msg);

	pr_debug("aux status %s\n",
		dp_aux_get_error(aux->aux_error_num));
		msg->reply = aux->native ?
			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
	} else {
		/* Reply defer to retry */
		msg->reply = aux->native ?
			DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
	}

	if (aux->aux_error_num == DP_AUX_ERR_NONE)
		ret = dp_cmd_fifo_rx(aux, len);
	else
		ret = aux->aux_error_num;
	/* Return requested size for success or retry */
	ret = msg->size;

	aux->cmds->buf = rp->data;
unlock_exit:
	aux->cmd_busy = false;

	mutex_unlock(&aux->mutex);

	return ret;
}

static int dp_aux_write_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
				enum aux_tx_mode mode, u8 *buf)
{
	struct aux_cmd cmd = {0};
	struct dp_aux_private *aux;

	if (!dp_aux || !len) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	cmd.ex_mode = AUX_WRITE;
	cmd.tx_mode = mode;
	cmd.addr    = addr;
	cmd.len     = len;
	cmd.buf     = buf;

	aux->cmds = &cmd;

	return dp_aux_write(aux);
}

static int dp_aux_read_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
				enum aux_tx_mode mode, u8 **buf)
{
	int rc = 0;
	struct aux_cmd cmd = {0};
	struct dp_aux_private *aux;

	if (!dp_aux || !len) {
		pr_err("invalid input\n");
		rc = -EINVAL;
		goto end;
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	cmd.ex_mode = AUX_READ;
	cmd.tx_mode = mode;
	cmd.addr    = addr;
	cmd.len     = len;

	aux->cmds = &cmd;

	rc = dp_aux_read(aux);
	if (rc <= 0) {
		rc = -EINVAL;
		goto end;
	}

	*buf = cmd.buf;
end:
	return rc;
}

static int dp_aux_process(struct dp_aux *dp_aux, struct aux_cmd *cmds)
static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg)
{
	struct dp_aux_private *aux;

	if (!dp_aux || !cmds) {
	if (!dp_aux) {
		pr_err("invalid input\n");
		return -EINVAL;
		return;
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	aux->cmds = cmds;

	if (cmds->ex_mode == AUX_READ)
		return dp_aux_read(aux);
	else
		return dp_aux_write(aux);
	aux->catalog->reset(aux->catalog);
	aux->catalog->enable(aux->catalog, true);
	aux->catalog->setup(aux->catalog, aux_cfg);
}

static bool dp_aux_ready(struct dp_aux *dp_aux)
static void dp_aux_deinit(struct dp_aux *dp_aux)
{
	u8 data = 0;
	int count, ret;
	struct dp_aux_private *aux;

	if (!dp_aux) {
		pr_err("invalid input\n");
		goto error;
		return;
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	for (count = 5; count; count--) {
		ret = dp_aux_write_ex(dp_aux, 0x50, 1, AUX_I2C, &data);
		if (ret >= 0)
			break;

		msleep(100);
	}

	if (count <= 0) {
		pr_err("aux chan NOT ready\n");
		goto error;
	}

	return true;
error:
	return false;
	aux->catalog->enable(aux->catalog, false);
}

static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg)
static int dp_aux_register(struct dp_aux *dp_aux)
{
	struct dp_aux_private *aux;
	int ret = 0;

	if (!dp_aux) {
		pr_err("invalid input\n");
		return;
		ret = -EINVAL;
		goto exit;
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	aux->catalog->reset(aux->catalog);
	aux->catalog->enable(aux->catalog, true);
	aux->catalog->setup(aux->catalog, aux_cfg);
	aux->drm_aux.name = "sde_dp_aux";
	aux->drm_aux.dev = aux->dev;
	aux->drm_aux.transfer = dp_aux_transfer;
	ret = drm_dp_aux_register(&aux->drm_aux);
	if (ret) {
		pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
		goto exit;
	}
	dp_aux->drm_aux = &aux->drm_aux;
exit:
	return ret;
}

static void dp_aux_deinit(struct dp_aux *dp_aux)
static void dp_aux_deregister(struct dp_aux *dp_aux)
{
	struct dp_aux_private *aux;

@@ -531,8 +361,7 @@ static void dp_aux_deinit(struct dp_aux *dp_aux)
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	aux->catalog->enable(aux->catalog, false);
	drm_dp_aux_unregister(&aux->drm_aux);
}

struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
@@ -553,21 +382,19 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
		goto error;
	}

	aux->dev = dev;

	dp_aux_buf_set(aux);
	init_completion(&aux->comp);
	aux->cmd_busy = false;
	mutex_init(&aux->mutex);

	aux->dev = dev;
	aux->catalog = catalog;

	dp_aux = &aux->dp_aux;

	dp_aux->process = dp_aux_process;
	dp_aux->read    = dp_aux_read_ex;
	dp_aux->write   = dp_aux_write_ex;
	dp_aux->ready   = dp_aux_ready;
	dp_aux->isr     = dp_aux_isr;
	dp_aux->init    = dp_aux_init;
	dp_aux->deinit  = dp_aux_deinit;
	dp_aux->drm_aux_register = dp_aux_register;
	dp_aux->drm_aux_deregister = dp_aux_deregister;

	return dp_aux;
error:
+4 −25
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#define _DP_AUX_H_

#include "dp_catalog.h"
#include "drm_dp_helper.h"

enum dp_aux_error {
	DP_AUX_ERR_NONE	= 0,
@@ -26,32 +27,10 @@ enum dp_aux_error {
	DP_AUX_ERR_NACK_DEFER	= -5,
};

enum aux_tx_mode {
	AUX_NATIVE,
	AUX_I2C,
};

enum aux_exe_mode {
	AUX_WRITE,
	AUX_READ,
};

struct aux_cmd {
	enum aux_exe_mode ex_mode;
	enum aux_tx_mode tx_mode;
	u32 addr;
	u32 len;
	u8 *buf;
	bool next;
};

struct dp_aux {
	int (*process)(struct dp_aux *aux, struct aux_cmd *cmd);
	int (*write)(struct dp_aux *aux, u32 addr, u32 len,
			enum aux_tx_mode mode, u8 *buf);
	int (*read)(struct dp_aux *aux, u32 addr, u32 len,
			enum aux_tx_mode mode, u8 **buf);
	bool (*ready)(struct dp_aux *aux);
	struct drm_dp_aux *drm_aux;
	int (*drm_aux_register)(struct dp_aux *aux);
	void (*drm_aux_deregister)(struct dp_aux *aux);
	void (*isr)(struct dp_aux *aux);
	void (*init)(struct dp_aux *aux, u32 *aux_cfg);
	void (*deinit)(struct dp_aux *aux);
+0 −2
Original line number Diff line number Diff line
@@ -177,8 +177,6 @@

#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN		(0x004)

#define EDID_START_ADDRESS			0x50

/* DP MMSS_CC registers */
#define MMSS_DP_LINK_CMD_RCGR			(0x0138)
#define MMSS_DP_LINK_CFG_RCGR			(0x013C)
+56 −82
Original line number Diff line number Diff line
@@ -20,14 +20,9 @@

#include "dp_ctrl.h"

#define DP_LINK_RATE_MULTIPLIER	27000000
#define DP_KHZ_TO_HZ 1000
#define DP_CRYPTO_CLK_RATE_KHZ 180000

/* sink power state  */
#define SINK_POWER_ON		1
#define SINK_POWER_OFF		2

#define DP_CTRL_INTR_READY_FOR_VIDEO     BIT(0)
#define DP_CTRL_INTR_IDLE_PATTERN_SENT  BIT(3)

@@ -103,14 +98,6 @@ static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl)
	complete(&ctrl->video_comp);
}

static void dp_ctrl_set_sink_power_state(struct dp_ctrl_private *ctrl,
		u8 power_state)
{
	const int len = 1;

	ctrl->aux->write(ctrl->aux, 0x600, len, AUX_NATIVE, &power_state);
}

static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
{
	ctrl->catalog->state_ctrl(ctrl->catalog, state);
@@ -128,7 +115,7 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)

	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

	dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_OFF);
	drm_dp_link_power_down(ctrl->aux->drm_aux, &ctrl->panel->dp_link);

	reinit_completion(&ctrl->idle_comp);
	dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
@@ -143,12 +130,13 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
{
	u32 config = 0, tbd;
	u8 *dpcd = ctrl->panel->dpcd;

	config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK  */
	config |= (0 << 11); /* RGB */

	/* Scrambler reset enable */
	if (ctrl->panel->dpcd.scrambler_reset)
	if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
		config |= (1 << 10);

	tbd = ctrl->link->get_test_bits_depth(ctrl->link,
@@ -158,7 +146,7 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
	/* Num of Lanes */
	config |= ((ctrl->link->lane_count - 1) << 4);

	if (ctrl->panel->dpcd.enhanced_frame)
	if (drm_dp_enhanced_frame_cap(dpcd))
		config |= 0x40;

	config |= 0x04; /* progressive video */
@@ -327,7 +315,7 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
	even_distribution = 0;
	min_hblank = 0;

	lclk = link_rate * DP_LINK_RATE_MULTIPLIER;
	lclk = drm_dp_bw_code_to_link_rate(link_rate) * DP_KHZ_TO_HZ;

	pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
						pclk, lwidth, h_blank);
@@ -763,7 +751,7 @@ static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl,
		buf[i] = voltage_level | pre_emphasis_level | max_level_reached;

	pr_debug("p|v=0x%x\n", voltage_level | pre_emphasis_level);
	return ctrl->aux->write(ctrl->aux, 0x103, 4, AUX_NATIVE, buf);
	return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
}

static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
@@ -778,25 +766,6 @@ static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
	dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level);
}

static void dp_ctrl_cap_lane_rate_set(struct dp_ctrl_private *ctrl)
{
	u8 buf[4];
	struct dp_panel_dpcd *cap;

	cap = &ctrl->panel->dpcd;

	pr_debug("bw=%x lane=%d\n", ctrl->link->link_rate,
		ctrl->link->lane_count);

	buf[0] = ctrl->link->link_rate;
	buf[1] = ctrl->link->lane_count;

	if (cap->enhanced_frame)
		buf[1] |= 0x80;

	ctrl->aux->write(ctrl->aux, 0x100, 2, AUX_NATIVE, buf);
}

static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
		u8 pattern)
{
@@ -805,33 +774,39 @@ static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
	pr_debug("pattern=%x\n", pattern);

	buf[0] = pattern;
	ctrl->aux->write(ctrl->aux, 0x102, 1, AUX_NATIVE, buf);
	drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1);
}

static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
{
	int tries, old_v_level;
	int ret = 0;
	int usleep_time;
	int tries, old_v_level, ret = 0, len = 0;
	u8 link_status[DP_LINK_STATUS_SIZE];
	int const maximum_retries = 5;

	dp_ctrl_state_ctrl(ctrl, 0);

	/* Make sure to clear the current pattern before starting a new one */
	wmb();

	ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
	dp_ctrl_cap_lane_rate_set(ctrl);
	dp_ctrl_train_pattern_set(ctrl, 0x21); /* train_1 */
	dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
		DP_RECOVERED_CLOCK_OUT_EN); /* train_1 */
	dp_ctrl_update_vx_px(ctrl);

	tries = 0;
	old_v_level = ctrl->link->v_level;
	while (1) {
		usleep_time = ctrl->panel->dpcd.training_read_interval;
		usleep_range(usleep_time, usleep_time * 2);
		drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);

		if (ctrl->link->clock_recovery(ctrl->link)) {
		len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
			link_status);
		if (len < DP_LINK_STATUS_SIZE) {
			pr_err("[%s]: DP link status read failed\n", __func__);
			ret = -1;
			break;
		}

		if (drm_dp_clock_recovery_ok(link_status,
			ctrl->link->lane_count)) {
			ret = 0;
			break;
		}
@@ -852,8 +827,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
			old_v_level = ctrl->link->v_level;
		}

		ctrl->link->adjust_levels(ctrl->link);

		ctrl->link->adjust_levels(ctrl->link, link_status);
		dp_ctrl_update_vx_px(ctrl);
	}

@@ -869,15 +843,15 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)

	switch (ctrl->link->link_rate) {
	case DP_LINK_RATE_810:
		ctrl->link->link_rate = DP_LINK_RATE_540;
		ctrl->link->link_rate = DP_LINK_BW_5_4;
		break;
	case DP_LINK_RATE_540:
		ctrl->link->link_rate = DP_LINK_RATE_270;
	case DP_LINK_BW_5_4:
		ctrl->link->link_rate = DP_LINK_BW_2_7;
		break;
	case DP_LINK_RATE_270:
		ctrl->link->link_rate = DP_LINK_RATE_162;
	case DP_LINK_BW_2_7:
		ctrl->link->link_rate = DP_LINK_BW_1_62;
		break;
	case DP_LINK_RATE_162:
	case DP_LINK_BW_1_62:
	default:
		ret = -EINVAL;
		break;
@@ -890,36 +864,38 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)

static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
{
	int usleep_time;

	dp_ctrl_train_pattern_set(ctrl, 0);

	usleep_time = ctrl->panel->dpcd.training_read_interval;
	usleep_range(usleep_time, usleep_time * 2);
	drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
}

static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
{
	int tries = 0;
	int ret = 0;
	int usleep_time;
	int tries = 0, ret = 0, len = 0;
	char pattern;
	int const maximum_retries = 5;
	u8 link_status[DP_LINK_STATUS_SIZE];

	if (ctrl->panel->dpcd.flags & DPCD_TPS3)
		pattern = 0x03;
	if (drm_dp_tps3_supported(ctrl->panel->dpcd))
		pattern = DP_TRAINING_PATTERN_3;
	else
		pattern = 0x02;
		pattern = DP_TRAINING_PATTERN_2;

	dp_ctrl_update_vx_px(ctrl);
	ctrl->catalog->set_pattern(ctrl->catalog, pattern);
	dp_ctrl_train_pattern_set(ctrl, pattern | 0x20);
	dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);

	do  {
		usleep_time = ctrl->panel->dpcd.training_read_interval;
		usleep_range(usleep_time, usleep_time * 2);
		drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);

		len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
			link_status);
		if (len < DP_LINK_STATUS_SIZE) {
			pr_err("[%s]: DP link status read failed\n", __func__);
			ret = -1;
			break;
		}

		if (ctrl->link->channel_equalization(ctrl->link)) {
		if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count)) {
			ret = 0;
			break;
		}
@@ -930,8 +906,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
		}
		tries++;

		ctrl->link->adjust_levels(ctrl->link);

		ctrl->link->adjust_levels(ctrl->link, link_status);
		dp_ctrl_update_vx_px(ctrl);
	} while (1);

@@ -941,12 +916,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
{
	int ret = 0;

	ret = ctrl->aux->ready(ctrl->aux);
	if (!ret) {
		pr_err("aux chan NOT ready\n");
		return ret;
	}
	struct drm_dp_link dp_link;

	ctrl->link->p_level = 0;
	ctrl->link->v_level = 0;
@@ -954,6 +924,11 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
	dp_ctrl_config_ctrl(ctrl);
	dp_ctrl_state_ctrl(ctrl, 0);

	dp_link.num_lanes = ctrl->link->lane_count;
	dp_link.rate = ctrl->link->link_rate;
	dp_link.capabilities = ctrl->panel->dp_link.capabilities;
	drm_dp_link_configure(ctrl->aux->drm_aux, &dp_link);

	ret = dp_ctrl_link_train_1(ctrl);
	if (ret < 0) {
		if (!dp_ctrl_link_rate_down_shift(ctrl)) {
@@ -1007,7 +982,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)

	ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);

	dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_ON);
	drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->dp_link);

	if (ctrl->link->phy_pattern_requested(ctrl->link))
		goto end;
@@ -1065,8 +1040,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
	ctrl->power->set_pixel_clk_parent(ctrl->power);

	dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
		(ctrl->link->link_rate * DP_LINK_RATE_MULTIPLIER) /
			DP_KHZ_TO_HZ);
		drm_dp_bw_code_to_link_rate(ctrl->link->link_rate));

	dp_ctrl_set_clock_rate(ctrl, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ);

@@ -1208,7 +1182,7 @@ static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)
	ctrl->catalog->hpd_config(ctrl->catalog, true);

	ctrl->link->link_rate  = ctrl->panel->get_link_rate(ctrl->panel);
	ctrl->link->lane_count = ctrl->panel->dpcd.max_lane_count;
	ctrl->link->lane_count = ctrl->panel->dp_link.num_lanes;
	ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;

	pr_debug("link_rate=%d, lane_count=%d, pixel_rate=%d\n",
+29 −28
Original line number Diff line number Diff line
@@ -195,6 +195,18 @@ static int dp_display_bind(struct device *dev, struct device *master,
		goto end;
	}

	rc = dp->aux->drm_aux_register(dp->aux);
	if (rc) {
		pr_err("DRM DP AUX register failed\n");
		goto end;
	}

	rc = dp->panel->sde_edid_register(dp->panel);
	if (rc) {
		pr_err("DRM DP EDID register failed\n");
		goto end;
	}

	rc = dp->power->power_client_init(dp->power, &priv->phandle);
	if (rc) {
		pr_err("Power client create failed\n");
@@ -227,6 +239,10 @@ static void dp_display_unbind(struct device *dev, struct device *master,

	(void)dp->power->power_client_deinit(dp->power);

	(void) dp->panel->sde_edid_deregister(dp->panel);

	(void) dp->aux->drm_aux_deregister(dp->aux);

	(void)dp_display_debugfs_deinit(dp);

	mutex_unlock(&dp->lock);
@@ -245,9 +261,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
	if (rc)
		goto end;

	rc = dp->panel->read_edid(dp->panel);
	if (rc)
		goto end;
	sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
		(void **)&dp->panel->edid_ctrl);

	return 0;
end:
@@ -256,6 +271,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)

static int dp_display_process_hpd_low(struct dp_display_private *dp)
{
	dp->dp_display.is_connected = false;
	return 0;
}

@@ -290,6 +306,7 @@ static int dp_display_usbpd_configure_cb(struct device *dev)

	if (dp->usbpd->hpd_high)
		dp_display_process_hpd_high(dp);
	dp->dp_display.is_connected = true;

	mutex_unlock(&dp->lock);
end:
@@ -315,6 +332,7 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
	}

	mutex_lock(&dp->lock);
	dp->dp_display.is_connected = false;
	disable_irq(dp->irq);
	mutex_unlock(&dp->lock);

@@ -573,33 +591,17 @@ static int dp_display_validate_mode(struct dp_display *dp,
	return 0;
}

static int dp_display_get_modes(struct dp_display *dp,
	struct dp_display_mode *modes, u32 *count)
static int dp_display_get_modes(struct dp_display *dp)
{
	*count = 1;

	if (modes) {
		modes->timing.h_active = 1920;
		modes->timing.v_active = 1080;
		modes->timing.h_back_porch = 148;
		modes->timing.h_front_porch = 88;
		modes->timing.h_sync_width = 44;
		modes->timing.h_active_low = 0;
		modes->timing.v_back_porch = 36;
		modes->timing.v_front_porch = 4;
		modes->timing.v_sync_width = 5;
		modes->timing.v_active_low = 0;
		modes->timing.h_skew = 0;
		modes->timing.refresh_rate = 60;
		modes->timing.pixel_clk_khz = 148500;
	}
	int ret = 0;
	struct dp_display_private *dp_display;

	return 0;
}
	dp_display = container_of(dp, struct dp_display_private, dp_display);

static int dp_display_detect(struct dp_display *dp)
{
	return 0;
	ret = _sde_edid_update_modes(dp->connector,
		dp_display->panel->edid_ctrl);

	return ret;
}

static int dp_display_probe(struct platform_device *pdev)
@@ -637,7 +639,6 @@ static int dp_display_probe(struct platform_device *pdev)
	g_dp_display->set_mode      = dp_display_set_mode;
	g_dp_display->validate_mode = dp_display_validate_mode;
	g_dp_display->get_modes     = dp_display_get_modes;
	g_dp_display->detect        = dp_display_detect;
	g_dp_display->prepare       = dp_display_prepare;
	g_dp_display->unprepare     = dp_display_unprepare;
	g_dp_display->request_irq   = dp_request_irq;
Loading