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部分,当平台无对应 显示接口使用转换芯片
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部分的控制流程
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
这部分是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子系统流程
//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>;
};
};
};
};
分别获取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_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;
}