uboot drm框架

uboot drm框架

drm概念

drm显示通路

在这里插入图片描述

CRTC: 显示控制器, 在 rockchip 平台是 SOC 内部 VOP(部分文档也称为 LCDC)模块的抽象;
Plane: 图层, 在 rockchip 平台是 SOC 内部 VOP(LCDC)模块 win 图层的抽象;
Encoder: 输出转换器, 指 RGB、 LVDS、 DSI、 eDP、 HDMI、 CVBS、 VGA 等显示接口;
Connector: 连接器, 指 encoder 和 panel 之间交互的接口部分;
Bridge: 桥接设备, 一般用于注册 encoder 后面另外再接的转换芯片, 如 DSI2HDMI 转换芯片。
Panel: 泛指屏, 各种 LCD、 HDMI 等显示设备的抽象;
GEM: buffer 管理和分配,类似 android 下的 ion。

其中bridge部分,当平台无对应 显示接口使用转换芯片

crtc控制器

Z:\RV1109\u-boot\drivers\video\drm\rockchip_crtc.c

//注册vop驱动
U_BOOT_DRIVER(rockchip_vop) = {
	.name	= "rockchip-vop",
	.id	= UCLASS_VIDEO_CRTC,
	.of_match = rockchip_vop_ids,
	.bind	= rockchip_vop_bind,
	.probe	= rockchip_vop_probe,
};
//通过of_match 匹配设备rockchip_vop_ids,1109和1126是一样通用的
    .compatible = "rockchip,rv1126-vop",
    .data = (ulong)&rv1126_vop_data,
//rv1126_vop 这个是1126平台的vop驱动设置了vop的一些参数寄存器等等,rockchip_vop_funcs是crtc vop的初始化之类的func
static const struct rockchip_crtc rv1126_vop_data = {
	.funcs = &rockchip_vop_funcs,
	.data = &rv1126_vop,
};

const struct rockchip_crtc_funcs rockchip_vop_funcs = {
	.preinit = rockchip_vop_preinit,
	.init = rockchip_vop_init,
	.set_plane = rockchip_vop_set_plane,
	.prepare = rockchip_vop_prepare,
	.enable = rockchip_vop_enable,
	.disable = rockchip_vop_disable,
	.fixup_dts = rockchip_vop_fixup_dts,
	.send_mcu_cmd = rockchip_vop_send_mcu_cmd,
};

panel

panel部分的控制流程

Z:\RV1109\u-boot\drivers\video\drm\rockchip_panel.c

panel的控制结构体如电源脚
 struct rockchip_panel_priv {
	bool prepared;
	bool enabled;
	struct udevice *power_supply;
	struct udevice *backlight;
	struct gpio_desc enable_gpio;
	struct gpio_desc reset_gpio;

	int cmd_type;
	struct gpio_desc spi_sdi_gpio;
	struct gpio_desc spi_scl_gpio;
	struct gpio_desc spi_cs_gpio;
};  
panel的参数结构体
 struct rockchip_panel_plat {
	bool power_invert;
	u32 bus_format;
	unsigned int bpc;

	struct {
		unsigned int prepare;
		unsigned int unprepare;
		unsigned int enable;
		unsigned int disable;
		unsigned int reset;
		unsigned int init;
	} delay;

	struct rockchip_panel_cmds *on_cmds;
	struct rockchip_panel_cmds *off_cmds;
};
panel的配置及连接状态
struct rockchip_panel {
	struct udevice *dev;
	u32 bus_format;
	unsigned int bpc;
	const struct rockchip_panel_funcs *funcs;
	const void *data;

	struct display_state *state;
};
//display 的结构体包含连接信息及状态 log信息
struct display_state {
	struct list_head head;

	const void *blob;
	ofnode node;

	struct crtc_state crtc_state;
	struct connector_state conn_state;
	struct panel_state panel_state;

	char ulogo_name[30];
	char klogo_name[30];

	struct logo_info logo;
	int logo_mode;
	int charge_logo_mode;
	void *mem_base;
	int mem_size;

	int enable;
	int is_init;
	int is_enable;
}

probe流程
    reset、电源脚申明
    gpio_request_by_name(dev, "enable-gpios", 0,
				   &priv->enable_gpio, GPIOD_IS_OUT);
	gpio_request_by_name(dev, "reset-gpios", 0,
				   &priv->reset_gpio, GPIOD_IS_OUT);
	uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
					   "backlight", &priv->backlight);
	uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
					   "power-supply", &priv->power_supply);
	//读取配置发送屏参的方式,有spi、mcu和默认的屏
	dev_read_string_index(dev, "rockchip,cmd-type", 0, &cmd_type);
	//注册panel_function,用于屏的初始化 enable之类
    panel->funcs = &rockchip_panel_funcs;

static const struct rockchip_panel_funcs rockchip_panel_funcs = {
	.init = panel_simple_init,
	.prepare = panel_simple_prepare,
	.unprepare = panel_simple_unprepare,
	.enable = panel_simple_enable,
	.disable = panel_simple_disable,
	.getid = panel_simple_getid,
};
//把panel的总线格式赋值到连接接口的值
static void panel_simple_init(struct rockchip_panel *panel)
{
	struct display_state *state = panel->state;
	struct connector_state *conn_state = &state->conn_state;

	conn_state->bus_format = panel->bus_format;
}
//panel上电准备
panel_simple_prepare
 //panel下电准备
 panel_simple_unprepare
 //enable  panel
 panel_simple_enable
 //disable panel
 panel_simple_disable
 //get  panel screen id,兼容多个屏,在mipi_dsi_get_screen_id做屏的兼容
 panel_simple_getid
    return  mipi_dsi_get_screen_id

connect

这部分是encoder 连接到panel,这里讲解平台用到mipi

//mipi 
U_BOOT_DRIVER(dw_mipi_dsi) = {
	.name = "dw_mipi_dsi",
	.id = UCLASS_DISPLAY,
	.of_match = dw_mipi_dsi_ids,
	.probe = dw_mipi_dsi_probe,
	.bind = dw_mipi_dsi_bind,
	.priv_auto_alloc_size = sizeof(struct dw_mipi_dsi),
	.per_child_platdata_auto_alloc_size = sizeof(struct mipi_dsi_device),
	.platdata_auto_alloc_size = sizeof(struct mipi_dsi_host),
	.child_post_bind = dw_mipi_dsi_child_post_bind,
	.child_pre_probe = dw_mipi_dsi_child_pre_probe,
};
//通过of_match 匹配平台的dw_mipi_dsi_ids,获取到rockchip_connector的data和func,fun是connect模块的功能函数,通过fun与对应的pannel连接
    .compatible = "rockchip,rv1126-mipi-dsi",
    .data = (ulong)&rv1126_mipi_dsi_driver_data,

static const struct rockchip_connector rv1126_mipi_dsi_driver_data = {
	 .funcs = &dw_mipi_dsi_connector_funcs,
	 .data = &rv1126_mipi_dsi_plat_data,
};

static const struct rockchip_connector_funcs dw_mipi_dsi_connector_funcs = {
	.init = dw_mipi_dsi_connector_init,
	.prepare = dw_mipi_dsi_connector_prepare,
	.unprepare = dw_mipi_dsi_connector_unprepare,
	.enable = dw_mipi_dsi_connector_enable,
	.disable = dw_mipi_dsi_connector_disable,
};

display子系统

display子系统流程

//Device information used by the video uclass
struct video_priv {
	/* Things set up by the driver: */
	ushort xsize;
	ushort ysize;
	ushort rot;
	enum video_log2_bpp bpix;
	const char *vidconsole_drv_name;
	int font_size;

	/*
	 * Things that are private to the uclass: don't use these in the
	 * driver
	 */
	void *fb;
	int fb_size;
	int line_length;
	int colour_fg;
	int colour_bg;
	bool flush_dcache;
	ushort *cmap;
};
//
struct video_uc_platdata {
	uint align;
	uint size;
	ulong base;
};
//display crtc控制器
struct rockchip_crtc {
	const struct rockchip_crtc_funcs *funcs;
	const void *data;
	struct drm_display_mode active_mode;
	bool hdmi_hpd : 1;
	bool active : 1;
};
//display的连接器
struct rockchip_connector {
	const struct rockchip_connector_funcs *funcs;

	const void *data;
};
//display 桥接状态
struct rockchip_bridge {
	struct udevice *dev;
	const struct rockchip_bridge_funcs *funcs;

	struct display_state *state;
};
//display  phy接口
struct rockchip_phy {
	struct udevice *dev;
	const struct rockchip_phy_funcs *funcs;
	const void *data;
	int soc_type;
};
//display  phy数据
struct public_phy_data {
	const struct rockchip_phy *phy_drv;
	int phy_node;
	int public_phy_type;
	bool phy_init;
};
//uboot的display driver
U_BOOT_DRIVER(rockchip_display) = {
	.name	= "rockchip_display",
	.id	= UCLASS_VIDEO,
	.of_match = rockchip_display_ids,
	.bind	= rockchip_display_bind,
	.probe	= rockchip_display_probe,
};
rockchip_display_probe
    //寻找dts的route节点,route节点下有很多子节点,子节点的接口有dsi、rgb、
   route_node = dev_read_subnode(dev, "route");
	//然后读取子节点的配置参数

ofnode_for_each_subnode(node, route_node) {
		if (!ofnode_is_available(node))
			continue;
    	//通过connct参数中寻找该节点,再找到port父节点接口
		phandle = ofnode_read_u32_default(node, "connect", -1);
		if (phandle < 0) {
			printf("Warn: can't find connect node's handle\n");
			continue;
		}
    	//ep_node 是connect参数 实际申明的节点
		ep_node = of_find_node_by_phandle(phandle);
		if (!ofnode_valid(np_to_ofnode(ep_node))) {
			printf("Warn: can't find endpoint node from phandle\n");
			continue;
		}
		port_node = of_get_parent(ep_node);
		if (!ofnode_valid(np_to_ofnode(port_node))) {
			printf("Warn: can't find port node from phandle\n");
			continue;
		}

		port_parent_node = of_get_parent(port_node);
		if (!ofnode_valid(np_to_ofnode(port_parent_node))) {
			printf("Warn: can't find port parent node from phandle\n");
			continue;
		}

		is_ports_node = strstr(port_parent_node->full_name, "ports") ? 1 : 0;
		if (is_ports_node) {
			vop_node = of_get_parent(port_parent_node);
			if (!ofnode_valid(np_to_ofnode(vop_node))) {
				printf("Warn: can't find crtc node from phandle\n");
				continue;
			}
		} else {
			vop_node = port_parent_node;
		}
		//找到display crtc控制器
		ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC,
						  np_to_ofnode(vop_node),
						  &crtc_dev);
		if (ret) {
			printf("Warn: can't find crtc driver %d\n", ret);
			continue;
		}
		crtc = (struct rockchip_crtc *)dev_get_driver_data(crtc_dev);
		//从ep_node的remote_point参数中得到申明节点的位置,在得到生成该节点的displayport 例如dsi 加入到display port链表中
		conn_dev = rockchip_of_find_connector(np_to_ofnode(ep_node));
		if (!conn_dev) {
			printf("Warn: can't find connect driver\n");
			continue;
		}

		conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev);
		//得到dsi port控制器的phy接口,dsi用的是mipi_dphy
		phy = rockchip_of_find_phy(conn_dev);
		//通过dsi节点来得到 bridge 节点  vop  vop-dsi
		bridge = rockchip_of_find_bridge(conn_dev);
		if (bridge)
			panel = rockchip_of_find_panel(bridge->dev);
		else
			panel = rockchip_of_find_panel(conn_dev);

		s = malloc(sizeof(*s));
		if (!s)
			continue;

		memset(s, 0, sizeof(*s));
		//从dts 文件中读取logo,mode的参数
		INIT_LIST_HEAD(&s->head);
		ret = ofnode_read_string_index(node, "logo,mode", 0, &name);
		if (!strcmp(name, "fullscreen"))
			s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
		else
			s->logo_mode = ROCKCHIP_DISPLAY_CENTER;
		ret = ofnode_read_string_index(node, "charge_logo,mode", 0, &name);
		if (!strcmp(name, "fullscreen"))
			s->charge_logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
		else
			s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER;
		//填充rockchip_state的参数 
		s->blob = blob;
		s->panel_state.panel = panel;
		s->conn_state.node = conn_dev->node;
		s->conn_state.dev = conn_dev;
		s->conn_state.connector = conn;
		s->conn_state.phy = phy;
		s->conn_state.bridge = bridge;
		s->conn_state.overscan.left_margin = 100;
		s->conn_state.overscan.right_margin = 100;
		s->conn_state.overscan.top_margin = 100;
		s->conn_state.overscan.bottom_margin = 100;
		s->crtc_state.node = np_to_ofnode(vop_node);
		s->crtc_state.dev = crtc_dev;
		s->crtc_state.crtc = crtc;
		s->crtc_state.crtc_id = get_crtc_id(np_to_ofnode(ep_node));
		s->node = node;

		if (bridge)
			bridge->state = s;

		if (panel)
			panel->state = s;

		get_crtc_mcu_mode(&s->crtc_state);

		ret = ofnode_read_u32_default(s->crtc_state.node,
					      "rockchip,dual-channel-swap", 0);
		s->crtc_state.dual_channel_swap = ret;
		if (connector_panel_init(s)) {
			printf("Warn: Failed to init panel drivers\n");
			free(s);
			continue;
		}

		if (connector_phy_init(s, data)) {
			printf("Warn: Failed to init phy drivers\n");
			free(s);
			continue;
		}
		list_add_tail(&s->head, &rockchip_display_list);
	}
//驱动程序中会遍历route节点下的子节点的connect参数,然后再通过of_find_node_by_phandle函数得到ep_node(vop_out_dsi)的定义点 通过两次调用of_get_parent函数得到该节点的父节点vop,再把vop的节点加入到crtc控制节点的链表中,通过rockchip_of_find_connector函数获取ep_node(vop_out_dsi)的节点下的remote-endpoint的参数,然后通过ofnode_get_by_phandle函数得到remote-endpoint参数(dsi_in_vop)的定义节点,然后通过三次调用ofnode_get_parent函数得到(dsi_in_vop)的父节点dsi display_port节点,加入到display_port链表中。通过调用rockchip_of_find_phy函数得到 dsi display_port节点中的phy节点的参数并加入到链表中调用rockchip_of_find_bridge函数遍历 dsi节点下的 ports节点的reg和port节点参数,再遍历port节点下的remote-endpoint的参数,调用of_get_parent三次是否可以得到父节点如果可以加入bridge链表,然后通过bridge得到panel.
//总结来说有bridge  crtc  --  encoder -- bridge --connect -- panel
//没有bridge  crtc  --  encoder --connect -- panel
	display_subsystem: display-subsystem {
		compatible = "rockchip,display-subsystem";
		ports = <&vop_out>;
		status = "disabled";
		logo-memory-region = <&drm_logo>;

		route {
			route_dsi: route-dsi {
				status = "disabled";
				logo,uboot_1024X600 = "logo_1024X600.bmp";
				logo,kernel_1024X600 = "logo_kernel_1024X600.bmp";
				logo,uboot_480X854 = "logo_480X854.bmp";
				logo,kernel_480X854 = "logo_kernel_480X854.bmp";
				logo,uboot_480X800 = "logo_480X800.bmp";
				logo,kernel_480X800 = "logo_kernel_480X800.bmp";
				logo,uboot_800X1280 = "logo_800X1280.bmp";
				logo,kernel_800X1280 = "logo_kernel_800X1280.bmp";
				logo,mode = "center";
				charge_logo,mode = "center";
				connect = <&vop_out_dsi>;
			};

			route_rgb: route-rgb {
				status = "disabled";
				logo,uboot = "logo.bmp";
				logo,kernel = "logo_kernel.bmp";
				logo,mode = "center";
				charge_logo,mode = "center";
				connect = <&vop_out_rgb>;
			};
		};
	};

	vop: vop@ffb00000 {
		compatible = "rockchip,rv1126-vop";
		reg = <0xffb00000 0x200>, <0xffb00a00 0x400>;
		reg-names = "regs", "gamma_lut";
		rockchip,grf = <&grf>;
		interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&cru ACLK_VOP>, <&cru DCLK_VOP>, <&cru HCLK_VOP>;
		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
		iommus = <&vop_mmu>;
		power-domains = <&power RV1126_PD_VO>;
		status = "disabled";

		vop_out: port {
			#address-cells = <1>;
			#size-cells = <0>;

			vop_out_rgb: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&rgb_in_vop>;
			};

			vop_out_dsi: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&dsi_in_vop>;
			};
		};
	};

	dsi: dsi@ffb30000 {
		compatible = "rockchip,rv1126-mipi-dsi";
		reg = <0xffb30000 0x500>;
		interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&cru PCLK_DSIHOST>, <&mipi_dphy>;
		clock-names = "pclk", "hs_clk";
		resets = <&cru SRST_DSIHOST_P>;
		reset-names = "apb";
		phys = <&mipi_dphy>;
		phy-names = "mipi_dphy";
		rockchip,grf = <&grf>;
		#address-cells = <1>;
		#size-cells = <0>;
		power-domains = <&power RV1126_PD_VO>;
		status = "disabled";

		ports {
			port {
				dsi_in_vop: endpoint {
					remote-endpoint = <&vop_out_dsi>;
				};
			};
		};
	};

display_init

分别获取connect、panel、crtc的结构体信息,然后初始化

//判断通路以及控制器是否初始化过
	if (state->is_init)
		return 0;

	if (!conn_funcs || !crtc_funcs) {
		printf("failed to find connector or crtc functions\n");
		return -ENXIO;
	}

	if (crtc_state->crtc->active &&
	    memcmp(&crtc_state->crtc->active_mode, &conn_state->screen[lcd_index].mode,
		   sizeof(struct drm_display_mode))) {
		printf("%s has been used for output type: %d, mode: %dx%dp%d\n",
			crtc_state->dev->name,
			crtc_state->crtc->active_mode.type,
			crtc_state->crtc->active_mode.hdisplay,
			crtc_state->crtc->active_mode.vdisplay,
			crtc_state->crtc->active_mode.vrefresh);
		return -ENODEV;
	}
//设置crtc控制器最大分辨率 	
if (crtc_funcs->preinit) {
		ret = crtc_funcs->preinit(state);
		if (ret)
			return ret;
	}
//panel初始化,设置bus_format -> 100e
if (panel_state->panel)
    rockchip_panel_init(panel_state->panel);
//connect初始化
if (conn_funcs->init) {
    ret = conn_funcs->init(state);
    if (ret)
        goto deinit;
}
//crtc和conect的prepare
if (crtc_funcs->prepare)
    crtc_funcs->prepare(state);

if (conn_funcs->prepare)
    conn_funcs->prepare(state, -1);
//panel的类型获取比如使用什么屏
if (panel_state->panel)
    display_get_lcd_index(panel_state->panel);
//panel的timing 和其他参数
if (panel_state->panel) {
    ret = display_get_timing(state);
    mode = &conn_state->screen[lcd_index].mode;
    if (!ret)
        conn_state->bpc = panel_state->panel->bpc;
    #if defined(CONFIG_I2C_EDID)
    if (ret < 0 && conn_funcs->get_edid) {
        rockchip_panel_prepare(panel_state->panel);

        ret = conn_funcs->get_edid(state);
        if (!ret) {
            ret = edid_get_drm_mode((void *)&conn_state->edid,
                                    sizeof(conn_state->edid),
                                    mode, &bpc);
            if (!ret) {
                conn_state->bpc = bpc;
                edid_print_info((void *)&conn_state->edid);
            }
        }
    }
    #endif
} else if (conn_state->bridge) {
    ret = video_bridge_read_edid(conn_state->bridge->dev,
                                 conn_state->edid, EDID_SIZE);
    if (ret > 0) {
        #if defined(CONFIG_I2C_EDID)
        ret = edid_get_drm_mode(conn_state->edid, ret, mode,
                                &bpc);
        if (!ret) {
            conn_state->bpc = bpc;
            edid_print_info((void *)&conn_state->edid);
        }
        #endif
    } else {
        ret = video_bridge_get_timing(conn_state->bridge->dev);
    }
} else if (conn_funcs->get_timing) {
    ret = conn_funcs->get_timing(state);
} else if (conn_funcs->get_edid) {
    ret = conn_funcs->get_edid(state);
    #if defined(CONFIG_I2C_EDID)
    if (!ret) {
			ret = edid_get_drm_mode((void *)&conn_state->edid,
						sizeof(conn_state->edid), mode,
						&bpc);
			if (!ret) {
				conn_state->bpc = bpc;
				edid_print_info((void *)&conn_state->edid);
			}
		}
#endif
	}


//获取display的时序和前后栏参数
static int display_get_timing(struct display_state *state)
{
	struct connector_state *conn_state = &state->conn_state;
	//struct drm_display_mode *mode = &conn_state->mode;
	//struct mipi_screen *mscreen = conn_state->screen;
	const struct drm_display_mode *m;
	struct panel_state *panel_state = &state->panel_state;
	const struct rockchip_panel *panel = panel_state->panel;

	if (dev_of_valid(panel->dev) &&
	    !display_get_timing_from_dts(panel_state, conn_state)) {
		printf("Using display timing dts %d\n", conn_state->screen[lcd_index].mode.hdisplay);
		return 0;
	}

	if (panel->data) {
		m = (const struct drm_display_mode *)panel->data;
		memcpy(&conn_state->screen[lcd_index].mode, m, sizeof(*m));
		printf("Using display timing from compatible panel driver\n");
		return 0;
	}

	return -ENODEV;
}
//具体参数从dts中获取,首先获取到mipilcd参数节点,再得到lcd的子节点有几个,然后遍历子节点把dts的参数赋值到具体的panel上
static int display_get_timing_from_dts(struct panel_state *panel_state,
				       struct connector_state *conn_state)
{
	struct rockchip_panel *panel = panel_state->panel;
	int phandle;
	int hactive, vactive, pixelclock;
	int hfront_porch, hback_porch, hsync_len;
	int vfront_porch, vback_porch, vsync_len;
	int val, flags = 0;
	ofnode timing, native_mode;
	const char *lcd_name;

	int len = 0;
	int index = -1;
	int lcd_phandle;
	ofnode lcd_list;
	ofnode lcd_node;

	struct mipi_screen *mscreen;
	int i = 0, j = 0;

	lcd_phandle = dev_read_u32_default(panel->dev, "mipilcd", -1);
	lcd_list = np_to_ofnode(of_find_node_by_phandle(lcd_phandle));
	if (!ofnode_valid(lcd_list)) {
		printf("failed to get display timings from DT\n");
		return -ENXIO;
	}

	ofnode_for_each_subnode(lcd_node, lcd_list) {
		lcd_name = ofnode_get_property(lcd_node, "name", &len);
		if(0 == strncmp(lcd_name, "lcd", 3)) {
			index = atoi((lcd_name+3));
			if(index == 0) {
				continue;
			}
			i++;
		}
	}

	mscreen = calloc(i+1, sizeof(struct mipi_screen));
	if (mscreen == NULL) {
		printf("failed to alloc mipi_screen memory\n");
		return -EFAULT;
	}

	ofnode_for_each_subnode(lcd_node, lcd_list) {
		lcd_name = ofnode_get_property(lcd_node, "name", &len);
		if(0 == strncmp(lcd_name, "lcd", 3)) {
			index = atoi((lcd_name+3));
			if(index == 0 || index > i) {
				continue;
			}
			j = index;
			timing = ofnode_find_subnode(lcd_node, "display-timings");
			if (!ofnode_valid(timing))
				return -ENODEV;

			native_mode = ofnode_find_subnode(timing, "timing");
			if (!ofnode_valid(native_mode)) {
				phandle = ofnode_read_u32_default(timing, "native-mode", -1);
				native_mode = np_to_ofnode(of_find_node_by_phandle(phandle));
				if (!ofnode_valid(native_mode)) {
					printf("failed to get display timings from DT\n");
					return -ENXIO;
				}
			}
			FDT_GET_INT(hactive, "hactive");
			FDT_GET_INT(vactive, "vactive");
			FDT_GET_INT(pixelclock, "clock-frequency");
			FDT_GET_INT(hsync_len, "hsync-len");
			FDT_GET_INT(hfront_porch, "hfront-porch");
			FDT_GET_INT(hback_porch, "hback-porch");
			FDT_GET_INT(vsync_len, "vsync-len");
			FDT_GET_INT(vfront_porch, "vfront-porch");
			FDT_GET_INT(vback_porch, "vback-porch");
			FDT_GET_INT(val, "hsync-active");
			flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
			FDT_GET_INT(val, "vsync-active");
			flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
			FDT_GET_INT(val, "pixelclk-active");
			flags |= val ? DRM_MODE_FLAG_PPIXDATA : 0;

			FDT_GET_INT_DEFAULT(val, "screen-rotate", 0);
			if (val == DRM_MODE_FLAG_XMIRROR) {
				flags |= DRM_MODE_FLAG_XMIRROR;
			} else if (val == DRM_MODE_FLAG_YMIRROR) {
				flags |= DRM_MODE_FLAG_YMIRROR;
			} else if (val == DRM_MODE_FLAG_XYMIRROR) {
				flags |= DRM_MODE_FLAG_XMIRROR;
				flags |= DRM_MODE_FLAG_YMIRROR;
			}
			mscreen[j].mode.hdisplay = hactive;
			mscreen[j].mode.hsync_start = mscreen[j].mode.hdisplay + hfront_porch;
			mscreen[j].mode.hsync_end = mscreen[j].mode.hsync_start + hsync_len;
			mscreen[j].mode.htotal = mscreen[j].mode.hsync_end + hback_porch;

			mscreen[j].mode.vdisplay = vactive;
			mscreen[j].mode.vsync_start = mscreen[j].mode.vdisplay + vfront_porch;
			mscreen[j].mode.vsync_end = mscreen[j].mode.vsync_start + vsync_len;
			mscreen[j].mode.vtotal = mscreen[j].mode.vsync_end + vback_porch;

			mscreen[j].mode.clock = pixelclock / 1000;
			mscreen[j].mode.flags = flags;
		}
	}
	conn_state->screen = mscreen;
	return 0;
}

display logo

//首先调用display_init 初始化display的crtc connect 和pannel
ret = display_init(state);
if (!state->is_init || ret)
return -ENODEV;
//加载logo
if (load_bmp_logo(&state->logo, state->ulogo_name))
    printf("failed to display uboot logo\n");
//设定logo 显示模式 全屏或者居中
	if (logo->mode == ROCKCHIP_DISPLAY_FULLSCREEN) {
		crtc_state->crtc_x = 0;
		crtc_state->crtc_y = 0;
		crtc_state->crtc_w = hdisplay;
		crtc_state->crtc_h = vdisplay;
	} else {
		if (crtc_state->src_w >= hdisplay) {
			crtc_state->crtc_x = 0;
			crtc_state->crtc_w = hdisplay;
		} else {
			crtc_state->crtc_x = (hdisplay - crtc_state->src_w) / 2;
			crtc_state->crtc_w = crtc_state->src_w;
		}

		if (crtc_state->src_h >= vdisplay) {
			crtc_state->crtc_y = 0;
			crtc_state->crtc_h = vdisplay;
		} else {
			crtc_state->crtc_y = (vdisplay - crtc_state->src_h) / 2;
			crtc_state->crtc_h = crtc_state->src_h;
		}
	}
//调用ctrc的plane 设定
	display_set_plane(state);
	display_enable(state);
//conn_funcs->prepare 下发panel 参数
static int display_enable(struct display_state *state)
{
	struct connector_state *conn_state = &state->conn_state;
	const struct rockchip_connector *conn = conn_state->connector;
	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
	struct crtc_state *crtc_state = &state->crtc_state;
	const struct rockchip_crtc *crtc = crtc_state->crtc;
	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
	struct panel_state *panel_state = &state->panel_state;

	if (!state->is_init)
		return -EINVAL;

	if (state->is_enable)
		return 0;

	if (crtc_funcs->prepare)
		crtc_funcs->prepare(state);

	if (conn_funcs->prepare)
		conn_funcs->prepare(state, 0);

	if (conn_state->bridge)
		rockchip_bridge_pre_enable(conn_state->bridge);

	if (panel_state->panel)
		rockchip_panel_prepare(panel_state->panel);

	if (crtc_funcs->enable)
		crtc_funcs->enable(state);

	if (conn_funcs->enable)
		conn_funcs->enable(state);

	if (conn_state->bridge)
		rockchip_bridge_enable(conn_state->bridge);

	if (panel_state->panel)
		rockchip_panel_enable(panel_state->panel);

	state->is_enable = true;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值