Note: SN65DSI86 的使用與注意事項

本文介绍TI的SN65DSI86 DSI到eDP桥接芯片的使用注意事项,重点讨论了eDP面板对于ASSR的支持判断方法,并提供了读取DPCD与EDID的测试代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://kunyichen.wordpress.com/2014/06/08/note-sn65dsi86-%E7%9A%84%E4%BD%BF%E7%94%A8%E8%88%87%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A0%85/


Note: SN65DSI86 的使用與注意事項

最近案子用上 TI 出的這顆 DSI to eDP 的Bridge, 搞了一陣子, eDP 方面基本上只有一點要注意, 就是Panel 一定要能支援 ASSR (Alternative scrambler seed reset), 如果想要用再沒有support ASSR 的面板上基本上也是有機會的, 只要TI 願意跟你講保留的測試pin 跟暫存器設定, 另外Colorbar 設定完後, VSTREAM bit 也設定後就可以正常看到 Color bar的畫面, 無關DSI 的信號與否

判讀 eDP Panel 有沒有支援ASSR 可以從下列資訊判讀

DPCD(DisplayPort Configuration Data)
eDP_CONFIGURATION_CAP(000DH) defined at page 19 (VESA Embedded DisplayPort Standard Version 1.2, 2 May 2010)

For Embedded DisplayPort receivers:
Bit 0 = ALTERNATE_SCRAMBLER_RESET_CAPABLE
A setting of 1 indicates that this is a eDP device that can use the eDP
alternat scrambler reset value of FFFEh

Bit 1 = FRAMING_CHANGE_CAPABLE
A setting of 1 indicates that this is an eDP device uses only
Enhanced Framing, independently of the setting by the source of
ENHANCED_FRAME_EN

Bit2 = RESERVED for eDP Read 0s.

Bit3 = DPCD_DISPLAY_CONTROL_CAPABLE
A setting of 1 indicates that display control registers starting at
address 00700h are enabled.

下面是測試程式的片斷, 展示如何讀寫DPCD & 讀取EDID 的資訊解析, 硬體平台用的是之前TI 特價買的 Stellaris Launchpad LM4F120 (現在已經改成Tiva C series Launchpad TM4C123G) , 實際用 ASSR 的panel 時記得要寫入 DPCD eDP_CONFIGURATION_SET (0010Ah)
bit0 為1 , 且要在 eDP traning 之前, 基本上就是eDP 的 Source & Sink 端同步 reset 亂數產生器的初始值為 0FFFEH

完整的程式可以在 http://pastebin.com/fg79hLvz 找到,

輸出則是 http://pastebin.com/rvN9a6iP

(ps. 這個基本上是hello 改過來的, 不過default 的stack size 太小, 要改大)

static void READ_DPCD(uint8_t* buff, uint32_t v_addr, uint32_t cnt)
{
	uint8_t tmp[4];
	// AUX 20bit address
	tmp[0] = (v_addr>>16) & 0x0F;
	tmp[1] = (v_addr>>8) & 0xFF;
	tmp[2] = (v_addr & 0xFF);
	// length
	tmp[3] = (cnt & 0x1F);
	I2C_Write8(tmp, 0x74, 4); // write DPCD register address

	// AUX_NATIVE_CMD (0x9)
	tmp[0] = (9<<4) | // AUX_NATIVE_READ
			 (1<<0);  // EN_SEND_AUX     I2C_Write8(tmp, 0x78, 1); 	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // waiting for response 	I2C_Read8(buff, 0x79, (cnt&0x1F)); } static void WRITE_DPCD(uint8_t* buff, uint32_t v_addr, uint32_t cnt) { 	uint8_t tmp[4]; 	// AUX 20bit address 	tmp[0] = (v_addr>>16) & 0x0F;
	tmp[1] = (v_addr>>8) & 0xFF;
	tmp[2] = (v_addr & 0xFF);
	// length
	tmp[3] = (cnt & 0x1F);
	I2C_Write8(tmp, 0x74, 4); // write DPCD register address

	I2C_Write8(buff, 0x64, cnt);

	// AUX_NATIVE_CMD (0x8)
	tmp[0] = (8<<4) | // AUX_NATIVE_WRITE
			 (1<<0);  // EN_SEND_AUX     I2C_Write8(tmp, 0x78, 1); 	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); } static void opAUX(uint32_t v_addr, uint8_t* buff, uint8_t cnt, uint8_t cmd) { 	uint8_t tmp[4]; 	// AUX 20bit address 	tmp[0] = (v_addr>>16) & 0x0F;
	tmp[1] = (v_addr>>8) & 0xFF;
	tmp[2] = (v_addr & 0xFF);
	// length
	tmp[3] = (cnt & 0x1F);
	I2C_Write8(tmp, 0x74, 4); // write address
	
	if ((cnt != 0) && cmd != 5)
		I2C_Write8(buff, 0x64, cnt);
	tmp[0] = (cmd << 4) |
			 ( 1 << 0); // SEND flag
	I2C_Write8(tmp, 0x78, 1);
	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3);
}

static void readEDID(void)
{
	uint8_t buf[2];
	uint8_t count;
	
	memset(buf, 0, sizeof(buf));
	opAUX(0x50, buf, 0, 4); // Write with MOT, I2C over AUX, SYNC
	opAUX(0x50, buf, 1, 4); // Write with MOT, Offset 0
	opAUX(0x50, buf, 0, 5); // Read with MOT, READ START
	for (count=0; count < 128; count+= 16) {
		opAUX(0x50, buf, 0x10, 5); // Read with MOT, read 16 byte
		I2C_Read8((g_ui8EDID+count), 0x79, 0x10);
	}
	opAUX(0x50, buf, 0, 1); // read without MOT, read stop
}

static void dumpEDID(void)
{
	uint8_t count;
	uint8_t vo;
	
	count = vo = 0;
	UARTprintf("--------------------------------------------------------\n");
	UARTprintf("Dump Panel EDID \n");
	UARTprintf("--------------------------------------------------------\n");
	UARTprintf("    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
	UARTprintf("--------------------------------------------------------");
	for(count = 0; count < sizeof(g_ui8EDID); count++) {
		if ((count % 16) == 0) {
			UARTprintf("\n%02X|", vo);
			vo += 0x10;
		}
		UARTprintf(" %02x", g_ui8EDID[count]);
	}
	
	UARTprintf("\n");
}

static void dumpPanelTiming(void)
{
	uint32_t t;
	uint16_t ha;
	uint16_t hb;
	uint16_t ho;
	uint16_t va;
	uint16_t vb;
	uint16_t vo;
	uint16_t hpw;
	uint16_t vpw;
	uint16_t hsz;
	uint16_t vsz;
	uint16_t hbp;
	uint16_t vbp;
	
	UARTprintf("--------------------------------------------------------\n");
	UARTprintf("Extract Panel timing from EDID DTD1\n");
	UARTprintf("--------------------------------------------------------\n");
	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // wating for UARTprintf

	#define DTD1_OFFSET  (0x36)
	t = (g_ui8EDID[DTD1_OFFSET+1]<<8) + g_ui8EDID[DTD1_OFFSET+0];
	ha = ((g_ui8EDID[DTD1_OFFSET+4] & 0xF0)<<4) + g_ui8EDID[DTD1_OFFSET+2];
	hb = ((g_ui8EDID[DTD1_OFFSET+4] & 0x0F)<<8) + g_ui8EDID[DTD1_OFFSET+3];
	va = ((g_ui8EDID[DTD1_OFFSET+7] & 0xF0)<<4) + g_ui8EDID[DTD1_OFFSET+5];
	vb = ((g_ui8EDID[DTD1_OFFSET+7] & 0x0F)<<8) + g_ui8EDID[DTD1_OFFSET+6];
	ho = ((g_ui8EDID[DTD1_OFFSET+11] & 0xC0)<<2) + g_ui8EDID[DTD1_OFFSET+8];
	vo = ((g_ui8EDID[DTD1_OFFSET+11] & 0x0C)<<2) + (g_ui8EDID[DTD1_OFFSET+10] >> 4);	
	hpw = ((g_ui8EDID[DTD1_OFFSET+11] & 0x30)<<4) + g_ui8EDID[DTD1_OFFSET+9];
	vpw = ((g_ui8EDID[DTD1_OFFSET+11] & 0x03)<<4) + (g_ui8EDID[DTD1_OFFSET+10]&0x0F);
	hsz = ((g_ui8EDID[DTD1_OFFSET+14] & 0xF0)<<4) + g_ui8EDID[DTD1_OFFSET+12];
	vsz = ((g_ui8EDID[DTD1_OFFSET+14] & 0x0F)<<8) + g_ui8EDID[DTD1_OFFSET+13];
	hbp = g_ui8EDID[DTD1_OFFSET+15];
	vbp = g_ui8EDID[DTD1_OFFSET+16];
	
	UARTprintf("Pixel Clock %dMHz(%dKHz)\n", t/100, t*10);
	UARTprintf("Active zone(Hori.xVert.): %dx%d\n", ha, va);
	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // wating for UARTprintf	
	UARTprintf("Blinking zone(Hori. & Vert.): %d & %d\n", hb, vb);
	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // wating for UARTprintf	
	UARTprintf("Horizontal sync Offset & Pulse width: %d & %d\n", ho, hpw);
	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // wating for UARTprintf	
	UARTprintf("Vertical sync Offset & Pulse width: %d & %d\n", vo, vpw);	
	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // wating for UARTprintf	
	UARTprintf("Border (Hori. & Vert.): %d & %d\n", hbp, vbp);
	UARTprintf("Display Size(Hori.xVert.): %dx%d mm2\n", hsz, vsz);
	ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // wating for UARTprintf
	if ((g_ui8EDID[DTD1_OFFSET+17] & 0x18) !=  0x18) {
		UARTprintf("can't support the panel, because we need a digital separate type\n");
		return;
	}
	UARTprintf("Horizontal sync. Polarity: ");		
	if (g_ui8EDID[DTD1_OFFSET+17] & (1<<1)) {
		UARTprintf("Positive\n");
	} else {
		UARTprintf("Negative\n");
	}

	UARTprintf("Vertical sync. Polarity: ");	
	if (g_ui8EDID[DTD1_OFFSET+17] & (1<<2)) {
		UARTprintf("Positive\n");
	} else {
		UARTprintf("Negative\n");
	}
}

static void dumpDPCD(void)
{
	uint8_t count;
	uint8_t i;
	uint8_t buf[16];
	uint16_t lists[] = {
		0x0000, 0x0100, 0x0200, 0x0210 };

	UARTprintf("--------------------------------------------------------\n");
	UARTprintf("dump panel DPCD value\n");
	UARTprintf("--------------------------------------------------------\n");

	for (i = 0; i < (sizeof(lists)/sizeof(uint16_t)); i++) {
		READ_DPCD(buf, lists[i], 16);
		UARTprintf("DPCD %04xh:", lists[i]);
		for(count = 0; count < 16; count++) { 			UARTprintf(" %02X", buf[count]); 		} 		UARTprintf("\n"); 		ROM_SysCtlDelay(ROM_SysCtlClockGet()/10/3); // wating for UARTprintf 	} } static void showDPCDInfo(void) { 	uint8_t buf[16]; 	READ_DPCD(buf, 0, 16); 	UARTprintf("DPCD: REV:%d.%d, MAX_LINK_RATE:", (buf[0] >> 4), (buf[0]&0xF));
	if (buf[1] == 0x06) {
		UARTprintf("1.62Gbps");
	} else if (buf[1] == 0x0A) {
		UARTprintf("2.7Gbps");
	}
	UARTprintf(" MAX_LINK_LANE:%d\n", buf[2]);
	if (buf[0x0D] & ASSR_SUPPORT) {
		UARTprintf(" support ASSR");
	} else {
		UARTprintf(" not support ASSR");
	}
	if (buf[0x0D] & ENHANCE_FRAMING) {
		UARTprintf(" support Enhance framing");
	} else {
		UARTprintf(" not support Enhance framing");
	}
	UARTprintf("\n");
}
//*****************************************************************************
//
//
//*****************************************************************************
int
main(void)
{
    //volatile uint32_t ui32Loop;
	uint32_t count;
	uint8_t BUF[32];
	uint32_t tmp;
	uint32_t vo = 0;

	tmp = 0;
	BUF[0] = BUF[1] = BUF[2] = BUF[3] = tmp;
	tmp = BUF[0];

    //
    // Enable lazy stacking for interrupt handlers.  This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    //
    ROM_FPULazyStackingEnable();

    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                       SYSCTL_OSC_MAIN);

    //
    // Enable the GPIO port that is used for the on-board LED.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    //
    // Enable the GPIO pins for the LED (PF2 & PF3).
    //
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);

	//
	// Initialize SoftI2C 
	//
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_6 | GPIO_PIN_7);
	memset(&g_sI2C, 0, sizeof(g_sI2C));
	SoftI2CCallbackSet(&g_sI2C, SoftI2CCallback);
	SoftI2CSCLGPIOSet(&g_sI2C, GPIO_PORTA_BASE, GPIO_PIN_6);
	SoftI2CSDAGPIOSet(&g_sI2C, GPIO_PORTA_BASE, GPIO_PIN_7);
	SoftI2CInit(&g_sI2C);

	SoftI2CIntEnable(&g_sI2C);

    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 40000);
    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    TimerEnable(TIMER0_BASE, TIMER_A);

    IntEnable(INT_TIMER0A);


    //
    // Initialize the UART.
    //
    ConfigureUART();
	
	UARTprintf("for ColorBar Test \r\n");
	BUF[0] = 1;
	I2C_Write8(BUF, 0x09, 1); // software reset
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = 0 ;
	I2C_Write8(BUF, 0x5A, 1); // disable VSTREAM
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = 0x0;
	I2C_Write8(BUF, 0x0D, 1); // disable DP_PLL_EN
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);
	
	BUF[0] = 1;
	I2C_Write8(BUF, 0x09, 1); // software reset
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);
	
	BUF[0] = 0x2;
	I2C_Write8(BUF, 0x0A, 1); // Clock Ref = 19.2MHz

	readEDID();
	dumpEDID();
	dumpPanelTiming();
	dumpDPCD();
	showDPCDInfo();
	BUF[0] = (1 << 5) | // SINGL CHANNEL DSI (A)
			(0 << 3) | // Four Lane
			(0);	   // SOT_ERR_TOL_DIS
	I2C_Write8(BUF, 0x10, 1);

	BUF[0] = 0; // disable ASSR
	I2C_Write8(BUF, 0x5A, 1);

	BUF[0] = 1<<1; // 24BPP
	I2C_Write8(BUF, 0x5B, 1);

	BUF[0] = 0; // HPD Enable
	I2C_Write8(BUF, 0x5C, 1);

	BUF[0] = (0 << 6)  | // DP pre emphasis lv 0
			(2 << 4)  | // DP 2 lane
			(2 << 1)  | // Downspread 3750ppm
			(0 << 0);   // disable SSC
	I2C_Write8(BUF, 0x93, 1);

	BUF[0] = (4 << 5) | // 2.70Gbps
			(0 << 2) | // 61ps
			(0 << 0);  // Voltage 	I2C_Write8(BUF, 0x94, 1); // Panel timing  #define  HA			(1920) #define  HSPW		(39) #define  HFP		(59) #define  HBP		(62) #define  HSP		(0) // Hsyn Polarity:0 POS #define  VA         (1200) #define  VSPW		(3) #define  VFP		(6) #define  VBP		(26) #define  VSP        (1) // Vsyn Polarity: NEG 	BUF[0] = (HA & 0xFF); 	BUF[1] = ((HA>>8) & 0xFF);
	I2C_Write8(BUF, 0x20, 2); // ActiveLine
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = (VA & 0xFF);
	BUF[1] = ((VA>>8) & 0xFF);
	I2C_Write8(BUF, 0x24, 2);  // Vertical line
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = (HSPW & 0xFF);
	BUF[1] = ((HSPW>>8) & 0x7F) |
			(HSP << 7); 	I2C_Write8(BUF, 0x2C, 2); // HSYNC Pulse width 	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3); 	BUF[0] = (VSPW & 0xFF); 	BUF[1] = ((VSPW>>8) & 0xFF) |
			(VSP << 7); // neg
	I2C_Write8(BUF, 0x30, 2); // VSYNC Pulse width
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = HBP;
	I2C_Write8(BUF, 0x34, 1); // H_BACK_PORCH
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = VBP;
	I2C_Write8(BUF, 0x36, 1); // V_BACK_PORCH
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = HFP;
	I2C_Write8(BUF, 0x38, 1); // H_FRONT_PORCH
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);
	
	BUF[0] = VFP;
	I2C_Write8(BUF, 0x3A, 1); // V_FRONT_PORCH
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);
	
	BUF[0] = 0;
	I2C_Write8(BUF, 0x5B, 1); //24bpp
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	BUF[0] = 0x1;
	I2C_Write8(BUF, 0x0D, 1); // Enable DP_PLL_EN
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	I2C_Read8(BUF, 0x0A, 1);
	if (BUF[0] & 0x80) UARTprintf("DSI86 PLL has Locked now\n");

	BUF[0] = 0xA;	// ML_TX_MODE,Semi Auto Link Training
	I2C_Write8(BUF, 0x96, 1);
	ROM_SysCtlDelay(ROM_SysCtlClockGet() / 10 / 3);

	I2C_Read8(BUF, 0x96, 1);
	UARTprintf("SemiTraning result:%02X\n", BUF[0]);

#if 0
	BUF[0] = EN_SELF_TEST;
	WRITE_DPCD(BUF, EDP_CONFIGURATION_SET, 1);
#endif

	BUF[0] = 0x18; // Color Bar enable
	I2C_Write8(BUF, 0x3C, 1);
	SysCtlDelay(SysCtlClockGet() / 10 / 3);

	I2C_Read8(BUF, 0x20, 4);

	BUF[0] = (1<<3) ; // VStream
			//(0<<2) | // Enhanced Framing
	I2C_Write8(BUF, 0x5A, 1);
	SysCtlDelay(SysCtlClockGet() / 10 / 3);
	
	UARTprintf("--------------------------------------------------------\n");
	UARTprintf("    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
	UARTprintf("--------------------------------------------------------");

#if 1
	for (tmp = 0; tmp < 8; tmp++) {
		I2C_Read8(BUF, tmp*sizeof(BUF), sizeof(BUF));
		for(count = 0; count < sizeof(BUF); count++) {
			if ((count % 16) == 0) {
				UARTprintf("\n%02X|", vo);
				vo += 0x10;
			}
			UARTprintf(" %02x", BUF[count]);
		}
	}
#endif
	UARTprintf("\n");
	dumpDPCD();
    while(1)
    {
		
        //
        // Turn on the BLUE LED.
        //
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);

        //
        // Delay for a bit.
        //
		 SysCtlDelay(SysCtlClockGet() / 10 / 3);
	
        //
        // Turn off the BLUE LED.
        //
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);

        //
        // Delay for a bit.
        //
        SysCtlDelay(SysCtlClockGet() / 10 / 3);
	}
}

ref. eDP Standard v1.2 
<think>好的,我需要帮助用户找到sn65dsi86相关的驱动程序或安装指南。首先,我应该先回顾用户提供的引用内容,看看里面有没有有用的信息。 引用[2]提到sn65dsi86使用I2C配置方法,需要配置寄存器,这可能意味着驱动程序主要涉及I2C通信和寄存器设置。引用[4]提到了测试代码片段,涉及读写DPCD和解析EDID,这可能说明驱动程序需要处理这些协议。另外,引用[3]提到HBP值的配置错误导致问题,说明正确设置时序寄存器非常重要。 用户可能需要的是Linux内核中的驱动程序,或者是特定平台的配置指南。根据引用[1]和[2],驱动可能涉及轮询法和I2C配置,用户可能需要参考内核中的现有驱动模块,比如TI的SN65DSI86驱动程序可能已经集成在内核中。 接下来,我应该检查Linux内核源码是否有相关的驱动程序。通常,显示转换芯片的驱动可能在drivers/gpu/drm/bridge/目录下。例如,sn65dsi86的驱动文件可能是sn65dsi86.c。如果存在,用户需要配置内核启用该驱动,并正确设置设备树。 此外,引用[4]中的示例代码可能来自TI的示例或文档,用户可能需要参考TI的官方资料或应用笔记来配置寄存器。用户可能需要根据具体的硬件平台(如Tiva C系列)调整代码。 可能的步骤包括:检查内核文档、启用驱动、配置设备树、参考TI的寄存器配置指南。同时,用户可能需要处理时序问题,如HBP、HFP等,确保正确设置以避免显示问题。 最后,用户可能需要调试工具,如i2c-tools,来验证I2C通信和寄存器配置是否正确。引用中提到的问题,如未设置HBP导致显示失败,说明调试时需要仔细检查寄存器写入的值。</think>关于SN65DSI86芯片的驱动程序开发配置,以下是关键步骤和资源指引: ### 1. **Linux内核集成驱动** SN65DSI86的显示桥接驱动已集成在Linux内核中,路径为`drivers/gpu/drm/bridge/ti-sn65dsi86.c`[^2][^4]。配置方法: ```bash # 内核配置中启用驱动 CONFIG_DRM_BRIDGE=y CONFIG_DRM_TI_SN65DSI86=y # 设备树节点示例 dsi_bridge: bridge@2d { compatible = "ti,sn65dsi86"; reg = <0x2d>; enable-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; }; ``` ### 2. **寄存器配置要点** - **I2C地址**:默认0x2D(7位地址),需通过硬件引脚配置[^1][^2] - **关键寄存器组**: ```c // 设置视频时序(示例) i2c_write(0x2D, 0x08, H_TOTAL); // Horizontal total i2c_write(0x2D, 0x0A, H_BP); // 必须正确设置HBP[^3] i2c_write(0x2D, 0x0E, V_TOTAL); // Vertical total ``` ### 3. **调试工具** - **I2C通信验证**: ```bash sudo apt install i2c-tools i2cdetect -y 1 # 检测设备是否在线 i2cdump -y 1 0x2d # 查看寄存器值 ``` - **EDID解析**:需实现DPCD读写逻辑,参考内核`drivers/gpu/drm/drm_dp_helper.c` ### 4. **常见问题解决** - **黑屏问题**:检查`0x0A`寄存器的HBP值是否正确写入 - **时序同步**:确保`0x0010A`寄存器的bit0置1以实现eDP同步 - **触摸屏干扰**:在`config.txt`中添加`disable_touchscreen=1`可关闭冲突的I2C设备 ### 5. **官方资源** - **TI技术文档**:[SN65DSI86 Datasheet](https://www.ti.com/lit/ds/symlink/sn65dsi86.pdf) - **参考设计**:[TI EVM Board Support Package](https://www.ti.com/tool/SN65DSI86EVM)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值