根据设备树 rockchip,uboot-logo-on = <1> 在u-boot中找到源码位置
void board_fbt_preboot(void)
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);
if (g_logo_on_state != 0) {
lcd_enable_logo(true);
drv_lcd_init();
/*
lcd_init(lcd_base); /* LCD initialization */
rc = stdio_register(&lcddev);
*/
#ifdef CONFIG_LCD
if (g_logo_on_state != 0) {
//lcd_enable_logo(true);
//显示logo
lcd_standby(0);
//mdelay(100);
/* use defaut brightness in dts */
rk_pwm_bl_config(-1);
}
#endif
}
lcd_init(void *lcdbase) (rk3288\u-boot\common\Lcd.c)
lcd_ctrl_init(lcdbase); (u-boot\driver\video\rockchip_fb.c)
/*
struct rockchip_fb *fb = &rockchip_fb;
int ret = rk_fb_parse_dt(fb, gd->fdt_blob); //解析fb相关的fdt
/*
node = fdt_path_offset(blob, "/display-timings");
//找到native-mode的值
phandle = fdt_getprop_u32_default_node(blob, node, 0, "native-mode", -1);
//根据native-mode对应的handler找到timing
node = fdt_node_offset_by_phandle_node(blob, node, phandle);
开始设置pannel_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-fac
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);
if (panel_info.vl_swap_rb == (u_char)-1) {
debug("Can't get swap-rb, set to 0 for default\n");
panel_info.vl_swap_rb = 0;
}
panel_info.vl_hspw = fdtdec_get_int(blob, node, "hsync-len", 0);
if (panel_info.vl_hspw == 0) {
debug("Can't get hsync-len, use 10 to default\n");
panel_info.vl_hspw = 10;
}
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);
//查看lcdc是PRIMER:0还是EXTERN:1
node = rk_fb_find_lcdc_node_dt(rk_fb, blob);
panel_info.lcdc_id = rk_fb->lcdc_id;
rk_fb_pwr_ctr_parse_dt(rk_fb, blob);
debug("lcd timing:\n"
"screen_type:%d\n"
"lcd_face=0x%x\n"
"vl_col=%d\n"
"vl_row=%d\n"
"vl_freq = %d\n"
"lvds_format=%d\n"
"lcdc_id=%d\n",
panel_info.screen_type,
panel_info.lcd_face,
panel_info.vl_col,
panel_info.vl_row,
panel_info.vl_freq,
panel_info.lvds_format,
panel_info.lcdc_id);
*/
//设置lcdc的时钟pll_src = 0, dclk_hz = 68000000, dclk_div = 6 (panel_info.lcdc_id:0代表lcdc0,1代表lcdc1,前面设置的是主显示器lcdc0)
panel_info.real_freq = rkclk_lcdc_clk_set(panel_info.lcdc_id,panel_info.vl_freq);
rk_lcdc_init(panel_info.lcdc_id); // 初始化lcdc0 panel_info.lcdc_id:0
rk_lcdc_load_screen(&panel_info);
*/
struct lcdc_device {
int node;
int id;
int soc_type;
int dft_win; /*default win for display*/
int regsbak[REG_LEN];
int regs; /*1:standby,0:wrok*/
struct rk_screen *screen;
};
int rk_lcdc_init(int lcdc_id)
{
struct lcdc_device *lcdc_dev = &rk32_lcdc;
u32 msk, val;
lcdc_dev->soc_type = gd->arch.chiptype;
lcdc_dev->id = lcdc_id;
rk32_lcdc_parse_dt(lcdc_dev, gd->fdt_blob);
/*
设置lcdc_dev->reg = 0xff930000, lcdc_dev->dft_win =order % 10;
*/
grf_writel(1<<16, GRF_IO_VSEL); /*LCDCIOdomain 3.3 Vvoltageselectio*/
msk = m_AUTO_GATING_EN | m_STANDBY_EN | m_DMA_STOP | m_MMU_EN;
val = v_AUTO_GATING_EN(1) | v_STANDBY_EN(0) | v_DMA_STOP(0) | v_MMU_EN(0);
lcdc_msk_reg(lcdc_dev, SYS_CTRL, msk, val);
msk = m_DSP_LAYER3_SEL | m_DSP_LAYER2_SEL| m_DSP_LAYER1_SEL | m_DSP_LAYER0_SEL;
val = v_DSP_LAYER3_SEL(3) | v_DSP_LAYER2_SEL(2) | v_DSP_LAYER1_SEL(1) | v_DSP_LAYER0_SEL(0);
lcdc_msk_reg(lcdc_dev, DSP_CTRL1, msk, val);
lcdc_cfg_done(lcdc_dev);
return 0;
}
/* Screen description
*type:LVDS,RGB,MIPI,MCU
*lvds_fromat:lvds data format,set it if the screen is lvds
*face:thi display output face,18bit,24bit,etc
*ft: the time need to display one frame time
*/
struct rk_screen {
u16 type;
u16 lvds_format;
u16 face;
u16 color_mode;
u8 lcdc_id;
u8 screen_id;
struct fb_videomode mode;
u32 post_dsp_stx;
u32 post_dsp_sty;
u32 post_xsize;
u32 post_ysize;
u16 x_mirror;
u16 y_mirror;
int interlace;
int pixelrepeat; //For 480i/576i format, pixel is repeated twice.
u16 width;
u16 height;
u8 ft;
int *dsp_lut;
int *cabc_lut;
u8 hdmi_resolution;
u8 mcu_wrperiod;
u8 mcu_usefmk;
u8 mcu_frmrate;
u8 pin_hsync;
u8 pin_vsync;
u8 pin_den;
u8 pin_dclk;
/* Swap rule */
u8 swap_gb;
u8 swap_rg;
u8 swap_rb;
u8 swap_delta;
u8 swap_dumy;
int xpos; //horizontal display start position on the sceen ,then can be changed by application
int ypos;
int xsize; //horizontal and vertical display size on he screen,they can be changed by application
int ysize;
struct rk_screen *ext_screen;
struct overscan overscan;
/* Operation function*/
int (*init)(void);
int (*standby)(u8 enable);
int (*refresh)(u8 arg);
int (*scandir)(u16 dir);
int (*disparea)(u8 area);
int (*sscreen_get)(struct rk_screen *screen, u8 resolution);
int (*sscreen_set)(struct rk_screen *screen, bool type);
};
int rk_lcdc_load_screen(vidinfo_t *vid)
{
struct lcdc_device *lcdc_dev = &rk32_lcdc;
struct rk_screen *screen = lcdc_dev->screen;
int face = 0;
u32 msk, val;
//用前面设置的panel_info给rk_screen赋值
rk_fb_vidinfo_to_screen(vid, screen);
if (vid->screen_type == SCREEN_RGB ||
vid->screen_type == SCREEN_LVDS ||
vid->screen_type == SCREEN_DUAL_LVDS) {
msk = m_MIPI_OUT_EN | m_EDP_OUT_EN |
m_HDMI_OUT_EN | m_RGB_OUT_EN;
val = v_RGB_OUT_EN(1);
}
lcdc_msk_reg(lcdc_dev, SYS_CTRL, msk, val);
msk = m_DSP_BLACK_EN | m_DSP_BLANK_EN | m_DSP_OUT_ZERO |
m_DSP_DCLK_POL | m_DSP_DEN_POL | m_DSP_VSYNC_POL |
m_DSP_HSYNC_POL;
val = v_DSP_BLACK_EN(0) | v_DSP_BLANK_EN(0) | v_DSP_OUT_ZERO(0) |
v_DSP_DCLK_POL(vid->vl_clkp) | v_DSP_DEN_POL(vid->vl_oep) |
v_DSP_VSYNC_POL(vid->vl_vsp) | v_DSP_HSYNC_POL(vid->vl_hsp);
lcdc_msk_reg(lcdc_dev, DSP_CTRL0, msk, val);
switch (vid->lcd_face) {
...
...
case OUT_D888_P666:
face = OUT_P888;
msk = m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE |
m_DITHER_DOWN_SEL;
val = v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1) |
v_DITHER_DOWN_SEL(1);
break;
}
lcdc_msk_reg(lcdc_dev, DSP_CTRL1, msk, val);
msk = m_DSP_RG_SWAP | m_DSP_RB_SWAP | m_DSP_DELTA_SWAP |
m_DSP_FIELD_POL | m_DSP_DUMMY_SWAP | m_DSP_BG_SWAP |
m_DSP_OUT_MODE;
val = v_DSP_RG_SWAP(0) | v_DSP_RB_SWAP(vid->vl_swap_rb) |
v_DSP_DELTA_SWAP(0) | v_DSP_DUMMY_SWAP(0) |
v_DSP_FIELD_POL(0) | v_DSP_BG_SWAP(0) |
v_DSP_OUT_MODE(face);
lcdc_msk_reg(lcdc_dev, DSP_CTRL0, msk, val);
lcdc_writel(lcdc_dev, DSP_BG, 0);
val = v_DSP_HS_PW(vid->vl_hspw) | v_DSP_HTOTAL(vid->vl_hspw +
vid->vl_hbpd + vid->vl_col + vid->vl_hfpd);
lcdc_writel(lcdc_dev, DSP_HTOTAL_HS_END, val);
val = v_DSP_HACT_END(vid->vl_hspw + vid->vl_hbpd + vid->vl_col) |
v_DSP_HACT_ST(vid->vl_hspw + vid->vl_hbpd);
lcdc_writel(lcdc_dev, DSP_HACT_ST_END, val);
val = v_DSP_VTOTAL(vid->vl_vspw + vid->vl_vbpd +
vid->vl_row + vid->vl_vfpd) | v_DSP_VS_PW(vid->vl_vspw);
lcdc_writel(lcdc_dev, DSP_VTOTAL_VS_END, val);
val = v_DSP_VACT_END(vid->vl_vspw + vid->vl_vbpd + vid->vl_row)|
v_DSP_VACT_ST(vid->vl_vspw + vid->vl_vbpd);
lcdc_writel(lcdc_dev, DSP_VACT_ST_END, val);
val = v_DSP_HACT_END_POST(vid->vl_hspw + vid->vl_hbpd + vid->vl_col) |
v_DSP_HACT_ST_POST(vid->vl_hspw + vid->vl_hbpd);
lcdc_writel(lcdc_dev, POST_DSP_HACT_INFO, val);
val = v_DSP_HACT_END_POST(vid->vl_vspw + vid->vl_vbpd + vid->vl_row)|
v_DSP_HACT_ST_POST(vid->vl_vspw + vid->vl_vbpd);
lcdc_writel(lcdc_dev, POST_DSP_VACT_INFO, val);
lcdc_writel(lcdc_dev, POST_DSP_VACT_INFO_F1, 0);
lcdc_writel(lcdc_dev, POST_RESERVED, 0x10001000);
lcdc_writel(lcdc_dev, MCU_CTRL, 0);
msk = m_DSP_LINE_FLAG_NUM | m_LINE_FLAG_INTR_EN;
val = v_DSP_LINE_FLAG_NUM(vid->vl_vspw + vid->vl_vbpd + vid->vl_row) |
v_LINE_FLAG_INTR_EN(0);
lcdc_msk_reg(lcdc_dev, INTR_CTRL0, msk, val);
lcdc_cfg_done(lcdc_dev);
if ((vid->screen_type == SCREEN_LVDS) ||
(vid->screen_type == SCREEN_DUAL_LVDS) ||
(vid->screen_type == SCREEN_RGB)) {
rk32_lvds_en(vid);
}
return 0;
}
/* Enable LCD and DIGITAL OUT in DSS */
void rk_lcdc_standby(int enable)
{
struct lcdc_device *lcdc_dev = &rk32_lcdc;
lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN,
v_STANDBY_EN(enable ? 1 : 0));
/*
#define v_STANDBY_EN(x) (((x)&1)<<22)
*/
lcdc_cfg_done(lcdc_dev);
}