查阅硬件设计指南可以确认 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;