Notes for debugging LCD based on msm8930 and orise

本文详细解读了MIPIDisplayProcessor(MDP)在更新流程中的关键步骤,包括ioctl调用、工作队列更新、overlay管道更新、颜色配置、时序引擎启动与中断处理,以及LCD开屏和关屏注意事项。同时,文章探讨了MIPIDisplayProcessor(MDP)在不同场景下的表现,如充电模式下快速suspend/resume导致的中断和dma异常问题,以及LCD背光测试方法和显示原理。此外,文章还提供了MIPIDisplayProcessor(MDP)与其他组件交互的实例,以及测试MIPISignal的方法和注意事项。

1  frame update

struct vsync_update {
	int update_cnt;	/* pipes to be updated */
	struct completion vsync_comp;
	struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
};

enum {
	OVERLAY_PIPE_VG1,	/* video/graphic */
	OVERLAY_PIPE_VG2,
	OVERLAY_PIPE_RGB1,
	OVERLAY_PIPE_RGB2,
	OVERLAY_PIPE_RGB3,
	OVERLAY_PIPE_VG3,
	OVERLAY_PIPE_VG4,
	OVERLAY_PIPE_MAX
};

enum {
	OVERLAY_TYPE_RGB,
	OVERLAY_TYPE_VIDEO,
	OVERLAY_TYPE_BF
};

enum {
	MDP4_MIXER0,
	MDP4_MIXER1,
	MDP4_MIXER2,
	MDP4_MIXER_MAX
};

enum {
	OVERLAY_PLANE_INTERLEAVED,
	OVERLAY_PLANE_PLANAR,
	OVERLAY_PLANE_PSEUDO_PLANAR
};

enum {
	MDP4_MIXER_STAGE_UNUNSED,	/* pipe not used */
	MDP4_MIXER_STAGE_BASE,
	MDP4_MIXER_STAGE0,	/* zorder 0 */
	MDP4_MIXER_STAGE1,	/* zorder 1 */
	MDP4_MIXER_STAGE2,	/* zorder 2 */
	MDP4_MIXER_STAGE3,	/* zorder 3 */
	MDP4_MIXER_STAGE_MAX
};

enum {
	MDP4_FRAME_FORMAT_LINEAR,
	MDP4_FRAME_FORMAT_ARGB_TILE,
	MDP4_FRAME_FORMAT_VIDEO_SUPERTILE
};

enum {
	MDP4_CHROMA_RGB,
	MDP4_CHROMA_H2V1,
	MDP4_CHROMA_H1V2,
	MDP4_CHROMA_420
};

static struct vsycn_ctrl {
	struct device *dev;
	int inited;
	int update_ndx;
	int ov_koff;
	int ov_done;
	atomic_t suspend;
	atomic_t vsync_resume;
	int wait_vsync_cnt;
	int blt_change;
	int blt_free;
	int blt_ctrl;
	int sysfs_created;
	struct mutex update_lock;
	struct completion ov_comp;
	struct completion dmap_comp;
	struct completion vsync_comp;
	spinlock_t spin_lock;
	struct msm_fb_data_type *mfd;
	struct mdp4_overlay_pipe *base_pipe;
	struct vsync_update vlist[2];
	int vsync_irq_enabled;
	ktime_t vsync_time;
} vsync_ctrl_db[MAX_CONTROLLER];

struct mdp4_overlay_ctrl {
	struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
	struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
	struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX];
	struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
	uint32 mixer_cfg[MDP4_MIXER_MAX]; // mixer:混合器(名词); blend:混合(动词)
	uint32 flush[MDP4_MIXER_MAX];
	struct iommu_free_list iommu_free[MDP4_MIXER_MAX];
	uint32 dmap_cfg[5];
	uint32 cs_controller;
	uint32 panel_3d;
	uint32 panel_mode;
	uint32 mixer0_played;
	uint32 mixer1_played;
	uint32 mixer2_played;
} mdp4_overlay_db = {
	.cs_controller = CS_CONTROLLER_0,
	.plist = {
		{
			.pipe_type = OVERLAY_TYPE_RGB,
			.pipe_num = OVERLAY_PIPE_RGB1, // 2
			.pipe_ndx = 1,
		},
		{
			.pipe_type = OVERLAY_TYPE_RGB,
			.pipe_num = OVERLAY_PIPE_RGB2, // 3
			.pipe_ndx = 2,
		},
		{
			.pipe_type = OVERLAY_TYPE_VIDEO,
			.pipe_num = OVERLAY_PIPE_VG1, // 0
			.pipe_ndx = 3,
		},
		{
			.pipe_type = OVERLAY_TYPE_VIDEO,
			.pipe_num = OVERLAY_PIPE_VG2, // 1
			.pipe_ndx = 4,
		},
		{
			.pipe_type = OVERLAY_TYPE_BF,
			.pipe_num = OVERLAY_PIPE_RGB3, // 4, mixer0
			.pipe_ndx = 5,
			.mixer_num = MDP4_MIXER0,
		},
		{
			.pipe_type = OVERLAY_TYPE_BF,
			.pipe_num = OVERLAY_PIPE_VG3, // 5, mixer1
			.pipe_ndx = 6,
			.mixer_num = MDP4_MIXER1,
		},
		{
			.pipe_type = OVERLAY_TYPE_BF,
			.pipe_num = OVERLAY_PIPE_VG4, // 6, mixer2
			.pipe_ndx = 7,
			.mixer_num = MDP4_MIXER2,
		},
	},
};

static DEFINE_MUTEX(iommu_mutex);
static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db;


The registers of Mobile Display Processor(MDP) are accessible by ARM CPU through the Peripheral Bus AHB interface. For read accesses, the number of cycles before data is available is variable depending on the register being read.

ARM registers:

NOTE: RGB3 and Video/Graphics3 Pipe are used for the border color feature in LM. These two registers don't have fetch logic and just provide a solid background color for LM 0/1.

MDP ARM register grouping:

Global general operation

Interrupts

EBI2 LCD parameters

MDDI parameters

DSI 1 command mode parameters(ID_MAP and TRIGGER_EN)

DSI 2 command mode parameters

Internal Memory Chip Select control register

Synchronization registers (VSYNC_CLK, MDP_CLK)

MGEN2MAXI control registers

    Client0 - VG1 read, Client1 - VG2 read, Client2 - RGB1 read, Client3 - RGB2 read, Client4 - DMA_P Image read, Client5 - DMA_P Cursor read, Client6 - DMA_S read, Client7 - DMA_E Image read, Client8 - DMA_E Cursor read, Client9 - Overlay0 write, Client10 -Overlay1 write

Overlay processor registers (Layer Mixer0, Layer Mixer1, V/G1 pipe, V/G2 pipe, RGB1/2/3 pipe, V/G3 pipe, Layer mixer2)

Primary Display Driver Settings

Secondary Display Driver Settings

External Display Driver Settings

DSI2 Video Mode/LCDC Timing Generator

DTV  Timing Generator

DSI1 Video Mode/LCDC Timing Generator

Test Bus and MISR Access(MDP_CLK, HCLK, DCLK, TV_CLK, DSI_PCLK, AXI_CLK)


log:

[    1.287715] mipi_global_lcd_probe: enter
[    1.288631] mipi_global_lcd_probe: enter
[    1.288814] setting pdata->panel_info.fb_num to 3. type: 8
[    1.320952] FrameBuffer[0] 540x960 size=6266880 bytes is registered successfully!
[    1.322600] mipi_global_lcd_probe: exit
[    1.323882] setting pdata->panel_info.fb_num to 1. type: 10
[    1.324462] Inside writeback_driver_init
[    1.325103] Inside writeback_probe
[    1.327239] FrameBuffer[1] 1280x720 size=0 bytes is registered successfully!
[    1.330749]
[    1.330779]  msm_vidc_enc: Inside vid_enc_init()
[    1.332031]
[    1.332031]  msm_vidc_enc: Inside vid_enc_vcd_init()

----------------------------------probe--------------------顺序为:

c0d68278 t __initcall_msm_fb_init6
c0d6827c t __initcall_mdp_driver_init6
c0d68280 t __initcall_mipi_dsi_driver_init6
c0d68284 t __initcall_mipi_video_mipi_global_wvga_pt_init6
c0d68288 t __initcall_writeback_panel_init6
c0d6828c t __initcall_writeback_driver_init6
c0d68290 t __initcall_vidc_init6
c0d68294 t __initcall_vid_dec_init6
c0d68298 t __initcall_vid_enc_init6
c0d6829c t __initcall_vfb_init6
c0d682a0 t __initcall_pty_init6
c0d682a4 t __initcall_sysrq_init6
c0d682a8 t __initcall_smux_init6
c0d682ac t __initcall_smux_ctl_init6
c0d682b0 t __initcall_msm_serial_hs_init6
c0d682b4 t __initcall_msm_serial_hsl_init6
c0d682b8 t __initcall_rand_initialize6
c0d682bc t __initcall_msm_rng_init6
c0d682c0 t __initcall_msm_rotator_init6

-------------------------------------end--------------

lcd on:

[    9.747047] mipi_global_lcd_on: lcd begin to open, cmds = 147
[    9.917106] mipi_global_lcd_on: lcd has opened successfully.
[    9.922661] ....................alloc count = 4, mixer:0,pipe.mixer_num:0, ptype:0, pipe index:1, type:0
[    9.922722] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x20000, srcp0_ystride:2176
[    9.922722] mdp4_overlayproc_cfg:-----------------directout mode
[   10.067083] ....................alloc count = 5, mixer:0,pipe.mixer_num:0, ptype:2, pipe index:5, type:2
[   10.145093] mdp4_dsi_video_pipe_commit:----------- pipe->ov_blt_addr is ZERO

[   10.739722] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   11.190019] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   11.391942] ....................alloc count = 6, mixer:0,pipe.mixer_num:0, ptype:0, pipe index:1, type:0
[   11.415992] mdp4_overlay_play:............1.............srcp0_addr:0x700000, srcp0_ystride:2176
[   11.425789] mdp4_overlay_play:............2.............srcp0_addr:0x700000, srcp0_ystride:2176
[   11.435464] mdp4_overlay_mdp_perf_upd mdp clk is changed [1] from 0 to 59080000
[   11.459209] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   11.465344] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x700000, srcp0_ystride:2176
[   11.490767] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   11.523546] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   11.615351] mdp4_overlay_play:............1.............srcp0_addr:0x900000, srcp0_ystride:2176
[   11.632137] mdp4_overlay_play:............2.............srcp0_addr:0x900000, srcp0_ystride:2176
[   11.641141] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   11.648130] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x900000, srcp0_ystride:2176
[   11.670685] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   11.690340] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   11.876972] mdp4_overlay_play:............1.............srcp0_addr:0x700000, srcp0_ystride:2176
[   11.885914] mdp4_overlay_play:............2.............srcp0_addr:0x700000, srcp0_ystride:2176

[   11.947169] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   11.953334] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x700000, srcp0_ystride:2176
[   11.967251] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   11.973844] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   12.140149] pil_get: 'q6' depends_on = 'none', count: 10
[   12.146497] apr_tal: SMD_EVENT_OPEN
[   12.180741] mdp4_overlay_play:............1.............srcp0_addr:0x900000, srcp0_ystride:2176
[   12.199999] mdp4_overlay_play:............2.............srcp0_addr:0x900000, srcp0_ystride:2176
[   12.208026] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   12.214832] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x900000, srcp0_ystride:2176
[   12.237356] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   12.257347] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   12.364718] mdp4_overlay_play:............1.............srcp0_addr:0x700000, srcp0_ystride:2176
[   12.389989] mdp4_overlay_play:............2.............srcp0_addr:0x700000, srcp0_ystride:2176
[   12.407172] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   12.413337] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x700000, srcp0_ystride:2176
[   12.427224] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   12.440805] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   12.569479] mdp4_overlay_play:............1.............srcp0_addr:0x900000, srcp0_ystride:2176
[   12.585197] mdp4_overlay_play:............2.............srcp0_addr:0x900000, srcp0_ystride:2176
[   12.616908] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   12.623195] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x900000, srcp0_ystride:2176
[   12.667205] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   12.674286] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video

[   12.759529] mdp4_overlay_play:............1.............srcp0_addr:0x700000, srcp0_ystride:2176
[   12.787242] mdp4_overlay_play:............2.............srcp0_addr:0x700000, srcp0_ystride:2176
[   12.795116] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   12.805127] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x700000, srcp0_ystride:2176
[   12.827224] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   12.841049] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   12.976957] mdp4_overlay_play:............1.............srcp0_addr:0x900000, srcp0_ystride:2176
[   12.989317] mdp4_overlay_play:............2.............srcp0_addr:0x900000, srcp0_ystride:2176
[   13.012757] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   13.027163] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x900000, srcp0_ystride:2176
[   13.035434] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   13.047428] mdp4_dsi_video_pipe_commit:----------- pipe->ov_blt_addr is ZERO
[   13.057836] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   13.092934] mdp4_overlay_play:............1.............srcp0_addr:0x700000, srcp0_ystride:2176
[   13.118022] mdp4_overlay_play:............2.............srcp0_addr:0x700000, srcp0_ystride:2176
[   13.125866] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   13.142377] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x700000, srcp0_ystride:2176
[   13.150801] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   13.174607] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   13.243125] mdp4_overlay_play:............1.............srcp0_addr:0x900000, srcp0_ystride:2176
[   13.267968] mdp4_overlay_play:............2.............srcp0_addr:0x900000, srcp0_ystride:2176
[   13.275965] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   13.283076] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x900000, srcp0_ystride:2176
[   13.309079] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   13.341370] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   13.360201] mdp4_overlay_play:............1.............srcp0_addr:0x700000, srcp0_ystride:2176
[   13.387273] mdp4_overlay_play:............2.............srcp0_addr:0x700000, srcp0_ystride:2176
[   13.395116] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   13.407111] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x700000, srcp0_ystride:2176
[   13.415443] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_iommu_pipe_free
[   13.458110] mdp4_dmap_done_dsi_video: ---------------------mdp4_dmap_done_dsi_video
[   13.466229] mdp4_overlay_play:............1.............srcp0_addr:0x900000, srcp0_ystride:2176
[   13.487227] mdp4_overlay_play:............2.............srcp0_addr:0x900000, srcp0_ystride:2176
[   13.495101] mdp4_dsi_video_pipe_commit:----------- mdp4_overlay_vsync_commit
[   13.507126] mdp4_overlay_rgb_setup:.........................srcp0_addr:0x900000, srcp0_ystride:2176


mdp 处理数据并update流程:

ioctl调用:

static int msmfb_display_commit(struct fb_info *info, unsigned long *argp) {
	int ret;
	struct mdp_display_commit disp_commit;
	ret = copy_from_user(&disp_commit, argp, sizeof(disp_commit));
	if (ret) {
		pr_err("%s:copy_from_user failed", __func__);
		return ret;
	}

	ret = msm_fb_pan_display_ex(info, &disp_commit);

	return ret;
}

msm_fb_pan_display_ex() -> schedule_work(&mfd->commit_work);


a. INIT_WORK(&mfd->commit_work, msm_fb_commit_wq_handler);  // 通过这个工作队列更新

b. 通过调用mdp4_overlay_commit

if (fb_backup->disp_commit.flags & MDP_DISPLAY_COMMIT_OVERLAY) {  
    mdp4_overlay_commit(info);  
}

mdp4_overlay_mdp_perf_upd(mfd, 1); // Implementation, as follow:  
mdp_set_core_clk(perf_req->mdp_clk_rate); // 设置core时钟:mdp_clk_rate  
mdp_bus_scale_update_request(...);   // bandwidth update  
if ((mfd->panel_info.pdest == DISPLAY_1 &&  // use_ov_blt isn't used 
		perf_req->use_ov_blt[0] && !perf_cur->use_ov_blt[0])) {
	if (mfd->panel_info.type == MIPI_VIDEO_PANEL)  
                mdp4_dsi_video_blt_start(mfd);
}

c. 对于video panel调用以下的case

case MIPI_VIDEO_PANEL:  
        mdp4_dsi_video_pipe_commit(0, 1);  
        break;

d. mdp4_overlay_vsync_commit

for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {  
        if (pipe->pipe_used) {  
            cnt++;  
            real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);  
            if (real_pipe && real_pipe->pipe_used) {  
                /* pipe not unset */  
                mdp4_overlay_vsync_commit(pipe);  // 这个小函数非常重要,提交了需要更新的framebuffer,下面具体分析此函数  
            }  
            /* free previous iommu to freelist which will be freed at next pipe_commit */  
            mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);  
            pipe->pipe_used = 0; /* clear */  
        }  
    }

(1) Implementation: mdp4_overlay_vsync_commit 

void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe)  
{  
    if (pipe->pipe_type == OVERLAY_TYPE_VIDEO)  
        mdp4_overlay_vg_setup(pipe);    /* video/graphic pipe */  
    else  
        mdp4_overlay_rgb_setup(pipe);   /* rgb pipe 对于UI一般情况下就是rgb pipe了 */  
  
    pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,  
        (int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);  
    mdp4_overlay_reg_flush(pipe, 1);
    mdp4_mixer_stage_up(pipe, 0);
}

(2) Implementation:mdp4_overlay_rgb_setup

void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe)  
{  
    char *rgb_base;  
    uint32 src_size, src_xy, dst_size, dst_xy;  
    uint32 format, pattern;  
    uint32 curr, mask;  
    uint32 offset = 0;  
    int pnum;  
  
    pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1; /* start from 0 */  
    rgb_base = MDP_BASE + MDP4_RGB_BASE;  
    rgb_base += (MDP4_RGB_OFF * pnum);  
  
    src_size = ((pipe->src_h << 16) | pipe->src_w);  
    src_xy = ((pipe->src_y << 16) | pipe->src_x);  
    dst_size = ((pipe->dst_h << 16) | pipe->dst_w);  
    dst_xy = ((pipe->dst_y << 16) | pipe->dst_x);  
  
    if ((pipe->src_x + pipe->src_w) > 0x7FF) {  
        offset += pipe->src_x * pipe->bpp;  
        src_xy &= 0xFFFF0000;  
    }  
  
    if ((pipe->src_y + pipe->src_h) > 0x7FF) {  
        offset += pipe->src_y * pipe->src_width * pipe->bpp;  
        src_xy &= 0x0000FFFF;  
    }  
  
    format = mdp4_overlay_format(pipe);  
    pattern = mdp4_overlay_unpack_pattern(pipe);  
  
    mdp4_scale_setup(pipe);  
  
    mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);  
  
    /* Ensure proper covert matrix loaded when color space swaps */  
    curr = inpdw(rgb_base + 0x0058);  
    /* Don't touch bits you don't want to configure*/  
    mask = 0xFFFEFFFF;  
    pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask);  
  
    outpdw(rgb_base + 0x0000, src_size);    /* MDP_RGB_SRC_SIZE */  
    outpdw(rgb_base + 0x0004, src_xy);  /* MDP_RGB_SRC_XY */  
    outpdw(rgb_base + 0x0008, dst_size);    /* MDP_RGB_DST_SIZE */  
    outpdw(rgb_base + 0x000c, dst_xy);  /* MDP_RGB_DST_XY */  
  
    outpdw(rgb_base + 0x0010, pipe->srcp0_addr + offset);// 对应于源地址,传到寄存器中  
    outpdw(rgb_base + 0x0040, pipe->srcp0_ystride);// 这里需要进一步打印出地址再进一步确认和overlay_play中如何控制?  
  
    outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */  
    outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */  
    if (format & MDP4_FORMAT_SOLID_FILL) {  
        u32 op_mode = pipe->op_mode;  
        op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);  
        op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);  
        outpdw(rgb_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */  
    } else {  
        if (pipe->op_mode & MDP4_OP_FLIP_LR && mdp_rev >= MDP_REV_42) {  
            /* Enable x-scaling bit to enable LR flip */  
            /* for MDP > 4.2 targets */  
            pipe->op_mode |= 0x01;  
        }  
        outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */  
    }  
    outpdw(rgb_base + 0x005c, pipe->phasex_step);  
    outpdw(rgb_base + 0x0060, pipe->phasey_step);  
  
    mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);  
  
    mdp4_stat.pipe[pipe->pipe_num]++;  
}

e. 启动时序引擎

/* start timing generator & mmu if they are not started yet */  
    mdp4_overlay_dsi_video_start(); // 启动dsi video 控制

f. 使能中断位,DMA_P_DONE

if (pipe->ov_blt_addr) {   // 这个addr 默认未使用所以走else分支,所以只打开了DMA_P_DONE中断  
        mdp4_dsi_video_blt_ov_update(pipe);  
        pipe->ov_cnt++;  
        INIT_COMPLETION(vctrl->ov_comp);  
        vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);  
        mb();  
        vctrl->ov_koff++;  
        /* kickoff overlay engine */  
        mdp4_stat.kickoff_ov0++;  
        outpdw(MDP_BASE + 0x0004, 0);  
    }  else {  
        /* schedule second phase update  at dmap */  
        INIT_COMPLETION(vctrl->dmap_comp);  
        vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);  // enable INTR_DMA_P_DONE(DMA_P Transfer done)  
    }

static void vsync_irq_enable(int intr, int term)  
{  
    unsigned long flag;  
  
    spin_lock_irqsave(&mdp_spin_lock, flag);  
    outp32(MDP_INTR_CLEAR, intr);  
    mdp_intr_mask |= intr;  
    outp32(MDP_INTR_ENABLE, mdp_intr_mask);  
    mdp_enable_irq(term);  
    spin_unlock_irqrestore(&mdp_spin_lock, flag);  
    pr_debug("%s: IRQ-en done, term=%x\n", __func__, term);  
}

h. 中断,一个是vsync,一个是dmap done 

if (isr & INTR_PRIMARY_VSYNC) {  
        mdp4_stat.intr_vsync_p++;  
        if (panel & MDP4_PANEL_LCDC)  
            mdp4_primary_vsync_lcdc();  
        else if (panel & MDP4_PANEL_DSI_VIDEO)  
            mdp4_primary_vsync_dsi_video();  
    }


if (isr & INTR_DMA_P_DONE) {  
        mdp4_stat.intr_dma_p++;  
        dma = &dma2_data;  
        if (panel & MDP4_PANEL_LCDC)  
            mdp4_dmap_done_lcdc(0);  
        else if (panel & MDP4_PANEL_DSI_VIDEO)  
            mdp4_dmap_done_dsi_video(0); 
}

2  LCD resume time

  1. 537.952815</span>] request_suspend_state: wakeup (3->0) at 537941084255 (2013-05-27 10:53:03.049466690 UTC)
  2. [  537.962307] get_prop_batt_temp: batt_temp phy = 312 meas = 0xc02b17ecec479268
  3. [  537.972256] report_state_of_charge: calculated_soc = 73,last_soc = 73,start_percent = -22,charge_time_us = 0,catch_up_time_us = 0
  4. [  538.007202] =====enter in rmi_f01_resume=====
  5. [  538.031893] report_state_of_charge: Reported SOC = 73
  6. [  538.063360] get_prop_batt_ocv: get_prop_batt_ocv:ocv_uv =3910136,ibatt_ua =329800.
  7. [  538.064703] get_prop_batt_temp: batt_temp phy = 314 meas = 0xecc33000
[  538.131878] mipi_global_lcd_on: ready for opening lcd

  1. [  538.312559] mipi_global_lcd_on: lcd is on, count = 147 
  2. [  538.365298] mdp4_overlay_mdp_perf_upd mdp clk is changed [1] from 0 to 59080000

  3. 按照log可以发现从请求wakeup到lcd on大概花费了360ms,所以开屏的过程还是比较慢的,这里还没计算再次打开背光的时间,这个也要通过mipi发给LCD(lcd提供背光的话)。而主要的停留是在mipi lcd on cmds的低速发送上等待时间比较长,这个dma搬运的时间持续了180ms,不过这里有147条开屏的cmds要通过mipi发给lcd,所以dma搬运的过程肯定会消耗不少时间。
  1. [  594.616419] mipi_global_lcd_off: ready for closing lcd
  2. [  594.837784] mipi_global_lcd_off: lcd is off, count = 2
  3. [  594.891255] request_suspend_state: sleep (0->3) at 594875256577 (2013-05-27 11:10:12.737098649 UTC)
  4. [  594.899893] =====enter in rmi_f01_suspend===== 
  5. [  597.610926] PM: suspend entry 2013-05-27 11:10:15.456769024 UTC

从log可以发现从LCD off到LCD完成off花费了220ms,这命令比LCD on的时间更长,现在原因还不太确定。不过总的来说LCD 的开屏和关屏时间还是比较长。所以在开屏和关屏期间需要注意背光的控制不能在开屏过程或者关屏过程进行!


Bug如下:

------ watchdog state ------

  1. [!!!!] Read b3af1000 from IMEM successfully!
  2. [!!!!] An FIQ occured on the system!
  3. running dump version 1
  4. Core 0 PC: mipi_dsi_isr+3c <c03026e4>
  5. Core 0 LR: uncached_logk_pc+20 <c007d8e8>

  6. [<c03026e4>] mipi_dsi_isr+0x3c
  7. [<c00d4798>] handle_irq_event_percpu+0xb0
  8. [<c00d49b4>] handle_irq_event+0x3c
  9. [<c00d75a0>] handle_fasteoi_irq+0xdc
  10. [<c00d3ffc>] generic_handle_irq+0x30
  11. [<c000efb0>] handle_IRQ+0x7c
  12. [<c00085b8>] gic_handle_irq+0x94
  13. [<c080aa40>] __irq_svc+0x40
  14. [<c0088184>] __do_softirq+0x4c
  15. [<c00887b0>] irq_exit+0x48
  16. [<c000efb4>] handle_IRQ+0x80
  17. [<c00085b8>] gic_handle_irq+0x94
  18. [<c080aa40>] __irq_svc+0x40
  19. [<c080a674>] _raw_spin_unlock_irqrestore+0x10
  20. [<c03c3d40>] pm8xxx_get_irq_stat+0x134
  21. [<c0550f14>] pm_chg_get_rt_status+0x34
  22. [<c0555590>] unplug_check_worker+0x70
  23. [<c009a950>] process_one_work+0x27c
  24. [<c009acf8>] worker_thread+0x1a0
  25. [<c009ec80>] kthread+0x80
  26. [<c000f130>] kernel_thread_exit+0x0

  27. Core 1 PC: go_wfi+4 <c0024a88>
  28. Core 1 LR: msm_pm_idle_enter+68 <c0057194>

  29. [   62.812635] mdp4_mixer_blend_setup: Error: no bg_pipe at mixer=0
  30. [   63.244925] setup_clocks: Failed to set fs_mdp tv_src_clk rate to 0 Hz.
  31. [   63.250602] fs_mdp: failed to disable
  32. [   63.531176] mipi_dsi_ahb_ctrl: ahb clks already ON
  33. [   63.537097] mipi_dsi_clk_enable: mipi_dsi_clks already ON 
  34. [   63.741126] mipi_dsi_cmd_dma_tx: dma timeout error  
  35. [   63.981168] mipi_dsi_cmd_dma_tx: dma timeout error
  36. [   64.181138] mipi_dsi_cmd_dma_tx: dma timeout error

  37. Bug 引起的根源是在充电模式下,直接调用了写文件的方式来让kernel suspend/resume,然后suspend和resume的切换又非常快导致suspend未完全结束,resume又开始执行,所以导致了中断、dsi dma异常,有些地方触摸屏也异常,很明显这里应该利用通知的方式等待系统完成suspend或者resume,才再次切换到下一种状态!

3  LCD点亮注意事项


1. phy参数(高通提供了计算相应数值的excel,所以只要按照它那个再填进来即可,大部分数值按照原先数值即可):

2. 高通DTYPE_DCS_WRITE这个0x05有写失败的场景,需要注意,所以最好都使用DTYPE_DCS_LWRITE

3. LCD 示波器背光测试(PWM由LCD输出波形如下所示,占空比为50%,波形为各占50%,高电平为1.8V,低电平为0V,100%为完全1.8V高电平),需要连接LCD后才能很好的测试。ORISE可通过开关CABC这个功能来选择省电。若开CABC,将会导致背光设为100%后,实际背光达不到100%。

4. frame rate 60Hz, 对于mipi接口又是如何,如下图所示:(1格的时间间隔是2ms



通过波形可以发现发完一帧,mipi会切换状态到low power mode,状态的变换细节等有空再仔细分析。注意高速和低速信号的swing

5. 几个tips,关于TFT lcd
a.  图像显示的偏色可能和背光灯的颜色有关系
b. 输出给LCD背光灯电压较大,我们平台为30V,所以额外需要IC来驱动
c. LCD灰阶分成一定等分,并给定相应的电压,如分成255
d. LCD显示效果起决定性因素的还是玻璃
e. LCD也需要调整白平衡
f. 平板电脑可能是由多个IC驱动LCD modules,通常经过一个时序IC来控制多个IC的输出顺序
g. porch的大小可能会影响LCD的flicker,同时porch的增加会增加mipi的带宽
h. OLED自发光,不再需要外围背光驱动,更省电
i. LCD驱动IC 使用command mode会节省主控CPU的消耗,但是这样的IC成本会提高,因为增加了ram,增加了面积,也增加了芯片的成本 

6. LCD 显示原理,如下图:






4  screenshot

Method 1

#1: adb shell

#2: adb root

#3: screencap -p /data/xxx.png

#4: adb pull /data/xxx.png Your_pc_workspace

Method 2

If You're Running Ice Cream Sandwich (4.0) and Above

If you have a shiny new phone with Ice Cream Sandwich or above, screenshots are built right into your phone! Just press the Volume Down and Power buttons at the same time, hold them for a second, and your phone will take a screenshot. It'll show up in your Gallery app for you to share with whomever you wish!

5  Test MIPI Signal

1)  测试的引脚一定要注意选择一个便于测试的引脚来测试,这个引脚可能是在一个相连的元器件的一端,比如某个电阻、电容、二极管、或者其他小芯片的某个引脚的非接地端;

2 )  MIPI信号的低速数据可以通过读的方式来读出数据或者可以通过发送的低速波形来读数据,不过要注意读出的数据为以下字节序(orise9605a, 小字节序),比如0x51,发送的波形为1000_1010,由于波形中含有协议部分的其他字节,另外要注意发送是LWRITE还是WRITE,如果是LWRITE的话,将是0x39,长包的格式比短包多一些;如果是WRITE的话,将是0x13,也就是0'b1100_1000,我们观察波形来验证我所说的是否是正确的:


发现0x51和0x13了么?OK,根据这个波形,证明结果是符合预期的。


3)  示波器的使用normal模式一般作为触发;auto模式一般作为持续更新;

4)HS swing / LP swing

5)  注意调节触发方式,从而将能保证触发刚好到达你所需要的波形处;

6)orise driver ic应该在LP00或者LP11时进行reset,并且拉高后需要保持一段时间,其他状态下driver ic行为可能异常;

如果复位发生在LP11然后后面出现类似于高速的信号,可能会使driver IC行为异常,但是波形却无法看出时序有任何问题,如下图所示:



上图中clock and data lane同时出现了一个类似电容放电的波形,这里可能是phy的复位,此过程根据系统延时时间会略有不同,一般15ms左右,下面一副图看起来更加标准一些,不过这个曲线看起来有点华丽,所以失去了真实。下面我们继续讨论复位后的行为,根据上图,我们可以看到数据线上有许多稀疏的拉到0的或者密集的拉到0的波形,实际上当展开后,你将发现密集的往往中间将会是高速信号,而稀疏的可能是vsync或者低速cmd信号。


回到主题的内容,既然这里有个持续15ms左右的200mV脉冲,那我们的reset位置放在何处比较好呢?由于此波形是从lk跳转到kernel的情形,复位前data和clock lane的状态为LP11,当phy复位时data线和clock线同时被拉到200mV,看起来200mV是pmos放电无法到GND的结果,假设把lcd driver IC复位放在这个phy复位前,发现一个严重的问题,就是这个时候让driver IC勿认为当前host请求进入了高速,driver IC也进入high speed mode,由于后面还需要给driver IC发送on cmd,这些on cmd有两种:1种可以在高速模式下发送,也就是cmd1,;还一种一般是在低速模式下发送,这种只有单个命令的指令在高速下发送才可以成功,有多个parameter的指令都无法发送成功。而当前driver IC处在它自己认为的高速状态(实际只是host端的phy复位信号),导致了cmd2的多个parameter的cmd发送无法成功,从而进一步将会导致首次lcd无法正常显示图像,此种复位波形如下:


GREEN: Reset Signal          Yellow:Data Lane

根据这个波形可以发现,其实host端已经将所有的cmd发送给了driver IC,只是driver勿认了当前的时序,导致cmd无法被成功执行;既然这样会导致这个问题,那我们干脆不去复位不是就可以了,如果从可以工作来说这样做,确实可以使首次lcd被点亮,但是其实这样也是有问题的,因为首次的cmd始终没有被正常发送给driver IC,所以如果前一次lk的cmds和kernel中cmds不完全匹配或者几乎不一致也会导致显示画面效果不是你想要得效果,所以这样做依然是有风险的,最好的方式就是把复位推后到host phy复位完成后,实际测试下来这种方式是最理想的效果,如下图所示:


sleep in -> sleep out


lk -> kernel

现在可以发现复位信号到了host phy复位后,cmds的发送也相应的推后了,实测这种方式能较好的工作,测试中还发现了一个问题,目前还没完全分析出来,那就是host端复位的实际时机,比如我们观察以下的波形可以一个有趣的现象,观察波形我们可以发现driver IC的复位刚好在host端phy的复位波形中,如图:


It's fun.


7)避免lcd在从bootloader切换到kernel闪屏的一种有效的办法是先发背光为0(如果lcd当前为开的情况下);

8)仔细分析波形,并理解时序,不放过每一个可能的细节。


















                
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值