
硬件确认1.1 rk3576 bt1120硬件确认查阅硬件设计指南可以确认 rk3576是支持 16bit bt1120模式 最高支持1080p60Hz。对应引脚可以查阅引脚设计指南或者设备树pinctrl bt1120只有这些引脚如下图所示1.2、nvp6021硬件确认电源有供电引脚控制需要开启并测了一下是否正常。复位这里是active low 因为使用硬件原理图上加了三极管需要取反处理I2C地址及电平使用i2c的电平必须为3v3或者转为3v3的。2、驱动及设备树配置2.1、nvp6021驱动实现nvp6021厂家是没有提供Linux版本驱动的只提供一个1080P_720P5060_74.25MHz_16bit_20191213.txt这种寄存器配置根据这个配置结合设备树简单实现对应分辨率及帧数选择。通过设备树nextchip,vmode 属性来选择对应寄存器写入。nvp6021: nvp602130 { pinctrl-names default; pinctrl-0 nvp6021_rst_pins; compatible nextchip,nvp6021; reg 0x30; reset-gpios gpio3 RK_PD4 GPIO_ACTIVE_HIGH; nextchip,vmode 0; // 0:1080p30, 1:1080p25, 2:720p60, 3:720p50 };实现的驱动源码复位引脚电平会导致寄存器是否正常写入以实际硬件为准。// SPDX-License-Identifier: GPL-2.0 /* * NVP6021 AHD TX initialization driver (I2C only) * * Supports video modes: * 0 1080p30 * 1 1080p25 * 2 720p60 * 3 720p50 */ #include linux/module.h #include linux/i2c.h #include linux/gpio/consumer.h #include linux/delay.h #include linux/of.h #include linux/property.h /* Video mode defines (matching original DecoderInitial) */ #define NVP6021_VMODE_1080P30 0 #define NVP6021_VMODE_1080P25 1 #define NVP6021_VMODE_720P60 2 #define NVP6021_VMODE_720P50 3 struct nvp6021_priv { struct i2c_client *client; struct gpio_desc *reset_gpio; u8 vmode; }; /* Write one byte to register address */ static int nvp6021_write(struct i2c_client *client, u8 reg, u8 val) { return i2c_smbus_write_byte_data(client, reg, val); } /* Hardware reset sequence (exactly as original) */ static void nvp6021_hw_reset(struct nvp6021_priv *priv) { if (!priv-reset_gpio) { dev_warn(priv-client-dev, No reset GPIO, skip reset\n); return; } gpiod_set_value_cansleep(priv-reset_gpio, 0); usleep_range(2000, 3000); gpiod_set_value_cansleep(priv-reset_gpio, 1); usleep_range(20000, 21000); gpiod_set_value_cansleep(priv-reset_gpio, 0); usleep_range(5000, 6000); } /* Full initialization sequence based on the given code */ static int nvp6021_initialize(struct nvp6021_priv *priv) { struct i2c_client *client priv-client; u8 vmode priv-vmode; int ret; dev_info(client-dev, Initializing NVP6021 (vmode%d)\n, vmode); /* Hardware reset */ nvp6021_hw_reset(priv); /* ---- BANK0 ---- */ ret nvp6021_write(client, 0xFF, 0x00); // select BANK0 if (ret) goto err; ret nvp6021_write(client, 0x00, 0x01); if (ret) goto err; switch (vmode) { case NVP6021_VMODE_1080P30: ret nvp6021_write(client, 0x01, 0xF0); if (ret) goto err; ret nvp6021_write(client, 0x04, 0x00); //ret nvp6021_write(client, 0x04, 0x85); break; case NVP6021_VMODE_1080P25: ret nvp6021_write(client, 0x01, 0xF1); if (ret) goto err; ret nvp6021_write(client, 0x04, 0x00); break; case NVP6021_VMODE_720P60: ret nvp6021_write(client, 0x01, 0xE2); if (ret) goto err; ret nvp6021_write(client, 0x04, 0x00); break; case NVP6021_VMODE_720P50: ret nvp6021_write(client, 0x01, 0xE3); if (ret) goto err; ret nvp6021_write(client, 0x04, 0x00); break; default: dev_err(client-dev, Invalid vmode %d\n, vmode); return -EINVAL; } if (ret) goto err; /* ---- BANK1 ---- */ ret nvp6021_write(client, 0xFF, 0x01); // select BANK1 if (ret) goto err; ret nvp6021_write(client, 0x0E, 0x00); if (ret) goto err; /* ---- BANK2 (main configuration) ---- */ ret nvp6021_write(client, 0xFF, 0x02); // select BANK2 if (ret) goto err; /* Write the sequence exactly as provided */ u8 init_vals[][2] { {0x00, 0xFE}, {0x02, 0x00}, {0x04, 0x80}, {0x05, 0x00}, {0x06, 0x10}, {0x0C, 0x04}, {0x0D, 0x3F}, {0x0E, 0x00}, {0x10, 0xEB}, {0x11, 0x10}, {0x12, 0xF0}, {0x13, 0x10}, {0x14, 0x01}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00}, {0x1C, 0x80}, {0x1D, 0x80}, {0x1E, 0x80}, {0x36, 0x01}, {0x37, 0x80}, {0x39, 0x00}, {0x3C, 0x00}, {0x3D, 0x00}, {0x3E, 0x00}, {0x40, 0x01}, {0x41, 0xFF}, {0x42, 0x80}, {0x60, 0x80}, {0x61, 0x80}, {0x63, 0xE0}, {0x64, 0x19}, {0x65, 0x04}, {0x66, 0xEB}, {0x67, 0x60}, {0x68, 0x00}, {0x69, 0x00}, {0x6A, 0x00}, {0x6B, 0x00}, }; for (int i 0; i ARRAY_SIZE(init_vals); i) { ret nvp6021_write(client, init_vals[i][0], init_vals[i][1]); if (ret) goto err; } /* Clear 0x20..0x34 */ for (u8 r 0x20; r 0x34; r) { ret nvp6021_write(client, r, 0x00); if (ret) goto err; } /* Clear 0x48..0x57 */ for (u8 r 0x48; r 0x57; r) { ret nvp6021_write(client, r, 0x00); if (ret) goto err; } /* Extra clears */ ret nvp6021_write(client, 0x59, 0x00); if (ret) goto err; ret nvp6021_write(client, 0x5A, 0x00); if (ret) goto err; for (u8 r 0x5C; r 0x5F; r) { ret nvp6021_write(client, r, 0x00); if (ret) goto err; } /* Mode-dependent BANK2 writes (0x3A, 0x01) */ switch (vmode) { case NVP6021_VMODE_1080P30: ret nvp6021_write(client, 0x3A, 0x11); if (ret) goto err; ret nvp6021_write(client, 0x01, 0xF0); break; case NVP6021_VMODE_1080P25: ret nvp6021_write(client, 0x3A, 0x11); if (ret) goto err; ret nvp6021_write(client, 0x01, 0xF1); break; case NVP6021_VMODE_720P60: ret nvp6021_write(client, 0x3A, 0x11); if (ret) goto err; ret nvp6021_write(client, 0x01, 0xE2); break; case NVP6021_VMODE_720P50: ret nvp6021_write(client, 0x3A, 0x11); if (ret) goto err; ret nvp6021_write(client, 0x01, 0xE3); break; } if (ret) goto err; /* Second BANK2 access – mode‑specific fine‑tuning */ ret nvp6021_write(client, 0xFF, 0x02); // ensure BANK2 if (ret) goto err; switch (vmode) { case NVP6021_VMODE_1080P30: ret nvp6021_write(client, 0x3D, 0x80); if (ret) goto err; ret nvp6021_write(client, 0x5C, 0x52); if (ret) goto err; ret nvp6021_write(client, 0x5D, 0xCA); if (ret) goto err; ret nvp6021_write(client, 0x5E, 0xF0); if (ret) goto err; ret nvp6021_write(client, 0x5F, 0x2C); if (ret) goto err; ret nvp6021_write(client, 0x1D, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x1E, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x37, 0xB0); break; case NVP6021_VMODE_1080P25: ret nvp6021_write(client, 0x3D, 0x80); if (ret) goto err; ret nvp6021_write(client, 0x5C, 0x52); if (ret) goto err; ret nvp6021_write(client, 0x5D, 0xC3); if (ret) goto err; ret nvp6021_write(client, 0x5E, 0x7D); if (ret) goto err; ret nvp6021_write(client, 0x5F, 0xC8); if (ret) goto err; ret nvp6021_write(client, 0x1D, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x1E, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x37, 0xB0); break; case NVP6021_VMODE_720P60: ret nvp6021_write(client, 0x3D, 0x80); if (ret) goto err; ret nvp6021_write(client, 0x5C, 0x52); if (ret) goto err; ret nvp6021_write(client, 0x5D, 0xC5); if (ret) goto err; ret nvp6021_write(client, 0x5E, 0xF9); if (ret) goto err; ret nvp6021_write(client, 0x5F, 0x2C); if (ret) goto err; ret nvp6021_write(client, 0x1D, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x1E, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x37, 0xB0); break; case NVP6021_VMODE_720P50: ret nvp6021_write(client, 0x3D, 0x80); if (ret) goto err; ret nvp6021_write(client, 0x5C, 0x52); if (ret) goto err; ret nvp6021_write(client, 0x5D, 0xCF); if (ret) goto err; ret nvp6021_write(client, 0x5E, 0xE7); if (ret) goto err; ret nvp6021_write(client, 0x5F, 0x2C); if (ret) goto err; ret nvp6021_write(client, 0x1D, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x1E, 0xB0); if (ret) goto err; ret nvp6021_write(client, 0x37, 0xB0); break; } if (ret) goto err; dev_info(client-dev, NVP6021 initialization completed successfully\n); //return 0; //ret nvp6021_write(client, 0xFF, 0x02); // 确保选择 BANK2 //if (ret) goto err; //ret nvp6021_write(client, 0x04, 0x81); // 0x04 的 bit7 置 1 使能彩条输出 //if (ret) goto err; dev_info(client-dev, NVP6021 initialization done (color bar test enabled)\n); return 0; err: dev_err(client-dev, I2C write failed\n); return ret; } /* Probe - called when device is found on I2C bus */ static int nvp6021_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev client-dev; struct nvp6021_priv *priv; u32 vmode NVP6021_VMODE_1080P30; int ret; priv devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv-client client; i2c_set_clientdata(client, priv); /* Obtain reset GPIO (active high as in original) */ priv-reset_gpio devm_gpiod_get_optional(dev, reset, GPIOD_OUT_LOW); if (IS_ERR(priv-reset_gpio)) return dev_err_probe(dev, PTR_ERR(priv-reset_gpio), Failed to get reset GPIO\n); /* Read video mode from device tree property */ device_property_read_u32(dev, nextchip,vmode, vmode); if (vmode NVP6021_VMODE_720P50) { dev_warn(dev, Invalid vmode %u, fallback to 1080p30\n, vmode); vmode NVP6021_VMODE_1080P30; } priv-vmode (u8)vmode; /* Run initialization sequence */ ret nvp6021_initialize(priv); if (ret) return ret; dev_info(dev, NVP6021 driver probe successful\n); return 0; } static const struct of_device_id nvp6021_of_match[] { { .compatible nextchip,nvp6021 }, { } }; MODULE_DEVICE_TABLE(of, nvp6021_of_match); static const struct i2c_device_id nvp6021_id[] { { nvp6021, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, nvp6021_id); static struct i2c_driver nvp6021_driver { .driver { .name nvp6021, .of_match_table nvp6021_of_match, }, .probe nvp6021_probe, .id_table nvp6021_id, }; module_i2c_driver(nvp6021_driver); MODULE_DESCRIPTION(Nextchip NVP6021 AHD TX initialization driver); MODULE_AUTHOR(lhx); MODULE_LICENSE(GPL);使用i2c-tools功能查看寄存器是正常写入,驱动里面有三个bank的寄存器配置这里以切换到bank0为例子2.2 设备树配置#include dt-bindings/display/media-bus-format.h #include dt-bindings/display/rockchip_vop.h /{ panel: panel { compatible simple-panel; clock-frequency 74250000; bus-format MEDIA_BUS_FMT_YUYV8_1X16; status okay; display-timings { native-mode timing_1080p30; timing_1080p30: timing { clock-frequency 74250000; // 74.25MHz时钟 hactive 1920; // 有效水平像素 vactive 1080; // 有效垂直行数 hfront-porch 88; // 水平前沿 hback-porch 148; // 水平后沿 hsync-len 44; // 水平同步脉冲 vfront-porch 4; // 垂直前沿 vback-porch 36; // 垂直后沿 vsync-len 5; // 垂直同步脉冲 hsync-active 1; // 高电平有效 vsync-active 1; // 高电平有效 de-active 0; // DE信号极性 pixelclk-active 0; // 像素时钟下降沿采样 }; timing_720p60: timing1 { clock-frequency 74250000; hactive 1280; vactive 720; hfront-porch 110; hback-porch 220; hsync-len 40; vfront-porch 5; vback-porch 20; vsync-len 5; hsync-active 1; vsync-active 1; de-active 0; pixelclk-active 0; }; }; port { panel_in_rgb: endpoint { remote-endpoint rgb_out_panel; }; }; }; }; display_subsystem { status okay; }; i2c8 { clock-frequency 400000; pinctrl-0 i2c8m1_xfer; status okay; nvp6021: nvp602130 { pinctrl-names default; pinctrl-0 nvp6021_rst_pins; compatible nextchip,nvp6021; reg 0x30; reset-gpios gpio3 RK_PD4 GPIO_ACTIVE_HIGH; nextchip,vmode 2; // 0:1080p30, 1:1080p25, 2:720p60, 3:720p50 }; }; rgb { status okay; pinctrl-names default; pinctrl-0 bt1120_pins; ports { port1 { reg 1; rgb_out_panel: endpoint { remote-endpoint panel_in_rgb; }; }; }; }; rgb_in_vp2 { status okay; }; route_rgb { status okay; connect vp2_out_rgb; }; pinctrl { nvp6021_rst { nvp6021_rst_pins: nvp6021_rst_pins { rockchip,pins 3 RK_PD4 RK_FUNC_GPIO pcfg_pull_none; }; }; };3、调试与测试查看当前屏幕的显示状态cat /sys/kernel/debug/dri/0/summary使用modetest测试输出彩条modetest -M rockchipmodestet -M rockchip -s 16872:1920x1080能正常输出彩条屏幕是调通了的。如果输出不太正常 可以尝试抓ahd_out输出波形或者时钟是否正确这里原厂说波形算下来和1080p30的行时序差不多具体如果计算并未说明。暂时还有一个问题未解决从寄存器配置输出彩条或者从modetest测试都偏暗测试调整过datasheet 里面, bnak2 0x1d/1e/0x37 没有效果也测试过调整色域参考rk色域说明也是没有什么效果。