Jetson tx2 mipi read reg fail

I am an engineer from China. Our company is HYC, a listed company.We need the company’s products.
The quantity is expected to be very large. But there was a technical problem
We now use your company’s Jetson TX2. We can drive a mobile screen of Mipi interface to display Ubuntu page, but we can’t use
int Tegra ﹣ DSI ﹣ read ﹣ data (struct Tegra ﹣ DC * DC) in the system,
struct tegra_dc_dsi_data *dsi, u16 max_ret_payload_size, u8 panel_reg_addr, u8 *read_data)
To read and write the register of Mipi display.
We use another device to drive the mobile screen and read it according to the same operation.
Please help support.
Thanks!!!

A little bit confused in these lines

“int Tegra ﹣ DSI ﹣ read ﹣ data (struct Tegra ﹣ DC * DC) in the system,
struct tegra_dc_dsi_data *dsi, u16 max_ret_payload_size, u8 panel_reg_addr, u8 *read_data)”

Could you copy the function name directly? Also, what error did you hit?
Could you share your sample code of using it?

HI WayneWWW,
I use command #cat /sys/kernel/debug/tegra_dsi/read_panel

Return result:
max ret payload size:0x4
panel reg addr:0xc9
read 0 read 0 read 0 read 0 read 0 read 0 read 0 read 0 read 0 read 0 read 0
Read data[0] 0 0 0 0
Invalid read response
Invalid response packet.

read 0 is the result I print, every byte.
According to Mipi protocol, the first byte should be 0x87, but we are 0, and the other bytes are not correct.

In addition, in order to eliminate image interference, I temporarily deleted gdm3, which means that Ubuntu interface will not be generated when the system is started.

We test our mobile screen. The steps are as follows: first send 0xbd, 0x00. Then send the payload size 4 and the read command 0xc9. We use other platforms to send data according to the above steps, read 0xc9, and the result can return to the normal read value. I used Mipi analyzer to grab the data sent by both of them, including the written data graphs of 0xbd, 4 and 0xc9.The waveform data written by the two devices is exactly the same.

In addition, 0xc9 is the NVIDIA, DSI init CMD used when the mobile screen starts. Here are some initialization commands that I can drive this mobile screen: NVIDIA, DSI init CMD=
<TEGRA_DSI_PACKET_CMD DSI_DCS_LONG_WRITE 0x04 0x0 0x0 0xB9 0x83 0x10 0x2D 0x0 0x0>,
<TEGRA_DSI_PACKET_CMD DSI_DCS_LONG_WRITE 0x0f 0x0 0x0 0xB1 0x22 0x44 0x31 0x31 0x22 0x34 0x2F 0x57 0x08 0x08 0x08 0x67 0x67 0x71 0x0 0x0>,
<TEGRA_DSI_PACKET_CMD DSI_DCS_LONG_WRITE 0x04 0x0 0x0 0xD3 0x01 0x00 0x39 0x0 0x0>,
<TEGRA_DSI_PACKET_CMD DSI_DCS_WRITE_1_PARAM 0xBD 0x00 0x00>,
<TEGRA_DSI_PACKET_CMD DSI_DCS_LONG_WRITE 0x05 0x0 0x0 0xC9 0x04 0x65 0x90 0x01 0x0 0x0>,

we read 0xC9 Should return 0x04 0x65 0x90 0x01. At least one return correct ID 0x87 appears.
But it fails.

##cat /sys/kernel/debug/tegra_dsi/read_panel

It actually calls the following functions.

static u32 max_ret_payload_size = 4;
static u32 panel_reg_addr = 0xc9;

static int read_panel_get(struct seq_file *s, void *unused)
{
	struct tegra_dc_dsi_data *dsi = s->private;
	struct tegra_dc *dc = dsi->dc;
	int err = 0;
	u8 buf[MAX_PANEL_REG_READ_SIZE] = {0};
	int j = 0 , b = 0 , k,i=0;
	u32 payload_size = 0;
        u8 del = 100;

        struct tegra_dsi_cmd user_command[] = {
	DSI_CMD_SHORT(0x15, 0xBD, 0x00),
	//DSI_DLY_MS(20),
	};

	if (!dsi->enabled) {
		dev_info(&dc->ndev->dev, " controller suspended\n");
		return -EINVAL;
	}

	seq_printf(s, "max ret payload size:0x%x\npanel reg addr:0x%x\n",
					max_ret_payload_size, panel_reg_addr);

	if ((max_ret_payload_size > MAX_PANEL_REG_READ_SIZE) ||
			(max_ret_payload_size == 0)) {
		seq_printf(s, "max reg payload size should be a positive value below 0x%x\n",
				MAX_PANEL_REG_READ_SIZE);
		return err;
	}

	

	

	//seq_printf(s, "data_id taken :0x%x\n", data_id);
	//seq_printf(s, "command value taken :0x%x\n", command_value);
	//seq_printf(s, "second command value taken :0x%x\n", command_value1);

	err = tegra_dsi_write_data(dc, dsi, user_command, del);

	err = tegra_dsi_read_data(dsi->dc, dsi,
				max_ret_payload_size,
				panel_reg_addr, buf);
        for (i = 0; i < 11; i++) {
		seq_printf(s, "read %x ", buf[i]);
	}

	for (b = 0; b < max_ret_payload_size; b += 4) {
		seq_printf(s, "\n Read data[%d] ", j++);
		for (k = b+4; k > b; k--)
			seq_printf(s, " %x ", buf[k-1]);
	}
	seq_puts(s, "\n");

	switch (buf[0]) {
	case DSI_ESCAPE_CMD:
		seq_printf(s, "escape cmd[0x%x]\n", buf[0]);
		break;
	case DSI_ACK_NO_ERR:
		seq_printf(s,
			"Panel ack, no err[0x%x]\n", buf[0]);
		goto fail;
		break;
	default:
		seq_puts(s, "Invalid read response\n");
		break;
	}

	switch (buf[4] & 0xff) {
	case GEN_LONG_RD_RES:
		/* Fall through */
	case DCS_LONG_RD_RES:
		payload_size = (buf[5] |
				(buf[6] << 8)) & 0xFFFF;
		seq_printf(s, "Long read response Packet\n"
				"payload_size[0x%x]\n", payload_size);
		break;
	case GEN_1_BYTE_SHORT_RD_RES:
		/* Fall through */
	case DCS_1_BYTE_SHORT_RD_RES:
		payload_size = 1;
		seq_printf(s, "Short read response Packet\n"
			"payload_size[0x%x]\n", payload_size);
		break;
	case GEN_2_BYTE_SHORT_RD_RES:
		/* Fall through */
	case DCS_2_BYTE_SHORT_RD_RES:
		payload_size = 2;
		seq_printf(s, "Short read response Packet\n"
			"payload_size[0x%x]\n", payload_size);
		break;
	case ACK_ERR_RES:
		payload_size = 2;
		seq_printf(s, "Acknowledge error report response\n"
			"Packet payload_size[0x%x]\n", payload_size);
		break;
	default:
		seq_puts(s, "Invalid response packet\n");
		break;
	}
fail:
	return err;
}
/////////////////////////
int tegra_dsi_read_data(struct tegra_dc *dc,
				struct tegra_dc_dsi_data *dsi,
				u16 max_ret_payload_size,
				u8 panel_reg_addr, u8 *read_data)
{
	int err = 0;
	struct dsi_status *init_status;
	static struct tegra_dsi_cmd temp_cmd;

	if (!dsi->enabled) {
		dev_err(&dc->ndev->dev, "DSI controller suspended\n");
		return -EINVAL;
	}
	tegra_dc_dsi_hold_host(dc);
	mutex_lock(&dsi->lock);
	tegra_dc_io_start(dc);
	if (dsi->dsi_fixed_clk)
		tegra_disp_clk_prepare_enable(dsi->dsi_fixed_clk);
	tegra_dsi_lp_clk_enable(dsi);
	init_status = tegra_dsi_prepare_host_transmission(
				dc, dsi, DSI_LP_OP_WRITE);
	if (IS_ERR_OR_NULL(init_status)) {
		dev_err(&dc->ndev->dev, "DSI host config failed\n");
		goto fail;
	}

	/* Set max return payload size in words */
	temp_cmd.data_id = dsi_command_max_return_pkt_size;
	temp_cmd.sp_len_dly.data_len = max_ret_payload_size;
	err = _tegra_dsi_write_data(dsi, &temp_cmd);
	if (err < 0) {
		dev_err(&dc->ndev->dev,
				"DSI write failed\n");
		goto fail;
	}

	/* DCS to read given panel register */
	temp_cmd.data_id = dsi_command_dcs_read_with_no_params;
	temp_cmd.sp_len_dly.sp.data0 = panel_reg_addr;
	temp_cmd.sp_len_dly.sp.data1 = 0;
	err = _tegra_dsi_write_data(dsi, &temp_cmd);
	if (err < 0) {
		dev_err(&dc->ndev->dev,
				"DSI write failed\n");
		goto fail;
	}

	tegra_dsi_reset_read_count(dsi);

	if (dsi->status.lp_op == DSI_LP_OP_WRITE) {
		err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_READ);
		if (err < 0) {
			dev_err(&dc->ndev->dev,
			"DSI failed to go to LP read mode\n");
			goto fail;
		}
	}

	err = tegra_dsi_bta(dsi);
	if (err < 0) {
		dev_err(&dc->ndev->dev,
			"DSI IMM BTA timeout\n");
		goto fail;
	}

	err = tegra_dsi_read_fifo(dc, dsi, read_data);
	if (err < 0) {
		dev_err(&dc->ndev->dev, "DSI read fifo failure\n");
		goto fail;
	}
fail:
	err = tegra_dsi_restore_state(dc, dsi, init_status);
	if (err < 0)
		dev_err(&dc->ndev->dev, "Failed to restore prev state\n");
	tegra_dsi_lp_clk_disable(dsi);
	if (dsi->dsi_fixed_clk)
		tegra_disp_clk_disable_unprepare(dsi->dsi_fixed_clk);
	tegra_dc_io_end(dc);
	mutex_unlock(&dsi->lock);
	tegra_dc_dsi_release_host(dc);
	return err;
}

Thanks!!

We are checking if this debug node is broken. I believe it hasn’t been used for long time.
Will update to you once we have some progress.

HI WayneWWW,
I have several questions about Mipi reading function:

  1. For example, if we really read FIFO:
    /* Read data from FIFO */
    for (i = 0; i < rd_fifo_cnt; i++) {
    val = tegra_dsi_readl(dsi, DSI_RD_DATA);
    if (enable_read_debug)
    dev_info(&dc->ndev->dev,
    “Read data[%d]: 0x%x\n”, i, val);
    memcpy(read_fifo, &val, 4);
    read_fifo += 4;
    }
    #define DSI_RD_DATA 0x09
    #define DSI_WR_DATA 0x0a

But the TRM I downloaded: Parker_TRM_DP07821001p.pdf
technical reference manual NVIDIA Parker Series SoC
Chapter on Mipi DSI, 24.9.5 DSI_CTXSW_0
DSI Read Return Data
Offset: 0x9 │ Byte Offset: 0x24 │ Read/Write: RO │ Reset: 0x0001fc0

This is not a register that Mipi read? Or do you have any other TRM data of Jetson TX2?
I need register data related to Mipi DSI, but only download this one.

2 We are going to read back the opcode CMD register of the written screen.
I found that the Mipi read function, tegra_dsi_read_data(), called the functions of tegra_dsi_soft_reset and tegra_dsi_stop_dc_stream_at_frame_end. Would these functions delete the opcode CMD register that has been written in the memory?

Thank you!!

Sorry for late reply.

I just checked with internal team for your questions.

  1. For the TRM issue, please refer to the code of “get_byte_offset” in dsi.c. This function is used in dsi_readl and writel. Because dsi.c driver is shared between TX1 and TX2, this “get_byte_offset” would help handle the difference between two platforms.

However, it also generates the problem you have here. That is, if you want to do the power control, you should still write “0xb” in your code instead of “0xc” even though TRM says 0xc is the correct offset. The driver would help you automatically +1 the input and become what you want.

  1. DSI soft_reset only resets the Tegra-DSI controller internal logic. This is completely transparent to the external display panel. So panel status is not impacted with this.

HI WayneWWW,

     Thank you for your reply!

Please continue to focus on the last one!
Problem with unable to read register.

Thanks!!

Hi baipl,

Could you also share what is your purpose here? I don’t get the meaning of this line is #1 -
“We use another device to drive the mobile screen and read it according to the same operation.”.

Could you briefly describe your system design as a block diagram?

HI WayneWWW,

Posted 12/13/2019 07:30 AM
At this time, I put forward the question.

Thanks!

We want to know more about " We use other platforms to send data according to the above steps, read 0xc9, and the result can return to the normal read value."

What is this platform and how does it connect to DSI panel?

HI WayneWWW,
That is to say, we can use FPGA to directly operate the Mipi of the mobile screen, which can read and write registers, or light up the mobile screen and display pictures. Then I can use TX2 to light up the same mobile screen, and write registers (I can grab the bytes written with Mipi analyzer), but I can’t read init CMD of mobile screen.
See this post more specifically,Posted 12/13/2019 07:30 AM

Thanks!

Ok I got it. May I know does this cause serious problem in your development?

HI WayneWWW,
When we develop, the manufacturer’s mobile screen (of course, there are TVs or other screens) has Mipi init CMD. We need to debug these init CMD. Otherwise, some commands may be wrong, causing that the screen cannot be lit. We may need to fine tune init CMD according to the actual situation. So we need to read and write init CMD of Mipi. We need to make sure that what we write is consistent with what we read. We may need to debug repeatedly.
Thanks!

Hi baipl,

Could you try to check the function “tegra_dc_dsi_postpoweron -> tegra_dsi_send_panel_cmd” returns any error or not?

HI WayneWWW,

       No any error.
       Is your code updated?

Thanks!

HI WayneWWW,
Excuse me, are you updated? Do you have any suggestions for our questions?
Thank you!

Hi baipl,

Sorry, still no update. If you are urgent for this issue, please find nvidia sales to address and highlight it.

Hi baipl,

Have you made any progress on your side? This will take sometime and maybe until next release. Is it okay for you?