zynq st7701s lcd显示驱动

内容分享3周前发布
0 0 0

一:背景

        博主使用zynq 7020 驱动st7701s lcd芯片,因项目需要,目前使用fb框架。博主采用内核6.1x以上版本

二:lcd显示需要的像素时钟计算

        时钟 = htotal*vtotal*60帧 

        可以参考网上的资料详细学习一下同步信号的时序

        一般需要配置:



.hdisplay	= 480,
.hsync_start	= 480+ 20,
.hsync_end	= 480+ 10 + 20,
.htotal		= 480+ 10 + 20+ 24,
 
.vdisplay	= 800,
.vsync_start	= 800 + 18 ,
.vsync_end	= 800 + 18 + 4, 
.vtotal		= 800 + 18 + 4 + 24,

三:st7701s 驱动芯片解析

ST7701S_SPEC_V1.1

3线spi模式

zynq st7701s lcd显示驱动

4线spi模式

zynq st7701s lcd显示驱动

两者的区别:spi 4线模式 + dc引脚控制,spi3线模式+9bit控制,第8bit为dc控制,dc主要是表明传输的是数据和还是cmd 。具体lcd 屏幕是几线控制模式,需要看lcd规格书确定。博主的是3线+9bit控制

最主要地址控制部分:

zynq st7701s lcd显示驱动

四:st7701s 参考驱动

        根据内核版本有driversgpudrmpanelpanel-sitronix-st7701.c 可以看到里面的源码时基于spi4线 模式+dc引脚控制的,或者是根据compatible配置不同可以mipi的驱动方式,跟博主使用的spi3线 + 9bit不一样,因此需要修改该驱动



#include <linux/module.h>
#include <linux/platform_device.h>
#include <drm/drm_panel.h>
#include <linux/fb.h>
#include <linux/fbcon.h>
#include <linux/clk.h>
#include <linux/dma/xilinx_dma.h>
#include <linux/of_dma.h>
#include <video/videomode.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <video/of_videomode.h>
#include <linux/pwm.h>
#include "xlnx_bridge.h"
// #include "xilinx_vtc.h"
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <linux/platform_device.h>
#include <linux/bitfield.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
 
#include <video/mipi_display.h>
 
/* Command2 BKx selection command */
#define ST7701_CMD2BKX_SEL			0xFF
#define ST7701_CMD1				0
#define ST7701_CMD2				BIT(4)
#define  ST7701_CMD2BK_MASK     GENMASK(3, 0)
 
/* Command2, BK0 commands */
#define ST7701_CMD2_BK0_PVGAMCTRL		0xB0 /* Positive Voltage Gamma Control */
#define ST7701_CMD2_BK0_NVGAMCTRL		0xB1 /* Negative Voltage Gamma Control */
#define ST7701_CMD2_BK0_LNESET			0xC0 /* Display Line setting */
#define ST7701_CMD2_BK0_PORCTRL			0xC1 /* Porch control */
#define _CMD2_BK0_INVSEL			0xC2 /* Inversion selection, Frame Rate Control */
#define ST7701_CMD2_BK0_INVSEL          0xC2 
/* Command2, BK1 commands */
#define ST7701_CMD2_BK1_VRHS			0xB0 /* Vop amplitude setting */
#define ST7701_CMD2_BK1_VCOM			0xB1 /* VCOM amplitude setting */
#define ST7701_CMD2_BK1_VGHSS			0xB2 /* VGH Voltage setting */
#define ST7701_CMD2_BK1_TESTCMD			0xB3 /* TEST Command Setting */
#define ST7701_CMD2_BK1_VGLS			0xB5 /* VGL Voltage setting */
#define ST7701_CMD2_BK1_PWCTLR1			0xB7 /* Power Control 1 */
#define ST7701_CMD2_BK1_PWCTLR2			0xB8 /* Power Control 2 */
#define ST7701_CMD2_BK1_SPD1			0xC1 /* Source pre_drive timing set1 */
#define ST7701_CMD2_BK1_SPD2			0xC2 /* Source EQ2 Setting */
#define ST7701_CMD2_BK1_MIPISET1		0xD0 /* MIPI Setting 1 */
 
/* Command2, BK0 bytes */
#define ST7701_CMD2_BK0_GAMCTRL_AJ_MASK		GENMASK(7, 6)
#define ST7701_CMD2_BK0_GAMCTRL_VC0_MASK	GENMASK(3, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC4_MASK	GENMASK(5, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC8_MASK	GENMASK(5, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC16_MASK	GENMASK(4, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC24_MASK	GENMASK(4, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC52_MASK	GENMASK(3, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC80_MASK	GENMASK(5, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC108_MASK	GENMASK(3, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC147_MASK	GENMASK(3, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC175_MASK	GENMASK(5, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC203_MASK	GENMASK(3, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC231_MASK	GENMASK(4, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC239_MASK	GENMASK(4, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC247_MASK	GENMASK(5, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC251_MASK	GENMASK(5, 0)
#define ST7701_CMD2_BK0_GAMCTRL_VC255_MASK	GENMASK(4, 0)
#define ST7701_CMD2_BK0_LNESET_LINE_MASK	GENMASK(6, 0)
#define ST7701_CMD2_BK0_LNESET_LDE_EN		BIT(7)
#define ST7701_CMD2_BK0_LNESET_LINEDELTA	GENMASK(1, 0)
#define ST7701_CMD2_BK0_PORCTRL_VBP_MASK	GENMASK(7, 0)
#define ST7701_CMD2_BK0_PORCTRL_VFP_MASK	GENMASK(7, 0)
#define ST7701_CMD2_BK0_INVSEL_ONES_MASK	GENMASK(5, 4)
#define ST7701_CMD2_BK0_INVSEL_NLINV_MASK	GENMASK(2, 0)
#define ST7701_CMD2_BK0_INVSEL_RTNI_MASK	GENMASK(4, 0)
 
/* Command2, BK1 bytes */
#define ST7701_CMD2_BK1_VRHA_MASK		GENMASK(7, 0)
#define ST7701_CMD2_BK1_VCOM_MASK		GENMASK(7, 0)
#define ST7701_CMD2_BK1_VGHSS_MASK		GENMASK(3, 0)
#define ST7701_CMD2_BK1_TESTCMD_VAL		BIT(7)
#define ST7701_CMD2_BK1_VGLS_ONES		BIT(6)
#define ST7701_CMD2_BK1_VGLS_MASK		GENMASK(3, 0)
#define ST7701_CMD2_BK1_PWRCTRL1_AP_MASK	GENMASK(7, 6)
#define ST7701_CMD2_BK1_PWRCTRL1_APIS_MASK	GENMASK(3, 2)
#define ST7701_CMD2_BK1_PWRCTRL1_APOS_MASK	GENMASK(1, 0)
#define ST7701_CMD2_BK1_PWRCTRL2_AVDD_MASK	GENMASK(5, 4)
#define ST7701_CMD2_BK1_PWRCTRL2_AVCL_MASK	GENMASK(1, 0)
#define ST7701_CMD2_BK1_SPD1_ONES_MASK		GENMASK(6, 4)
#define ST7701_CMD2_BK1_SPD1_T2D_MASK		GENMASK(3, 0)
#define ST7701_CMD2_BK1_SPD2_ONES_MASK		GENMASK(6, 4)
#define ST7701_CMD2_BK1_SPD2_T3D_MASK		GENMASK(3, 0)
#define ST7701_CMD2_BK1_MIPISET1_ONES		BIT(7)
#define ST7701_CMD2_BK1_MIPISET1_EOT_EN		BIT(3)
 
#define CFIELD_PREP(_mask, _val)					
	(((typeof(_mask))(_val) << (__builtin_ffsll(_mask) - 1)) & (_mask))
 
enum op_bias {
	OP_BIAS_OFF = 0,
	OP_BIAS_MIN,
	OP_BIAS_MIDDLE,
	OP_BIAS_MAX
};
 
struct st7701;
 
struct st7701_panel_desc {
	const struct drm_display_mode *mode;
	unsigned int lanes;
	enum mipi_dsi_pixel_format format;
	unsigned int panel_sleep_delay;
 
	/* TFT matrix driver configuration, panel specific. */
	const u8	pv_gamma[16];	/* Positive voltage gamma control */
	const u8	nv_gamma[16];	/* Negative voltage gamma control */
	const u8	nlinv;		/* Inversion selection */
	const u32	vop_uv;		/* Vop in uV */
	const u32	vcom_uv;	/* Vcom in uV */
	const u16	vgh_mv;		/* Vgh in mV */
	const s16	vgl_mv;		/* Vgl in mV */
	const u16	avdd_mv;	/* Avdd in mV */
	const s16	avcl_mv;	/* Avcl in mV */
	const enum op_bias	gamma_op_bias;
	const enum op_bias	input_op_bias;
	const enum op_bias	output_op_bias;
	const u16	t2d_ns;		/* T2D in ns */
	const u16	t3d_ns;		/* T3D in ns */
	const bool	eot_en;
 
	/* GIP sequence, fully custom and undocumented. */
	void		(*gip_sequence)(struct st7701 *st7701);
};
 
struct st7701 {
	struct spi_device *spi;
	const struct st7701_panel_desc *desc;
 
	//struct platform_device *pdev; 
    struct gpio_desc *sck;
    struct gpio_desc *mosi;
    struct gpio_desc *cs;
    
    // 时序参数
    unsigned int speed_hz;
 
	struct gpio_desc *reset;
	unsigned int sleep_delay;
	enum drm_panel_orientation orientation;
 
	int (*write_command)(struct st7701 *st7701, u8 cmd, const u8 *seq,
			     size_t len);
};
 
/* 自定义结构体用于描述我们的 LCD 设备 */
struct xilinx_vdmafb_dev {
    struct fb_info *info; // FrameBuffer 设备信息
    struct platform_device *pdev; // platform 平台设备
    struct clk *pclk; // LCD 像素时钟
    struct dma_chan *vdma; // VDMA 通道
    struct dma_interleaved_template *dma_template;
    struct xlnx_bridge *vtc_bridge; // VTC桥接器(Xilinx标准接口)
    struct gpio_desc* bl_gpio; // LCD 背光引脚
};
static struct st7701 *g_st7701;
static inline struct st7701 *panel_to_st7701(struct xilinx_vdmafb_dev *fbdev)
{
	return g_st7701;
}
 
#define ST7701_CMD(x)  ((x) & 0x1ff)  // 第9位为0表示命令
#define ST7701_DATA(x) ((x) | 0x100)  // 第9位为1表示数据
// 延时函数(ns)
static void st7701_delay_ns(struct st7701 *ctx, unsigned int us_count)
{
    //ns 延时,根据平台修改
}
 
// 发送9位数据(命令或数据)
static void st7701_spi_send_9bit(struct st7701 *ctx, u16 data)
{
    int i;
    for (i = 8; i >= 0; i--) {
        gpiod_set_value(ctx->sck, 0);
        if(data & (1<<i)){
            gpiod_set_value(ctx->mosi, 1);
        }
        else{
             gpiod_set_value(ctx->mosi, 0);
        }
        st7701_delay_ns(ctx, 33);
        gpiod_set_value(ctx->sck, 1);
        st7701_delay_ns(ctx, 33);
    }
}
 
static void st7701_send_cmd(struct st7701 *ctx, u8 cmd)
{
	st7701_delay_ns(ctx,110);
    st7701_spi_send_9bit(ctx, ST7701_CMD(cmd));
}
 
static void st7701_send_data(struct st7701 *ctx, u8 data)
{
	st7701_delay_ns(ctx,110);
    st7701_spi_send_9bit(ctx, ST7701_DATA(data));
}
 
static int st7701_send_data_bulk(struct st7701 *st7701, u8 cmd, const u8 *seq,
			    size_t len)
{
    st7701_send_cmd(st7701, cmd); 
    msleep(1); 
    for(int i=0;i<len;i++) {
        msleep(1); 
        st7701_send_data(st7701, seq[i]);
    }
	return 0;
}
 
 
#define ST7701_WRITE(st7701, cmd, seq...)				
	{								
		const u8 d[] = { seq };					
		st7701_send_data_bulk(st7701, cmd, d, ARRAY_SIZE(d));	
	}
 
static u8 st7701_vgls_map(struct st7701 *st7701)
{
	const struct st7701_panel_desc *desc = st7701->desc;
	struct {
		s32	vgl;
		u8	val;
	} map[16] = {
		{ -7060, 0x0 }, { -7470, 0x1 },
		{ -7910, 0x2 }, { -8140, 0x3 },
		{ -8650, 0x4 }, { -8920, 0x5 },
		{ -9210, 0x6 }, { -9510, 0x7 },
		{ -9830, 0x8 }, { -10170, 0x9 },
		{ -10530, 0xa }, { -10910, 0xb },
		{ -11310, 0xc }, { -11730, 0xd },
		{ -12200, 0xe }, { -12690, 0xf }
	};
	int i;
 
	for (i = 0; i < ARRAY_SIZE(map); i++)
		if (desc->vgl_mv == map[i].vgl)
			return map[i].val;
 
	return 0;
}
 
static void st7701_switch_cmd_bkx(struct st7701 *st7701, bool cmd2, u8 bkx)
{
	u8 val;
 
	if (cmd2)
		val = ST7701_CMD2 | FIELD_PREP(ST7701_CMD2BK_MASK, bkx);
	else
		val = ST7701_CMD1;
 
	ST7701_WRITE(st7701, ST7701_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, val);
}
 
static void st7701_init_sequence(struct st7701 *st7701)   
{
	const struct st7701_panel_desc *desc = st7701->desc;
	const struct drm_display_mode *mode = desc->mode;
	const u8 linecount8 = mode->vdisplay / 8;
	const u8 linecountrem2 = (mode->vdisplay % 8) / 2;
 
	ST7701_WRITE(st7701, MIPI_DCS_SOFT_RESET, 0x00);
 
	/* We need to wait 5ms before sending new commands */
	msleep(5);
 
	ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE, 0x00);
 
	msleep(st7701->sleep_delay);
 
    
	ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE, 0x00);
 
	msleep(st7701->sleep_delay);
 
	/* Command2, BK0 */
	st7701_switch_cmd_bkx(st7701, true, 0);
 
	st7701->write_command(st7701, ST7701_CMD2_BK0_PVGAMCTRL, desc->pv_gamma,
			      ARRAY_SIZE(desc->pv_gamma));
	st7701->write_command(st7701, ST7701_CMD2_BK0_NVGAMCTRL, desc->nv_gamma,
			      ARRAY_SIZE(desc->nv_gamma));
 
	ST7701_WRITE(st7701, ST7701_CMD2_BK0_LNESET,
		   FIELD_PREP(ST7701_CMD2_BK0_LNESET_LINE_MASK, linecount8 - 1) |
		   (linecountrem2 ? ST7701_CMD2_BK0_LNESET_LDE_EN : 0),
		   FIELD_PREP(ST7701_CMD2_BK0_LNESET_LINEDELTA, linecountrem2));
	ST7701_WRITE(st7701, ST7701_CMD2_BK0_PORCTRL,
		   FIELD_PREP(ST7701_CMD2_BK0_PORCTRL_VBP_MASK,
			      mode->vtotal - mode->vsync_end),
		   FIELD_PREP(ST7701_CMD2_BK0_PORCTRL_VFP_MASK,
			      mode->vsync_start - mode->vdisplay));
	/*
	 * Horizontal pixel count configuration:
	 * PCLK = 512 + (RTNI[4:0] * 16)
	 * The PCLK is number of pixel clock per line, which matches
	 * mode htotal. The minimum is 512 PCLK.
	 */
	ST7701_WRITE(st7701, ST7701_CMD2_BK0_INVSEL,
		   ST7701_CMD2_BK0_INVSEL_ONES_MASK |
		   FIELD_PREP(ST7701_CMD2_BK0_INVSEL_NLINV_MASK, desc->nlinv),
		   FIELD_PREP(ST7701_CMD2_BK0_INVSEL_RTNI_MASK,
			      (clamp((u32)mode->htotal, 512U, 1008U) - 512) / 16));
 
	/* Command2, BK1 */  //B0开始地方
	st7701_switch_cmd_bkx(st7701, true, 1);
 
	/* Vop = 3.5375V + (VRHA[7:0] * 0.0125V) */ //B0
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_VRHS,
		   FIELD_PREP(ST7701_CMD2_BK1_VRHA_MASK,
			      DIV_ROUND_CLOSEST(desc->vop_uv - 3537500, 12500)));
 
	/* Vcom = 0.1V + (VCOM[7:0] * 0.0125V) */
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_VCOM,
		   FIELD_PREP(ST7701_CMD2_BK1_VCOM_MASK,
			      DIV_ROUND_CLOSEST(desc->vcom_uv - 100000, 12500)));
 
	/* Vgh = 11.5V + (VGHSS[7:0] * 0.5V) */
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGHSS,
		   FIELD_PREP(ST7701_CMD2_BK1_VGHSS_MASK,
			      DIV_ROUND_CLOSEST(clamp(desc->vgh_mv,
						      (u16)11500,
						      (u16)17000) - 11500,
						500)));
 
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_TESTCMD, ST7701_CMD2_BK1_TESTCMD_VAL);
 
	/* Vgl is non-linear */
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGLS,
		   ST7701_CMD2_BK1_VGLS_ONES |
		   FIELD_PREP(ST7701_CMD2_BK1_VGLS_MASK, st7701_vgls_map(st7701)));
//B7
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR1,  
		   FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL1_AP_MASK,
			      desc->gamma_op_bias) |
		   FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL1_APIS_MASK,
			      desc->input_op_bias) |
		   FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL1_APOS_MASK,
			      desc->output_op_bias));
 
	/* Avdd = 6.2V + (AVDD[1:0] * 0.2V) , Avcl = -4.4V - (AVCL[1:0] * 0.2V) */
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR2, 
		   FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL2_AVDD_MASK,
			      DIV_ROUND_CLOSEST(desc->avdd_mv - 6200, 200)) |
		   FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL2_AVCL_MASK,
			      DIV_ROUND_CLOSEST(-4400 - desc->avcl_mv, 200)));
 
	/* T2D = 0.2us * T2D[3:0] */ 
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD1,
		   ST7701_CMD2_BK1_SPD1_ONES_MASK |
		   FIELD_PREP(ST7701_CMD2_BK1_SPD1_T2D_MASK,
			      DIV_ROUND_CLOSEST(desc->t2d_ns, 200)));
 
	/* T3D = 4us + (0.8us * T3D[3:0]) */
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD2,
		   ST7701_CMD2_BK1_SPD2_ONES_MASK |
		   FIELD_PREP(ST7701_CMD2_BK1_SPD2_T3D_MASK,
			      DIV_ROUND_CLOSEST(desc->t3d_ns - 4000, 800)));
 
	ST7701_WRITE(st7701, ST7701_CMD2_BK1_MIPISET1,
		   ST7701_CMD2_BK1_MIPISET1_ONES |
		   (desc->eot_en ? ST7701_CMD2_BK1_MIPISET1_EOT_EN : 0));
    
}
 
static void st7701s_gip_sequence(struct st7701 *st7701)
{
	st7701_switch_cmd_bkx(st7701, true, 3);
	ST7701_WRITE(st7701, 0xEF, 0x08);
 
    //此部分根据产商提供测demo st7701s寄存器设置修改。可以直接参考内核的驱动文件
    //。。。。。
}
 
static int st7701_prepare(struct xilinx_vdmafb_dev *fbdev)
{
	struct st7701 *st7701 = panel_to_st7701(fbdev);
	int ret;
 
	gpiod_set_value(st7701->reset, 0);
	msleep(200);
	gpiod_set_value(st7701->reset, 1);
	msleep(150);
 
    gpiod_set_value(st7701->cs, 0);
 
	st7701_init_sequence(st7701);
    gpiod_set_value(st7701->cs, 0);
	if (st7701->desc->gip_sequence)
		st7701->desc->gip_sequence(st7701);
 
	/* Disable Command2 */
	st7701_switch_cmd_bkx(st7701, false, 0);
 
	return 0;
}
 
static int st7701_enable(struct xilinx_vdmafb_dev *fbdev)
{
	struct st7701 *st7701 = panel_to_st7701(fbdev);
 
	ST7701_WRITE(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00);
 
	return 0;
}
 
static int st7701_disable(struct xilinx_vdmafb_dev *fbdev)
{
	struct st7701 *st7701 = panel_to_st7701(fbdev);
 
	ST7701_WRITE(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);
 
	return 0;
}
 
static int st7701_unprepare(struct xilinx_vdmafb_dev *fbdev)
{
	struct st7701 *st7701 = panel_to_st7701(fbdev);
 
	ST7701_WRITE(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00);
 
	msleep(st7701->sleep_delay);
 
	gpiod_set_value(st7701->reset, 0);
 
    gpiod_set_value(st7701->cs, 1);
 
	/**
	 * During the Resetting period, the display will be blanked
	 * (The display is entering blanking sequence, which maximum
	 * time is 120 ms, when Reset Starts in Sleep Out –mode. The
	 * display remains the blank state in Sleep In –mode.) and
	 * then return to Default condition for Hardware Reset.
	 *
	 * So we need wait sleep_delay time to make sure reset completed.
	 */
	msleep(st7701->sleep_delay);
 
	return 0;
}
 
static const struct drm_display_mode rgb565_mode = {
	.clock		= 24000,// = htotal*vtotal*60
 
    .hdisplay	= 480,
	.hsync_start	= 480+ 20,
	.hsync_end	= 480+ 10 + 20,
	.htotal		= 480+ 10 + 20+ 24,
 
	.vdisplay	= 800,
	.vsync_start	= 800 + 18,
	.vsync_end	= 800 + 18+ 4, 
	.vtotal		= 800 + 18+ 4 + 24,
    .width_mm	= 50,  //物理板卡宽高
	.height_mm	= 81,
 
	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 
	.type = FB_TYPE_PACKED_PIXELS,
};
 
static const struct st7701_panel_desc rgb565_desc = {
	.mode = &rgb565_mode,
 
	.panel_sleep_delay = 80,
 
	.pv_gamma = {
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x6),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x10),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x16),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),
 
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),
 
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x22),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x14),
 
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xf),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x29),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x2f),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)
	},
	.nv_gamma = {
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0xf),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x18),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1e),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xc),
 
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0xf),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0xa),
 
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x9),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x5),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x10),
 
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x11),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2A),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x34),
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
		CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)
	},
	.nlinv = 8,
	.vop_uv = 4500000,
	.vcom_uv = 875000,
	.vgh_mv = 12900,
	.vgl_mv = -10000,
	.avdd_mv = 6600,
	.avcl_mv = -4400,
	.gamma_op_bias = OP_BIAS_MIDDLE,
	.input_op_bias = OP_BIAS_MIN,
	.output_op_bias = OP_BIAS_MIN,
	.t2d_ns = 1600,
	.t3d_ns = 10400,
	.eot_en = true,
	.gip_sequence = st7701s_gip_sequence,
};
 
static int st7701_probe(struct xilinx_vdmafb_dev *fbdev, int connector_type)
{
	struct device * dev = &fbdev->pdev->dev;
	const struct st7701_panel_desc *desc = &rgb565_desc;
	struct st7701 *st7701;
	int ret;
	
	st7701 = devm_kzalloc(dev, sizeof(struct st7701), GFP_KERNEL);
	if (!st7701)
		return -ENOMEM;
 
    dev_info(dev, "st7701_probe devm_kzalloc drm_panel_add
");
 
	st7701->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
	if (IS_ERR(st7701->reset)) {
		dev_err(dev, "Couldn't get reset GPIO
");
		return PTR_ERR(st7701->reset);
	}
 
    st7701->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
    if (IS_ERR(st7701->sck)){
		return PTR_ERR(st7701->sck);
    }
 
    st7701->mosi = devm_gpiod_get(dev, "mosi", GPIOD_OUT_LOW);
    if (IS_ERR(st7701->mosi))
    {
        return PTR_ERR(st7701->mosi); 
    }
    st7701->cs = devm_gpiod_get(dev, "cs", GPIOD_OUT_HIGH);
    if (IS_ERR(st7701->cs)){
        return PTR_ERR(st7701->cs);
    }
 
    // 获取SPI频率
    ret = device_property_read_u32(dev, "spi-max-frequency", &st7701->speed_hz);
    if (ret)
        st7701->speed_hz = 10000000; 
 
	st7701->sleep_delay = 120 + desc->panel_sleep_delay;
 
	st7701->desc = desc;
    g_st7701 = st7701;
	return ret;
}
 
static int st7701_spi_probe(struct xilinx_vdmafb_dev *vdev)
{
 
	struct gpio_desc *dc;
	int err;
	err = st7701_probe(vdev, DRM_MODE_CONNECTOR_DPI);
	if (err)
		return err;
 
    g_st7701->write_command = st7701_send_data_bulk;
	return 0;
}

五:fb驱动和设备树

        上述修改的是st7701s的驱动,通常来说就是panel的驱动,针对fb要使用到这个pannel ,需要添加fb驱动代码,参考正点原子的vdma教程,并修改为内核6.1x版本,最主要的修改就是vtc时序和fb ops操作



static int vdmafb_setcolreg(unsigned regno, unsigned red,unsigned green, unsigned blue,
unsigned transp, struct fb_info *fb_info)
{
    u32 tmp;
 
    if (regno >= 16)
    return 1;
 
    u8 r5 = red >> 3;   
    u8 g6 = green >> 2;  
    u8 b5 = blue >> 3;  
    tmp = (r5 << 11) | (g6 << 5) | b5; 
 
    ((u32*)(fb_info->pseudo_palette))[regno] = tmp;
 
    return 0;
}
 
static int vdmafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *fb_info)
{
    struct fb_var_screeninfo *fb_var = &fb_info->var;
    memcpy(var, fb_var, sizeof(struct fb_var_screeninfo));
    return 0;
}
 
static int vdmafb_blank(int blank_mode,struct fb_info *fb_info)
{
    return 0;
}
 
/* Frame Buffer 操作函数集 */
static struct fb_ops vdmafb_ops = {
    .owner = THIS_MODULE,
    .fb_setcolreg = vdmafb_setcolreg,
    .fb_check_var = vdmafb_check_var,
    .fb_blank = vdmafb_blank, 
    //下面三个接口需要添加内核宏定义,配置可以看后面部分
    .fb_fillrect = cfb_fillrect,
    .fb_copyarea = cfb_copyarea,
    .fb_imageblit = cfb_imageblit,
    .fb_mmap = fb_io_mmap, //一定需要加 ,不然应用程序在mmap会报错,没办法映射内存操作
};
 
static int vdmafb_init_fbinfo_dt(struct xilinx_vdmafb_dev *fbdev,
struct videomode *vmode)
{
    struct device *dev = &fbdev->pdev->dev;
    int display_timing = 0;
    int ret;
 
    ret = of_get_videomode(dev->of_node, vmode, display_timing);
    if (ret < 0) {
        dev_err(dev, "Failed to get videomode from DT
");
        return ret;
    }
 
    return 0;
}
static int vdmafb_init_fbinfo(struct xilinx_vdmafb_dev *fbdev,
struct videomode *vmode)
{
    struct device *dev = &fbdev->pdev->dev;
    struct fb_info *fb_info = fbdev->info;
    struct fb_videomode mode = {0};
    dma_addr_t fb_phys; // 显存物理地址
    void *fb_virt;      // 显存虚拟地址
    unsigned fb_size;   // 显存大小
    int ret;
 
    /* 解析设备树获取 LCD 时序参数 */
    ret = vdmafb_init_fbinfo_dt(fbdev, vmode);
    if (ret < 0)
        return ret;
 
    /* 申请 LCD 显存 强制页对齐 */
    fb_size = vmode->hactive * vmode->vactive * 2;
    unsigned long alloc_size = PAGE_ALIGN(fb_size); 
 
    fb_virt = dma_alloc_wc(dev, alloc_size, &fb_phys, GFP_KERNEL | GFP_USER);
    if (!fb_virt) {
        dev_err(dev, "dma_alloc_wc failed (size=%lu)
", alloc_size);
        return -ENOMEM;
    }
    memset(fb_virt, 0, fb_size); // 显存清零
 
    /* 初始化 fb_info */
    fb_info->fbops = &vdmafb_ops;
    fb_info->flags = 0; //注意这里设置为0即可
    fb_info->screen_base = fb_virt;
    fb_info->screen_size = fb_size;
 
 
    strcpy(fb_info->fix.id, "xlnx");
    fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
    fb_info->fix.visual = FB_VISUAL_TRUECOLOR,
    fb_info->fix.accel = FB_ACCEL_NONE;
    fb_info->fix.line_length = vmode->hactive * 2;
    fb_info->fix.smem_start = fb_phys;
    fb_info->fix.smem_len = fb_size;
 
    fb_info->var.grayscale = 0; // 彩色
    fb_info->var.nonstd = 0; // 标准像素格式
    fb_info->var.activate = FB_ACTIVATE_NOW;
    fb_info->var.accel_flags = FB_ACCEL_NONE;
    fb_info->var.bits_per_pixel = 16; // 像素深度(bit 位)
 
    fb_info->var.xres = fb_info->var.xres_virtual = vmode->hactive;
    fb_info->var.yres = fb_info->var.yres_virtual = vmode->vactive;
    fb_info->var.xoffset = fb_info->var.yoffset = 0;
 
    fb_info->var.red.offset = 11;
    fb_info->var.red.length = 5;
    fb_info->var.green.offset = 5;
    fb_info->var.green.length = 6;
    fb_info->var.blue.offset = 0;
    fb_info->var.blue.length = 5;
    fb_info->var.transp.offset = 0;
    fb_info->var.transp.length = 0;
 
    fb_videomode_from_videomode(vmode, &mode);
    fb_videomode_to_var(&fb_info->var, &mode);
 
    return 0;
}
 
static int vdmafb_init_vdma(struct xilinx_vdmafb_dev *fbdev)
{
    struct device *dev = &fbdev->pdev->dev;
    struct fb_info *info = fbdev->info;
    struct dma_interleaved_template *dma_template = fbdev->dma_template;
    struct dma_async_tx_descriptor *tx_desc;
    struct xilinx_vdma_config vdma_config = {0};
    size_t sig_size;
 
    /* 申请 VDMA 通道 */
    fbdev->vdma = of_dma_request_slave_channel(dev->of_node, "vdma0");
    if (IS_ERR(fbdev->vdma)) {
        dev_err(dev, "Failed to request vdma channel
");
        return PTR_ERR(fbdev->vdma);
    }
    dev_err(dev, "Panel prepare vdma  channel: 
");
    /* 终止 VDMA 通道数据传输 */
    dmaengine_terminate_all(fbdev->vdma);
    /* 初始化 VDMA 通道 */
    dma_template->dir = DMA_MEM_TO_DEV;
    dma_template->numf = info->var.yres;
    dma_template->sgl[0].size = info->fix.line_length;
    dma_template->frame_size = 1;
    dma_template->sgl[0].icg = 0;
    dma_template->src_start = info->fix.smem_start; 
    dma_template->src_sgl = 1;
    dma_template->src_inc = 1;
    dma_template->dst_inc = 0;
    dma_template->dst_sgl = 0;
    tx_desc = dmaengine_prep_interleaved_dma(fbdev->vdma, dma_template,
    DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
 
    if (!tx_desc) {
        dev_err(dev, "Failed to prepare DMA descriptor
");
        dma_release_channel(fbdev->vdma);
        return -1;
    }
 
    vdma_config.park = 1;
    xilinx_vdma_channel_set_config(fbdev->vdma, &vdma_config);
 
    /* 启动 VDMA 通道数据传输 */
    dmaengine_submit(tx_desc);
    dma_async_issue_pending(fbdev->vdma);
    return 0;
}
 
/* --------------------------- VTC控制函数(基于xlnx_bridge) --------------------------- */
 
static int xilinx_vtc_init(struct xilinx_vdmafb_dev *dpi)
{
    struct device_node *vtc_node;
    struct device *dev = &dpi->pdev->dev;
    int ret = 0;
 
    // 1. 从设备树获取VTC节点(xlnx,bridge属性)
    vtc_node = of_parse_phandle(dev->of_node, "xlnx,bridge", 0);
    if (!vtc_node) {
        dev_err(dev, "VTC node not found in DT
");
        return -ENODEV;
    }
 
    // 2. 获取VTC桥接器实例(支持probe defer)
    dpi->vtc_bridge = of_xlnx_bridge_get(vtc_node);
    of_node_put(vtc_node);
    if (IS_ERR(dpi->vtc_bridge)) {
        ret = PTR_ERR(dpi->vtc_bridge);
        if (ret != -EPROBE_DEFER)
            dev_err(dev, "VTC bridge get failed: %d
", ret);
        return ret;
    }
 
    dev_info(dev, "VTC bridge init success
");
    return 0;
}
 
static int vdmafb_init_vtc(struct xilinx_vdmafb_dev *fbdev,
struct videomode *vmode)
{
    struct device_node *node;
    struct device *dev = &fbdev->pdev->dev;
    int ret;
 
     // 3. 初始化VTC桥接器
    ret = xilinx_vtc_init(fbdev);  //提前获取用户配置的vtc
    if (ret) {
        if (ret != -EPROBE_DEFER)
            dev_err(dev, "VTC init failed: %d
", ret);
        return ret;
    }
 
    xlnx_bridge_disable(fbdev->vtc_bridge);
    // 1. 配置VTC时序(Xilinx标准接口)
    xlnx_bridge_set_timing(fbdev->vtc_bridge, vmode);
    // 2. 启用VTC
    xlnx_bridge_enable(fbdev->vtc_bridge);
 
    dev_info(dev, "VTC timing set:clk=%dMHz
",vmode->pixelclock / 1000000);
    return 0;
}
 
static int vdmafb_probe(struct platform_device *pdev)
{
    struct xilinx_vdmafb_dev *fbdev;
    struct fb_info *info;
    struct videomode vmode;
    struct pwm_device *pwm;
    int ret;
 
     dev_err(&pdev->dev, "init to allocate memory
");
    /* 实例化一个 fb_info 结构体对象 */
    info = framebuffer_alloc(sizeof(struct xilinx_vdmafb_dev), &pdev->dev);
    if (!info) {
        dev_err(&pdev->dev, "Failed to allocate memory
");
        return -ENOMEM;
    }
 
    fbdev = info->par;
    fbdev->info = info;
    fbdev->pdev = pdev;
 
    /* 获取 LCD 所需的像素时钟 */
    fbdev->pclk = devm_clk_get(&pdev->dev, "lcd_pclk");
    if (IS_ERR(fbdev->pclk)) {
        dev_err(&pdev->dev, "Failed to get pixel clock
");
        ret = PTR_ERR(fbdev->pclk);
        goto label1;
    }
    clk_disable_unprepare(fbdev->pclk); // 先禁止时钟输出
 
    /* 初始化 info 变量 */
    ret = vdmafb_init_fbinfo(fbdev, &vmode);
    if (ret)
        goto label1;
 
    ret = fb_alloc_cmap(&info->cmap, 256, 0);
    if (ret < 0) {
        dev_err(&pdev->dev, "Failed to allocate color map
");
        goto label2;
    }
 
    fbdev->dma_template = devm_kzalloc(&pdev->dev,
    sizeof(struct dma_interleaved_template) +
    sizeof(struct data_chunk),
    GFP_KERNEL);
    if (!fbdev->dma_template)
        return -ENOMEM;
 
    info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16, GFP_KERNEL);
    if (!info->pseudo_palette) {
        ret = -ENOMEM;
        goto label3;
    }
 
    /* 设置 LCD 像素时钟、使能时钟 */
    info->var.pixclock =24000000ULL / ((u32)vmode.pixelclock/10000);
    clk_set_rate(fbdev->pclk, vmode.pixelclock);
    clk_prepare_enable(fbdev->pclk);
    msleep(5); 
 
    /* 初始化 LCD 时序控制器 vtc */
    ret = vdmafb_init_vtc(fbdev, &vmode);
    if (ret)
        goto label4;
 
    st7701_spi_probe(fbdev);
    ret = st7701_prepare(fbdev);
    if (ret) {
        dev_err(&pdev->dev, "Panel prepare failed: %d
", ret);
    }
    st7701_enable(fbdev);
 
    /* 初始化 LCD VDMA */
    ret = vdmafb_init_vdma(fbdev);
    if (ret)
        goto label6;
 
    /* 注册 FrameBuffer 设备 */
    ret = register_framebuffer(info);
    if (ret < 0) {
        dev_err(&pdev->dev,"Failed to register framebuffer device
");
        goto label6;
    }
 
    platform_set_drvdata(pdev, fbdev);
    return 0;
 
 
label6:
    dmaengine_terminate_all(fbdev->vdma); // 终止 VDMA 通道所有数据传输
    dma_release_channel(fbdev->vdma); // 释放 VDMA 通道
label5:
    xlnx_bridge_disable(fbdev->vtc_bridge); // 禁止 vtc 时序控制器
 
label4:
    clk_disable_unprepare(fbdev->pclk); // 禁止时钟输出
 
label3:
    fb_dealloc_cmap(&info->cmap); 
label2:
    dma_free_wc(&pdev->dev, info->screen_size,
    info->screen_base, info->fix.smem_start);
 
label1:
    framebuffer_release(info); 
    return ret;
}
 
static void vdmafb_remove(struct platform_device *pdev)
{
    struct xilinx_vdmafb_dev *fbdev = platform_get_drvdata(pdev);
    struct fb_info *info = fbdev->info;
 
    unregister_framebuffer(info);
    dmaengine_terminate_all(fbdev->vdma);
    dma_release_channel(fbdev->vdma);
    xlnx_bridge_disable(fbdev->vtc_bridge);
    clk_disable_unprepare(fbdev->pclk);
    fb_dealloc_cmap(&info->cmap);
 
    dma_free_wc(&pdev->dev, info->screen_size,info->screen_base, info->fix.smem_start);
    framebuffer_release(info);
}
static void vdmafb_shutdown(struct platform_device *pdev)
{
    struct xilinx_vdmafb_dev *fbdev = platform_get_drvdata(pdev);
    xlnx_bridge_disable(fbdev->vtc_bridge);
    clk_disable_unprepare(fbdev->pclk);
}
 
static const struct of_device_id vdmafb_of_match_table[] = {
    { .compatible = "st7701s,lcd", },
    { /* end of table */ },
};
MODULE_DEVICE_TABLE(of, vdmafb_of_match_table);
 
static struct platform_driver xilinx_vdmafb_driver = {
    .probe = vdmafb_probe,
    .remove = vdmafb_remove,
    .shutdown = vdmafb_shutdown,
    .driver = {
        .name = "st7701s,lcd",
        .of_match_table = vdmafb_of_match_table,
    },
};
 
module_platform_driver(xilinx_vdmafb_driver);
 
MODULE_DESCRIPTION("Framebuffer driver based on Xilinx VDMA IP Core.");
MODULE_AUTHOR("dttt.nt");
MODULE_LICENSE("GPL v2");

将以上两部分代码放置到同一个文件,并放置到/drivers/gpu/drm/xlnx/,并修改该路径makefile:

$a obj-y      += st7701s_dma_lcd.o编译即可

六:设备树配置和内核宏定义



 
&clk_wiz_0 {
    compatible = "xlnx,clocking-wizard";
    xlnx,nr-outputs = <2>;
};
 
//内核运行的时候,会优先注册号vtc等驱动。fb驱动只需要读取并配置vtc brid时序即可
&v_tc_0 {
	compatible = "xlnx,bridge-v-tc-6.1";
	xlnx,pixels-per-clock = <1>;
};
 
 
&amba_pl {
	xlnx_vdmafb_lcd: mys_7701@0 {
		status = "okay";
		compatible = "st7701s,lcd";
		xlnx,bridge = <&v_tc_0>; // 绑定VTC时序控制器
	
		clocks = <&clk_wiz_0 0>;
		clock-names = "lcd_pclk";
 
		dmas = <&axi_vdma_0 0>; // 绑定VDMA通道0
		dma-names = "vdma0";
 
		backlight-gpios = <&gpio0 57 1>; 
 
		sck-gpios = <&gpio0 61 GPIO_ACTIVE_HIGH>;  
		mosi-gpios = <&gpio0 60 GPIO_ACTIVE_HIGH>; 
		cs-gpios = <&gpio0 59 GPIO_ACTIVE_HIGH>;
 
		reset-gpios = <&gpio0 58 GPIO_ACTIVE_HIGH>;
		spi-max-frequency = <33000000>;
 
		/* 参考正点原子写法 */
		display-timings {
			native-mode = <&st7701_timing>;
			st7701_timing: timing0 {
				clock-frequency = <24000000>; 
				hactive = <480>;
				vactive = <800>;
				hfront-porch = <20>;
				hsync-len = <10>;
				hback-porch = <24>;
				vfront-porch = <18>;
				vsync-len = <4>;
				vback-porch = <24>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
				pixelclk-active = <0>;
			};
		};
	};
};

因为博主在测试内核开宏定义的时候,开启相关宏,内核编译依旧报找不到cfb_fillrect等三个接口

因此把下面宏全部开启就可以解决了。当然有些宏肯定可以不开的,这里就不深究了



CONFIG_HAS_IOMEM=y
CONFIG_VIDEO=y
CONFIG_FB=y
CONFIG_FB_OPENCORES=y
CONFIG_FB_CORE=y
CONFIG_FB_NOTIFY=y
 
CONFIG_FB_DEVICE=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_IMAGEBLIT=y
 
CONFIG_FB_SYSMEM_FOPS=y
CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_DMAMEM_HELPERS=y
CONFIG_FB_DMAMEM_HELPERS_DEFERRED=y
CONFIG_FB_IOMEM_FOPS=y
CONFIG_FB_IOMEM_HELPERS=y
CONFIG_FB_SYSMEM_HELPERS=y
CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
CONFIG_VIDEOMODE_HELPERS=y
 
#
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_DUMMY_CONSOLE_COLUMNS=80
CONFIG_DUMMY_CONSOLE_ROWS=30
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_CMA_ALLOW_ZONE_MOVEMENT=y
CONFIG_FB_CMA=y
CONFIG_FB_MMAP=y
 
#CONFIG_DRM=y
CONFIG_DRM_KMS_HELPER=y
CONFIG_DRM_ATOMIC_HELPER=y
CONFIG_DRM_GEM_CMA_HELPER=y 
CONFIG_DRM_FBDEV_EMULATION=y 
 
CONFIG_COMMON_CLK_XLNX_CLKWZRD=y
CONFIG_DRM_XLNX=y
CONFIG_DRM_XLNX_BRIDGE_VTC=y
CONFIG_DRM_XLNX_VTC=y  
CONFIG_DRM_XLNX_AXI_VDMA=y  
CONFIG_DRM_XLNX_PANEL=y  
CONFIG_DRM_XLNX_BRIDGE=y
 
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_DRM_ATOMIC=y
CONFIG_CLK_WIZARD=y

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...