完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1、代码流程
由rk3288 uboot 启动流程分析可知,dispaly 驱动在board_fbt_preboot;中被调用,如下所示: #ifdef CONFIG_LCD /* logo state defautl init = 0 */ g_logo_on_state = 0; if (gd-》fdt_blob) { int node = fdt_path_offset(gd-》fdt_blob, “/fb”); g_logo_on_state = fdtdec_get_int(gd-》fdt_blob, node, “rockchip,uboot-logo-on”, 0); } printf(“read logo on state from dts [%d]n”, g_logo_on_state); if (g_logo_on_state != 0) { lcd_enable_logo(true); drv_lcd_init(); } #endif 当定义了CONFIG_LCD后,这段代码被调用通过对g_logo_on_state的判断来确定是否在uboot阶段显示logo。 /* /common/lcd.c */ static void *lcd_base; /* Start of framebuffer memory */ lcd_enable_logo(true); lcd_show_logo = 1; drv_lcd_init(); /* 第一步:获取framebuffer memory的起始位置 */ lcd_base = map_sysmem(gd-》fb_base, 0);/* framebuffer addr = 0x7dc00000 ,位于ddr地址的最后 */ /* 第二步: 初始化LCD */ /* 2.1 : 定义一个rockchip_fb的结构体指针 */ /* 2.2 : 解析屏幕相关的参数填充到panel_info结构体 */ /* 2.3 : 解析gpio相关的参数填充到pwr_ctr 结构体 */ /* 2.4 : 根据pwr_ctr结构体 控制gpio 输出 */ /* 2.5 : lcd 控制器的初始化 */ lcd_init(lcd_base); /* LCD initialization */ /* drivers/video/rockchip_fb.c */ struct rockchip_fb rockchip_fb; /* 定义了一个全局结构体 rockchip_fb */ lcd_ctrl_init(lcdbase); /* 定义一个 rockchip_fb 结构体指针 */ struct rockchip_fb *fb = &rockchip_fb; /* rockchip_fb 是一个全局结构体 */ /* 从设备树解析屏幕参数 */ int ret = rk_fb_parse_dt(fb, gd-》fdt_blob); /* gd-》fdt_blob 决定了是否从dts中解析数据 */ /* 获得dtb下display-timings 节点的偏移 ,这个偏移可以代表这个节点 */ int node = fdt_path_offset(blob(gd-》fdt_blob), “/display-timings”); phandle = fdt_getprop_u32_default_node(blob, node, 0, “native-mode”, -1); /* 填充panel_info结构体 */ /* panel_info 也是一个全局结构体 */ panel_info.vl_bpix = 5; panel_info.lvds_ttl_en = 0; panel_info.screen_type = fdtdec_get_int(blob, node, “screen-type”, -1); panel_info.color_mode = fdtdec_get_int(blob, node, “color-mode”, 0); panel_info.lcd_face = fdtdec_get_int(blob, node, “out-face”, -1); panel_info.vl_col = fdtdec_get_int(blob, node, “hactive”, 0); panel_info.vl_row = fdtdec_get_int(blob, node, “vactive”, 0); panel_info.vl_width = fdtdec_get_int(blob, node, “hactive”, 0); panel_info.vl_height = fdtdec_get_int(blob, node, “vactive”, 0); panel_info.vl_freq = fdtdec_get_int(blob, node, “clock-frequency”, 0); panel_info.vl_oep = fdtdec_get_int(blob, node, “de-active”, -1); panel_info.vl_hsp = fdtdec_get_int(blob, node, “hsync-active”, -1); panel_info.vl_vsp = fdtdec_get_int(blob, node, “vsync-active”, -1); panel_info.lvds_format = fdtdec_get_int(blob, node, “lvds-format”, -1); panel_info.vl_swap_rb = fdtdec_get_int(blob, node, “swap-rb”, -1); panel_info.vl_hspw = fdtdec_get_int(blob, node, “hsync-len”, 0); panel_info.vl_hfpd = fdtdec_get_int(blob, node, “hfront-porch”, 0); panel_info.vl_hbpd = fdtdec_get_int(blob, node, “hback-porch”, 0); panel_info.vl_vspw = fdtdec_get_int(blob, node, “vsync-len”, 0); panel_info.vl_vfpd = fdtdec_get_int(blob, node, “vfront-porch”, 0); panel_info.vl_vbpd = fdtdec_get_int(blob, node, “vback-porch”, 0); /* 解析lcdc0 节点 */ node = rk_fb_find_lcdc_node_dt(rk_fb(fb), blob); node = fdt_path_offset(blob, “lcdc0”); /* 解析gpio 节点 */ rk_fb_pwr_ctr_parse_dt(rk_fb, blob); panel_info.logo_rgb_mode = RGB565; /* 使能对应的gpio口 */ rk_fb_pwr_enable(fb); gpio_direction_output(pwr_ctr-》gpio.gpio,pwr_ctr-》atv_val); mdelay(pwr_ctr-》delay); /* LCDC 控制器 初始化 */ /* drivers/video/rk32_lcdc.c */ rk_lcdc_init(panel_info.lcdc_id); struct lcdc_device *lcdc_dev = &rk32_lcdc; /* rk32_lcdc 是一个全局结构体 */ lcdc_dev-》soc_type = gd-》arch.chiptype; /* 应该没什么用这个参数 */ lcdc_dev-》id = lcdc_id; /* lcdc_id = panel_info.lcdc_id */ rk32_lcdc_parse_dt(lcdc_dev, gd-》fdt_blob); /* 解析得到lcdc0 节点 */ lcdc_dev-》node = fdt_path_offset(blob, “lcdc0”); /* 获取lcdc 节点的regs 资源 */ lcdc_dev-》regs = fdtdec_get_addr(blob, lcdc_dev-》node, “reg”); /* 寄存器控制 */ /* 写 SYS_CTRL */ /* 写 DSP_CTRL1 */ /* cfg_done */ /*第三步 : 配置mipi dsi */ /*3.1 :解析display-timing /*3.2 :解析dsi /*3.3 :配置dsi host(初始化 phy等) /*3.4 :发送屏幕初始化序列 /* 配置mipi dsi */ /* drivers/video/rk32_lcdc.c */ rk_lcdc_load_screen(&panel_info); /* 使用在lcdc_init中初始化的lcdc_dev */ struct lcdc_device *lcdc_dev = &rk32_lcdc; struct rk_screen *screen = lcdc_dev-》screen; /* 将panel_info 过渡给rk_screen */ /* drivers/video/rockchip_fb.c */ rk_fb_vidinfo_to_screen(vid, screen); screen-》type = vid-》screen_type; 。.. /* mipi dsi 初始化 */ /* drivers/video/transmitter/rk32_mipi_dsi.c */ rk32_mipi_enable(vid); struct dsi *dsi; struct mipi_dsi_ops *ops; struct rk_screen *screen; struct mipi_dsi_screen *dsi_screen; /* drivers/video/screen/lcd_mipi.c */ rk_mipi_screen_probe(); gmipi_screen = calloc(1, sizeof(struct mipi_screen)); /* 全局变量 */ /* 解析dts */ ret = rk_mipi_screen_init_dt(gmipi_screen); struct device_node *childnode, *grandchildnode, *root; struct mipi_dcs_cmd_ctr_list *dcs_cmd; struct list_head *pos; struct property *prop; /* 将mipi_screen 清 0 , mipi_screen 是一个全局变量 */ memset(screen, 0, sizeof(*screen)); /* 链表头初始化 */ INIT_LIST_HEAD(&screen-》cmdlist_head); /* 获取mipi_dsi_init 节点 */ childnode = of_find_node_by_name(NULL, “mipi_dsi_init”); /* 获取screen_init 属性的值赋予value */ ret = of_property_read_u32(childnode, “rockchip,screen_init”, &value); /* 赋值screen_init */ screen-》screen_init = value ; /* 获取 dsi_lane 属性的值 */ ret = of_property_read_u32(childnode, “rockchip,dsi_lane”, &value); screen-》dsi_lane = value; /* 获取dsi_hs_clk 属性的值 */ ret = of_property_read_u32(childnode, “rockchip,dsi_hs_clk”, &value); screen-》hs_tx_clk = value*MHz; /* 获取mipi_dsi_num 属性的值 */ ret = of_property_read_u32(childnode, “rockchip,mipi_dsi_num”, &value); screen-》mipi_dsi_num = value ; /* 获取 mipi_power_ctr 节点 */ childnode = of_find_node_by_name(NULL, “mipi_power_ctr”); /* 获取mipi_lcd_rst 节点 */ grandchildnode = of_get_child_by_name(childnode, “mipi_lcd_rst”); /* 获取 mipi reset delay 属性的值 */ ret = of_property_read_u32(grandchildnode, “rockchip,delay”, &value); screen-》lcd_rst_delay = value; /* 获取mipi reset gpio 属性 */ gpio = of_get_named_gpio_flags(grandchildnode, “rockchip,gpios”, 0, &flags); /* 获取对应的gpio */ ret = gpio_request(gpio,“mipi_lcd_rst”); screen-》lcd_rst_gpio = gpio; screen-》lcd_rst_atv_val = (flags == GPIO_ACTIVE_HIGH)? 1:0; /* 获取mipi_lcd_en 节点 */ grandchildnode = of_get_child_by_name(childnode, “mipi_lcd_en”); /* 获取 mipi en delay 属性的值 */ ret = of_property_read_u32(grandchildnode, “rockchip,delay”, &value); screen-》lcd_en_delay = value; /* 获取mipi en gpio */ gpio = of_get_named_gpio_flags(grandchildnode, “rockchip,gpios”, 0, &flags); ret = gpio_request(gpio,“mipi_lcd_en”); screen-》lcd_en_gpio = gpio; screen-》lcd_en_atv_val= (flags == GPIO_ACTIVE_HIGH)? 1:0; /* 获取screen-on-cmds 节点 */ root= of_find_node_by_name(NULL,“screen-on-cmds”); /* cmd 节点的东西很多 需要循环依次来获取存放 */ for_each_child_of_node(root, childnode) /* 存放cmd的结构体 */ dcs_cmd = kmalloc(sizeof(struct mipi_dcs_cmd_ctr_list), GFP_KERNEL); /* 区分不同的cmd */ strcpy(dcs_cmd-》dcs_cmd.name, childnode-》name); /* 获取一个cmd的长度 */ prop = of_find_property(childnode, “rockchip,cmd”, &length); dcs_cmd-》dcs_cmd.cmd_len = length / sizeof(u32) ; /* 根据长度依次 将cmd保存到dcs_cmd-》dcs_cmd.cmds */ for(i = 0; i 《 (length / sizeof(u32)); i++) dcs_cmd-》dcs_cmd.cmds = cmds; /* 获取dsi_id */ ret = of_property_read_u32(childnode, “rockchip,dsi_id”, &value); dcs_cmd-》dcs_cmd.dsi_id = value; /* 获取cmd_type */ ret = of_property_read_u32(childnode, “rockchip,cmd_type”, &value); dcs_cmd-》dcs_cmd.type = value; /* 获取cmd_delay */ ret = of_property_read_u32(childnode, “rockchip,cmd_delay”, &value); dcs_cmd-》dcs_cmd.delay = value; /* 解析完了一个cmd 后将包含这个cmd的信息链接到cmdlist_head链表中 */ list_add_tail(&dcs_cmd-》list, &screen-》cmdlist_head); /* rk32_mipi_enable */ /* 获取之前解析出来的dsi 数量 */ dsi_number = rk_mipi_get_dsi_num(); /* 有几个dsi就搞几个dsi */ for(id = 0; id 《 dsi_number;) /* 为每一个dsi分配空间 */ dsi = calloc(1, sizeof(struct dsi)); /* 通过id区分不同的dsi */ dsi-》dsi_id = id++; /* 解析dsi_host 就是为了dsi的基地址 */ rk_dsi_host_parse_dt(gd-》fdt_blob,dsi); /* 找到rk32_dsi 节点 */ node = fdt_node_offset_by_compatible(blob, 0, “rockchip,rk32-dsi”); /* 确定host 的基地址 */ dsi-》host.membase = (void __iomem *)(unsigned long)fdtdec_get_int(blob, node, “reg”, -1); /* 分 配 rk_screen */ screen = calloc(1, sizeof(struct rk_screen)); /* 准备填充ops */ ops = &dsi-》ops; ops-》dsi = dsi; ops-》get_id = rk32_mipi_dsi_get_id, /* 关键操作函数 发送数据 */ ops-》dsi_send_packet = rk32_mipi_dsi_send_packet; ops-》dsi_read_dcs_packet = rk32_mipi_dsi_read_dcs_packet, ops-》dsi_enable_video_mode = rk32_mipi_dsi_enable_video_mode, ops-》dsi_enable_command_mode = rk32_mipi_dsi_enable_command_mode, ops-》dsi_enable_hs_clk = rk32_mipi_dsi_enable_hs_clk, ops-》dsi_is_active = rk32_mipi_dsi_is_active, ops-》dsi_is_enable= rk32_mipi_dsi_is_enable, ops-》power_up = rk32_mipi_dsi_power_up, ops-》power_down = rk32_mipi_dsi_power_down, ops-》dsi_init = rk_mipi_dsi_init, /* 填充mipi_dsi_screen */ dsi_screen = &dsi-》screen; dsi_screen-》type = screen-》type = vid-》screen_type; dsi_screen-》face = screen-》face = vid-》lcd_face; dsi_screen-》pixclock = screen-》mode.pixclock = vid-》real_freq; dsi_screen-》pin_den = screen-》pin_den = vid-》vl_oep; 。。。 |
|
|
|
dsi_screen-》lcdc_id = 1;
/* 注册dsi ops */ ret = rk_mipi_dsi_probe(dsi); /* 就是将ops放入一个全局数组中通过dsi_id管理起来 */ register_dsi_ops(dsi-》dsi_id, &dsi-》ops); dsi_ops[id] = ops; /*static struct mipi_dsi_ops *dsi_ops[MAX_DSI_CHIPS] = {NULL}; 全局变量 */ /* 探测当前的dsi chip是否存在 */ ret = dsi_probe_current_chip(dsi-》dsi_id); /* 不在dis_num 的for中 */ rk32_dsi_enable(); /* 判断dsi0 的时钟是否打开 dsi0 是一个全局变量*/ if (!dsi0-》clk_on) { /* 调用之前注册到dsi 的dsi_init ops函数 ,这里将dsi0 和前面的dsi关联起来了 */ dsi_init(0, 0); /* 这里的dsi 对应的就是id = 0 的dsi */ ops-》dsi_init(ops-》dsi, n); static int rk_mipi_dsi_init(void *arg, u32 n) struct dsi *dsi = arg; struct mipi_dsi_screen *screen = &dsi-》screen; /* 设置各种时钟 */ dsi-》phy.Tpclk = div_u64(1000000000000llu, screen-》pixclock); dsi-》phy.ref_clk = 24*MHZ; dsi-》phy.sys_clk = dsi-》phy.ref_clk; dsi-》phy.ddr_clk = 1500 * MHz; /* default is 1.5HGz */ decimals = dsi-》phy.ref_clk; dsi-》phy.ddr_clk = dsi-》phy.ref_clk / dsi-》phy.prediv * dsi-》phy.fbdiv; 。。。 dsi-》host.video_mode = VM_BM; mdelay(10); /* 计算完phy的时钟后开始进行操作了 */ rk_phy_power_up(dsi); rk32_phy_power_up(dsi); /* 开时钟 */ rk32_mipi_dsi_clk_enable(dsi); val = 0x80000000;//bit31~bit16 writel(val, RK3288_CRU_PHYS + 0x174); /*24M*/ writel(val, RK3288_CRU_PHYS + 0x1a0); /*pclk*/ /* 设置dsi lane */ switch(dsi-》host.lane) /* 以4根lane为例 */ rk32_dsi_set_bits(dsi, 3, n_lanes); /* 写寄存器了 */ rk32_dsi_set_bits(dsi, 1, phy_shutdownz); rk32_dsi_set_bits(dsi, 1, phy_rstz); rk32_dsi_set_bits(dsi, 1, phy_enableclk); rk32_dsi_set_bits(dsi, 1, phy_forcepll); /* dsi 上电? */ rk32_mipi_dsi_host_power_up(dsi); /* 禁用所有中断 */ rk32_dsi_set_bits(dsi, 0x1fffff, INT_MKS0); rk32_dsi_set_bits(dsi, 0x3ffff, INT_MKS1); rk32_mipi_dsi_is_enable(dsi, 1); rk32_dsi_set_bits(dsi, enable, shutdownz); /* 检测phy clk 是否起来了 等待了一段时间 */ while(!rk32_dsi_get_bits(dsi, phylock) && val--) /* phy 的初始化 */ rk_phy_init(dsi); /* phy 的初始化 */ rk32_phy_init(dsi); /* test data 那一套东西 */ /* dsi host 的初始化 */ rk32_mipi_dsi_host_init(dsi); struct mipi_dsi_screen *screen = &dsi-》screen; rk32_dsi_set_bits(dsi, dsi-》host.lane - 1, n_lanes); rk32_dsi_set_bits(dsi, dsi-》vid, dpi_vcid); rk32_dsi_set_bits(dsi, 1, hsync_active_low); 。。。 rk32_dsi_set_bits(dsi, dsi-》host.video_mode, vid_mode_type); //burst mode 。。。 /* 根据video mode screen type 等配置寄存器 */ /* 配置一些时序 寄存器 */ rk32_dsi_set_bits(dsi, dsi-》phy.Tpclk * (screen-》left_margin) / dsi-》phy.Ttxbyte_clk, vid_hbp_time); rk32_dsi_set_bits(dsi, screen-》y_res , vid_active_lines); rk32_dsi_set_bits(dsi, screen-》lower_margin, vid_vfp_lines); rk32_dsi_set_bits(dsi, screen-》upper_margin, vid_vbp_lines); 。。。 driver/video/transmitter/rk32_mipi_dsi.c rk32_dsi_enable */ rk_mipi_screen_standby(0); /* driver/video/screen/lcd_mipi.c */ int rk_mipi_screen_standby(u8 enable) rk_dsi_num = gmipi_screen-》mipi_dsi_num; rk_mipi_screen(); /* enable = 0 时 */ rk_dsi_num = gmipi_screen-》mipi_dsi_num; /* 这个不需要也可以前面做过了 */ rk_mipi_screen_pwr_enable(gmipi_screen); dsi_enable_hs_clk(0,1); dsi_enable_video_mode(0,0); /* 通过ops调用之前注册的ops函数中的dsi enable video mode函数 enable = 0 */ ops-》dsi_enable_video_mode(ops-》dsi, enable); rk32_mipi_dsi_enable_video_mode(ops-》dsi,0) /* 设置相应的寄存器 */ rk32_dsi_set_bits(dsi, !enable, cmd_video_mode); /* 打开command mode */ dsi_enable_command_mode(0, 1); /* 通过command mode 发送屏幕初始化序列 */ rk_mipi_screen_cmd_init(gmipi_screen); struct list_head *screen_pos; struct mipi_dcs_cmd_ctr_list *dcs_cmd; /* 通过screen 中的comlist_head链表去访问各个cmd */ list_for_each(screen_pos, &screen-》cmdlist_head){ /* 发送函数 */ dsi_send_packet(1, cmds, len); ops-》dsi_send_packet(ops-》dsi, packet, n); static int rk32_mipi_dsi_send_packet(void *arg, unsigned char cmds[], u32 length) /* 发送完初始化序列后,关闭command模式 */ dsi_enable_command_mode(0,0); /* 打开video 模式 */ dsi_enable_video_mode(0,1); dsi_is_enable(0, 0); rk32_mipi_dsi_is_enable(dsi,0) rk32_dsi_set_bits(dsi, enable, shutdownz); dsi_enable_video_mode(0, 1); dsi_is_enable(0, 1); /* rk32_lcdc.c rk_lcdc_load_screen */ rk32_dsi_sync(); dsi_is_enable(0, 0); dsi_enable_video_mode(0, 1); dsi_is_enable(0, 1); /* 第四步: 显示logo */ /*4.1 : 获取bmp问题的位置 */ /*4.2 : 获取framebuffer的位置 */ /*4.3 : 将bmp写到framebuffer中 */ /*4.4 : 设置图层显示framebuffer的内容 */ /* /common/lcd.c lcd_init */ /* lcd_ctrl_init 完成后,准备显示logo */ lcd_clear(); /* 画logo */ static void *lcd_logo(void) /* 绘制位图并显示*/ bitmap_plot(0, 0); /* 获取一个bmp_logo_palette 的数据 */ uint *cmap = (uint *)bmp_logo_palette; ushort i, j; uchar *bmap; uchar *fb; ushort *fb16; unsigned bpix = NBITS(panel_info.vl_bpix); /* 获取一个bmp_logo_bitmap 的数据 */ bmap = &bmp_logo_bitmap[0]; /* 设置fb 指针 */ fb = (uchar *)(lcd_base); /* */ if(!rk_bitmap_from_resource((unsigned short*)fb)) show_resource_image(file_path) /*把位图搬运到bmp-》addr处 */ load_content_data(&image, 0, image.load_addr, blocks) /* 把bmp-》addr得东西按照格式搞到fb-》add */ lcd_display_bitmap_center((uint32_t)(unsigned long)image.load_addr); lcd_display_bitmap(bmp_image, (panel_info.vl_col - width)/2,(panel_info.vl_row - height)/2); /* 写buffer */ /* 显示 drivers/video/rockchip_fb.c */ lcd_pandispaly(&fb_info); /* drivers/video/rk32_lcdc.c */ rk_lcdc_set_par(info, &panel_info); /* 有多个图层 选择一个作为默认的图层去显示 */ fb_info-》layer_id = lcdc_dev-》dft_win; /* 通过win0 显示 */ win0_set_par(lcdc_dev, fb_info, vid); /* 使用这个来表示一个图层 */ struct rk_lcdc_win win; memset(&win, 0, sizeof(struct rk_lcdc_win)); /* 计算显示时x坐标 */ win.area[0].dsp_stx = dsp_x_pos(win.mirror_en, screen, win.area); /* 计算显示时y坐标 */ win.area[0].dsp_sty = dsp_y_pos(win.mirror_en, screen, win.area); /* 显示效果相关计算获取对应的参数 */ rk3288_lcdc_calc_scl_fac(&win, screen); /* 显示格式 */ win.area[0].y_vir_stride = v_RGB565_VIRWIDTH(fb_info-》xvir); /* 写寄存器,将刚计算获得的值写到相应的寄存器中去 */ rk3288_win_0_1_reg_update(lcdc_dev, &win, fb_info-》layer_id); /* 设置将win0 的数据获取入口设置为framebuffer 的位置 */ lcdc_writel(lcdc_dev, WIN0_YRGB_MST, fb_info-》yaddr); lcdc_writel(lcdc_dev, BCSH_BCS, 0xd0010000); 。。。 lcdc_cfg_done(lcdc_dev); /* bitmap_plot(0, 0); */ /* 刷新caches */ lcd_sync(); /* 第五步: 开背光 */ /* board/rockchip/common/rkboot/fastboot.c */ rk_pwm_bl_config(-1); /* drives/video/backlight/pwm_bl.c */ int rk_pwm_bl_config(int brightness) /* 设置pwm */ 2、十二问 问题1、GD这个全局变量是什么? /* include/asm-arm/global_data.h */ typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; unsigned long have_console; /* serial_init() was called */ unsigned long reloc_off; /* Relocation Offset */ unsigned long env_addr; /* Address of Environment struct */ unsigned long env_valid; /* Checksum of Environment valid? */ unsigned long fb_base; /* base address of frame buffer */ #ifdef CONFIG_VFD unsigned char vfd_type; /* display type */ #endif #if 0 unsigned long cpu_clk; /* CPU clock in Hz! */ unsigned long bus_clk; unsigned long ram_size; /* RAM size */ unsigned long reset_status; /* reset status register at boot */ #endif void **jt; /* jump table */ }gd_t; GD全局变量是uboot启动的最开始就在ram中申请创建的一个结构体,它的生命周期贯穿uboot启动的整个阶段,所以可以用来传递大量信息。 uboot使用gd来传递信息是因为,有些时候uboot可能是在一些只读类存储器上运行的,在uboot被重定位到ram之前,是无法写入数据的,把gd放在ram中,就可以对齐进行读写保存需要的信息。 在gd初始化的时候,会将gd的地址放在r9寄存器中,后面需要使用到gd时直接访问r9即可。 问题2、gd-》fb_base 是何时赋值为何? 在board_init_f 的list中有一个reserve_lcd。这个函数中对gd-》fb_base进行了赋值 。 static int setup_fdt(void) { #ifdef CONFIG_OF_CONTROL # ifdef CONFIG_OF_EMBED /* 使用CONFIG_OF_EMBED 的方式,dtb集成到了uboot的bin文件中,通过_dtb_dt_begin 来获取dtb的地址 */ /* Get a pointer to the FDT */ gd-》fdt_blob = __dtb_dt_begin; # elif defined CONFIG_OF_SEPARATE /* FDT is at end of image */ /* 使用CONFIG_OF_SEPARATE 的方式,此时dtb 是追加在uboot的bin文件后面的,所以通过_end符号来获取dtb的地址 */ gd-》fdt_blob = (ulong *)&_end; # elif defined(CONFIG_OF_HOSTFILE) if (read_fdt_from_file()) { puts(“Failed to read control FDTn”); return -1; } # endif /* Allow the early environment to override the fdt address */ /* 也可以通过环境变量“fdtcontroladdr 来指定fdt的地址 */ gd-》fdt_blob = (void *)getenv_ulong(“fdtcontroladdr”, 16, (uintptr_t)gd-》fdt_blob); #endif return 0; } 问题3、gd-》fdt_blob 是做什么的,何时初始化的? gd-》fdt_blob 保存的是fdt的地址,是由board_init_f 的list中的setup_fdt最先获取,注意:设备树编译生成的dtb文件并不包含在uboot.bin当中。 static int setup_fdt(void) { #ifdef CONFIG_OF_CONTROL # ifdef CONFIG_OF_EMBED /* 使用CONFIG_OF_EMBED 的方式,dtb集成到了uboot的bin文件中,通过_dtb_dt_begin 来获取dtb的地址 */ /* Get a pointer to the FDT */ gd-》fdt_blob = __dtb_dt_begin; # elif defined CONFIG_OF_SEPARATE /* FDT is at end of image */ /* 使用CONFIG_OF_SEPARATE 的方式,此时dtb 是追加在uboot的bin文件后面的,所以通过_end符号来获取dtb的地址 */ gd-》fdt_blob = (ulong *)&_end; # elif defined(CONFIG_OF_HOSTFILE) if (read_fdt_from_file()) { puts(“Failed to read control FDTn”); return -1; } # endif /* Allow the early environment to override the fdt address */ /* 也可以通过环境变量“fdtcontroladdr 来指定fdt的地址 */ gd-》fdt_blob = (void *)getenv_ulong(“fdtcontroladdr”, 16, (uintptr_t)gd-》fdt_blob); #endif return 0; } 由setup_fdt 获取fdt 最开始的地址后,我们还需要调用reserve_fdt来为其保留空间: static int reserve_fdt(void) { /* * If the device tree is sitting immediate above our image then we * must relocate it. If it is embedded in the data section, then it * will be relocated with other data. */ if (gd-》fdt_blob) { gd-》fdt_size = ALIGN(fdt_totalsize(gd-》fdt_blob) + 0x1000, 32); gd-》start_addr_sp -= gd-》fdt_size; gd-》new_fdt = map_sysmem(gd-》start_addr_sp, gd-》fdt_size); debug(“Reserving %lu Bytes for FDT at: %08lxn”, gd-》fdt_size, gd-》start_addr_sp); } return 0; } 最后通过reloc_fdt来完成fdt的重定位并更新fdt的地址: static int reloc_fdt(void) { if (gd-》new_fdt) { memcpy(gd-》new_fdt, gd-》fdt_blob, gd-》fdt_size); gd-》fdt_blob = gd-》new_fdt; } return 0; } |
|
|
|
问题4、 struct mipi_screen 中的cmdlist_head 链表的作用是什么?
struct list_head cmdlist_head; 在rk_mipi_screen_init_dt(gmipi_screen); 中调用 INIT_LIST_HEAD(&screen-》cmdlist_head);完成了初始化,然后在后面解析cmd命令时,每解析完一条cmd(完成struct mipi_dcs_cmd_ctr_list 结构体的填充后)调用 list_add_tail(&dcs_cmd-》list, &screen-》cmdlist_head); 将struct mipi_dcs_cmd_ctr_list 中的dcs_cmd -》链接到cmdlist_head 中,就这样每解析了一条cmd就链接进去一条。最终实现了通过struct mipi_screen 结构体可以访问到所有cmd的功能。方便通过mipi 发送cmd去初始化屏幕。 问题5、rk32_mipi_enable 中的struct rk_screen *screen 与rk_mipi_screen_probe()中的struct mipi_screen gmipi_screen 及struct mipi_dsi_screen *dsi_screen;的关系是什么? struct rk_screen *screen 是rk对支持的屏幕的一个集合,这些屏幕包括rgb屏幕、mipi屏幕、lvds屏幕等。当使用其中一种屏幕时有些成员时没有用的。其主要用于lcdc控制器中图层相关的寄存器配置上。而struct mipi_screen 是针对mipi屏幕的特点构成的一个集合,主要包含了mipi 屏幕使用dsi 通道数目、使能和复位的gpio口控制、需要发送的屏幕初始化序列。主要用来初始化屏幕。struct mipi_dsi_screen 是 struct dsi 中成员,在mipi dis host 初始化时会使用struct mipi_dsi_screen 成员的的值去配置相应的寄存器。如:vid_hline_time、vid_hbp_time、vid_hsa_time、vid_active_lines、vid_vfp_lines、vid_vbp_lines、vid_vsa_lines等。 总结:struct rk_screen *screen 用于lcdc控制器的寄存器配置、struct mipi_screen gmipi_screen 用于mipi 屏幕的初始化、struct mipi_dsi_screen *dsi_screen 用于MIPI DSI相关寄存器的配置。 问题6、 在rk32_mipi_enable(vid); 中会根据dsi_num去配置所有的dsi,dsi_num是什么含义? 查看rk3288 Block Diagram 可知,rk3288中集成了两个MIPI DSi PHY :dsihost0: mipi@ff960000 dsihost1: mipi@ff964000。在初始化的时候需要将这两个dsi phy都初始化了,所以出现了dsi_num的参数。方便对一个或两个dsi phy进行访问控制。 问题7、rk32_dsi_enable 中出现的dsi0 和 rk32_mipi_enable 中初始化填充的dsi有什么关联? 没什么用,可以用自己建立的dsi去代替它 问题8、解析设备树获取节点属性信息时,有很多define值,他们定义在什么地方? 解析设备树时所有的信息都是从设备树文件中得到,打开查看设备树文件可以看到它也是有#include 头文件的。其中大部分头文件都是在kernel/arch/arm/boot/dts/include/dt-bindings/。。。 中,这些头文件就定义了绝大部分使用到的值,如: 。/rkfb/rk_fb.h:#define SCREEN_MIPI 7 问题9、Uboot启动阶段一定会使能mipi dsi 的command mode去发送屏幕初始化序列么? 根据不同的lcd屏幕的spec 决定是否需要初始化,对于需要初始化的lcd屏幕就调用相应的接口发送初始化cmd进行初始化。 问题10、代码中的standby的含义是什么? 待机模式,当需要进入待机模式时调用rk_mipi_screen_standby(1),会通过dcs发送display_off命令给lcd。并进入sleep 模式。 最后关掉power。 退出standby模式时会首先打开dsi power。使能时钟,使能command模式,发送退出sleep mode 命令。发送display on命令,再关闭command模式。打开video mode。 问题11、bmp_logo_palette[] 是什么? bmp_logo_palette 放在bmp_logo_data.h中,是一个数组。而我们在编译uboot的过程中可以看到以下打印信息: tools/bmp_logo --gen-info /home/kai/work/rk3288/x3288_lollipop/u-boot/tools/logos/rockchip.bmp 》 /home/kai/work/rk3288/x3288_lollipop/u-boot/include/bmp_logo.h tools/bmp_logo --gen-data /home/kai/work/rk3288/x3288_lollipop/u-boot/tools/logos/rockchip.bmp 》 /home/kai/work/rk3288/x3288_lollipop/u-boot/include/bmp_logo_data.h 可以看出bmp_logo_data.h 是由/home/kai/work/rk3288/x3288_lollipop/u-boot/tools/logos/rockchip.bmp 这个位图文件经由tools/bmp_logo 处理产生的 起始就是把一个.bmp位图转换成数组数据放在了.h文件中,方便程序去调用显示。 问题12、如何获取bmp? bmp 可以通过上面bmp_logo_palette数组中的数据获得,也可以在一开始就在ram中保留一个区域,然后将img中的位图拷贝过去 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1924 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2406 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5193 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 22:45 , Processed in 0.624441 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号