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

Commit bc882fb8 authored by Sandeep Panda's avatar Sandeep Panda Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/dsi-staging: add support for checking panel status



Panel health status can be read back from panel using DCS read
mechanism. This change adds support for the same along with
fixing various HW configuration issues related with read back
from MIPI peripherals.

Change-Id: I129f5c564dd4e4acda56031dc2f985267ee1a590
Signed-off-by: default avatarSandeep Panda <spanda@codeaurora.org>
parent bca90e2f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
	ctrl->ops.setup_misr = dsi_ctrl_hw_cmn_setup_misr;
	ctrl->ops.collect_misr = dsi_ctrl_hw_cmn_collect_misr;
	ctrl->ops.debug_bus = dsi_ctrl_hw_cmn_debug_bus;
	ctrl->ops.get_cmd_read_data = dsi_ctrl_hw_cmn_get_cmd_read_data;
	ctrl->ops.clear_rdbk_register = dsi_ctrl_hw_cmn_clear_rdbk_reg;

	switch (version) {
	case DSI_CTRL_VERSION_1_4:
+6 −0
Original line number Diff line number Diff line
@@ -170,6 +170,12 @@ void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl,
			bool enable);
void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
			bool enable);
u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl,
				     u8 *rd_buf,
				     u32 read_offset,
				     u32 rx_byte,
				     u32 pkt_size, u32 *hw_read_cnt);
void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl);

/* Definitions specific to 1.4 DSI controller hardware */
int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
+126 −11
Original line number Diff line number Diff line
@@ -886,6 +886,11 @@ static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl,
		buf[3] |= BIT(6);

	buf[3] |= BIT(7);

	/* send embedded BTA for read commands */
	if ((buf[2] & 0x3f) == MIPI_DSI_DCS_READ)
		buf[3] |= BIT(5);

	*buffer = buf;
	*size = len;

@@ -1061,6 +1066,7 @@ static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl,
{
	int rc = 0;
	u8 tx[2] = { (u8)(size & 0xFF), (u8)(size >> 8) };
	u32 flags = DSI_CTRL_CMD_FETCH_MEMORY;
	struct mipi_dsi_msg msg = {
		.channel = rx_msg->channel,
		.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
@@ -1068,24 +1074,77 @@ static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl,
		.tx_buf = tx,
	};

	rc = dsi_message_tx(dsi_ctrl, &msg, 0x0);
	rc = dsi_message_tx(dsi_ctrl, &msg, flags);
	if (rc)
		pr_err("failed to send max return size packet, rc=%d\n", rc);

	return rc;
}

/* Helper functions to support DCS read operation */
static int dsi_parse_short_read1_resp(const struct mipi_dsi_msg *msg,
		unsigned char *buff)
{
	u8 *data = msg->rx_buf;
	int read_len = 1;

	if (!data)
		return 0;

	/* remove dcs type */
	if (msg->rx_len >= 1)
		data[0] = buff[1];
	else
		read_len = 0;

	return read_len;
}

static int dsi_parse_short_read2_resp(const struct mipi_dsi_msg *msg,
		unsigned char *buff)
{
	u8 *data = msg->rx_buf;
	int read_len = 2;

	if (!data)
		return 0;

	/* remove dcs type */
	if (msg->rx_len >= 2) {
		data[0] = buff[1];
		data[1] = buff[2];
	} else {
		read_len = 0;
	}

	return read_len;
}

static int dsi_parse_long_read_resp(const struct mipi_dsi_msg *msg,
		unsigned char *buff)
{
	if (!msg->rx_buf)
		return 0;

	/* remove dcs type */
	if (msg->rx_buf && msg->rx_len)
		memcpy(msg->rx_buf, buff + 4, msg->rx_len);

	return msg->rx_len;
}

static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,
			  const struct mipi_dsi_msg *msg,
			  u32 flags)
{
	int rc = 0;
	u32 rd_pkt_size;
	u32 total_read_len;
	u32 bytes_read = 0, tot_bytes_read = 0;
	u32 current_read_len;
	u32 rd_pkt_size, total_read_len, hw_read_cnt;
	u32 current_read_len = 0, total_bytes_read = 0;
	bool short_resp = false;
	bool read_done = false;
	u32 dlen, diff, rlen = msg->rx_len;
	unsigned char *buff;
	char cmd;

	if (msg->rx_len <= 2) {
		short_resp = true;
@@ -1101,6 +1160,7 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,

		total_read_len = current_read_len + 6;
	}
	buff = msg->rx_buf;

	while (!read_done) {
		rc = dsi_set_max_return_size(dsi_ctrl, msg, rd_pkt_size);
@@ -1110,24 +1170,79 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,
			goto error;
		}

		/* clear RDBK_DATA registers before proceeding */
		dsi_ctrl->hw.ops.clear_rdbk_register(&dsi_ctrl->hw);

		rc = dsi_message_tx(dsi_ctrl, msg, flags);
		if (rc) {
			pr_err("Message transmission failed, rc=%d\n", rc);
			goto error;
		}

		dlen = dsi_ctrl->hw.ops.get_cmd_read_data(&dsi_ctrl->hw,
					buff, total_bytes_read,
					total_read_len, rd_pkt_size,
					&hw_read_cnt);
		if (!dlen)
			goto error;

		tot_bytes_read += bytes_read;
		if (short_resp)
			break;

		if (rlen <= current_read_len) {
			diff = current_read_len - rlen;
			read_done = true;
		else if (msg->rx_len <= tot_bytes_read)
			read_done = true;
		} else {
			diff = 0;
			rlen -= current_read_len;
		}

		dlen -= 2; /* 2 bytes of CRC */
		dlen -= diff;
		buff += dlen;
		total_bytes_read += dlen;
		if (!read_done) {
			current_read_len = 14; /* Not first read */
			if (rlen < current_read_len)
				rd_pkt_size += rlen;
			else
				rd_pkt_size += current_read_len;
		}
	}

	if (hw_read_cnt < 16 && !short_resp)
		buff = msg->rx_buf + (16 - hw_read_cnt);
	else
		buff = msg->rx_buf;

	/* parse the data read from panel */
	cmd = buff[0];
	switch (cmd) {
	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
		pr_err("Rx ACK_ERROR\n");
		rc = 0;
		break;
	case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
		rc = dsi_parse_short_read1_resp(msg, buff);
		break;
	case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
		rc = dsi_parse_short_read2_resp(msg, buff);
		break;
	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
		rc = dsi_parse_long_read_resp(msg, buff);
		break;
	default:
		pr_warn("Invalid response\n");
		rc = 0;
	}

error:
	return rc;
}


static int dsi_enable_ulps(struct dsi_ctrl *dsi_ctrl)
{
	int rc = 0;
@@ -2335,8 +2450,8 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,

	if (flags & DSI_CTRL_CMD_READ) {
		rc = dsi_message_rx(dsi_ctrl, msg, flags);
		if (rc)
			pr_err("read message failed, rc=%d\n", rc);
		if (rc <= 0)
			pr_err("read message failed read length, rc=%d\n", rc);
	} else {
		rc = dsi_message_tx(dsi_ctrl, msg, flags);
		if (rc)
+13 −2
Original line number Diff line number Diff line
@@ -520,11 +520,17 @@ struct dsi_ctrl_hw_ops {
	 * get_cmd_read_data() - get data read from the peripheral
	 * @ctrl:           Pointer to the controller host hardware.
	 * @rd_buf:         Buffer where data will be read into.
	 * @total_read_len: Number of bytes to read.
	 * @read_offset:    Offset from where to read.
	 * @rx_byte:        Number of bytes to be read.
	 * @pkt_size:        Size of response expected.
	 * @hw_read_cnt:    Actual number of bytes read by HW.
	 */
	u32 (*get_cmd_read_data)(struct dsi_ctrl_hw *ctrl,
				 u8 *rd_buf,
				 u32 total_read_len);
				 u32 read_offset,
				 u32 rx_byte,
				 u32 pkt_size,
				 u32 *hw_read_cnt);

	/**
	 * wait_for_lane_idle() - wait for DSI lanes to go to idle state
@@ -710,6 +716,11 @@ struct dsi_ctrl_hw_ops {
	 */
	void (*set_timing_db)(struct dsi_ctrl_hw *ctrl,
				 bool enable);
	/**
	 * clear_rdbk_register() - Clear and reset read back register
	 * @ctrl:         Pointer to the controller host hardware.
	 */
	void (*clear_rdbk_register)(struct dsi_ctrl_hw *ctrl);
};

/*
+57 −19
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/iopoll.h>

#include "dsi_catalog.h"
#include "dsi_ctrl_hw.h"
#include "dsi_ctrl_reg.h"
#include "dsi_hw.h"
@@ -708,6 +709,22 @@ void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl)
	pr_debug("[DSI_%d] CMD DMA triggered\n", ctrl->index);
}

/**
 * clear_rdbk_reg() - clear previously read panel data.
 * @ctrl:          Pointer to the controller host hardware.
 *
 * This function is called before sending DSI Rx command to
 * panel in order to clear if any stale data remaining from
 * previous read operation.
 */
void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl)
{
	DSI_W32(ctrl, DSI_RDBK_DATA_CTRL, 0x1);
	wmb(); /* ensure read back register is reset */
	DSI_W32(ctrl, DSI_RDBK_DATA_CTRL, 0x0);
	wmb(); /* ensure read back register is cleared */
}

/**
 * get_cmd_read_data() - get data read from the peripheral
 * @ctrl:           Pointer to the controller host hardware.
@@ -719,16 +736,16 @@ void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl)
u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl,
				     u8 *rd_buf,
				     u32 read_offset,
				     u32 total_read_len)
				     u32 rx_byte,
				     u32 pkt_size,
				     u32 *hw_read_cnt)
{
	u32 *lp, *temp, data;
	int i, j = 0, cnt;
	int i, j = 0, cnt, off;
	u32 read_cnt;
	u32 rx_byte = 0;
	u32 repeated_bytes = 0;
	u8 reg[16] = {0};
	u32 pkt_size = 0;
	int buf_offset = read_offset;
	bool ack_err = false;

	lp = (u32 *)rd_buf;
	temp = (u32 *)reg;
@@ -737,28 +754,49 @@ u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl,
	if (cnt > 4)
		cnt = 4;

	if (rx_byte == 4)
		read_cnt = 4;
	else
		read_cnt = pkt_size + 6;
	read_cnt = (DSI_R32(ctrl, DSI_RDBK_DATA_CTRL) >> 16);
	ack_err = (rx_byte == 4) ? (read_cnt == 8) :
			((read_cnt - 4) == (pkt_size + 6));

	if (ack_err)
		read_cnt -= 4;
	if (!read_cnt) {
		pr_err("Panel detected error, no data read\n");
		return 0;
	}

	if (read_cnt > 16) {
		int bytes_shifted;
		int bytes_shifted, data_lost = 0, rem_header = 0;

		bytes_shifted = read_cnt - rx_byte;
		if (bytes_shifted >= 4)
			data_lost = bytes_shifted - 4; /* remove DCS header */
		else
			rem_header = 4 - bytes_shifted; /* remaining header */

		bytes_shifted = read_cnt - 16;
		repeated_bytes = buf_offset - bytes_shifted;
		repeated_bytes = (read_offset - 4) - data_lost + rem_header;
	}

	for (i = cnt - 1; i >= 0; i--) {
		data = DSI_R32(ctrl, DSI_RDBK_DATA0 + i*4);
	off = DSI_RDBK_DATA0;
	off += ((cnt - 1) * 4);

	for (i = 0; i < cnt; i++) {
		data = DSI_R32(ctrl, off);
		if (!repeated_bytes)
			*lp++ = ntohl(data);
		else
			*temp++ = ntohl(data);
		off -= 4;
	}

	if (repeated_bytes) {
		for (i = repeated_bytes; i < 16; i++)
			rd_buf[j++] = reg[i];
	}

	pr_debug("[DSI_%d] Read %d bytes\n", ctrl->index, j);
	return j;
	*hw_read_cnt = read_cnt;
	pr_debug("[DSI_%d] Read %d bytes\n", ctrl->index, rx_byte);
	return rx_byte;
}

/**
Loading