---恢复内容开始---

1  lcd probe

The probe sequence is determined by compilation sequence:
mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o #
mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
mdss-mdp-objs += mdss_mdp_pp.o
mdss-mdp-objs += mdss_mdp_intf_video.o
mdss-mdp-objs += mdss_mdp_intf_cmd.o
mdss-mdp-objs += mdss_mdp_intf_writeback.o
mdss-mdp-objs += mdss_mdp_rotator.o
mdss-mdp-objs += mdss_mdp_overlay.o
mdss-mdp-objs += mdss_mdp_wb.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o ifeq ($(CONFIG_FB_MSM_MDSS),y)
obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
endif dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o dsi_panel_v2.o #: dsi_host_v2, #: dsi_panel_v2
obj-$(CONFIG_FB_MSM_MDSS) += dsi-v2.o mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
mdss-dsi-objs += mdss_dsi_panel.o
mdss-dsi-objs += msm_mdss_io_8974.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_edp.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_edp_aux.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_io_util.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o #
c0ace4b4 t __initcall_iommu_init4
c0ace4b8 t __initcall_msm_iommu_init4
c0ace4bc t __initcall_msm_iommu_driver_init4
 
c0ace7d0 t __initcall_percpu_counter_startup6
c0ace7d4 t __initcall_dynamic_debug_init_debugfs6
c0ace7d8 t __initcall_qpnp_pin_init6
c0ace7dc t __initcall_mdp3_driver_init6  // (1)
c0ace7e0 t __initcall_mdss_mdp_driver_init6 // (2)
c0ace7e4 t __initcall_msm_dsi_v2_driver_init6 // (3)
c0ace7e8 t __initcall_dsi_panel_module_init6 // (4)
c0ace7ec t __initcall_mdss_dsi_driver_init6 // (5)
c0ace7f0 t __initcall_mdss_dsi_panel_init6 // (6)
c0ace7f4 t __initcall_mdss_edp_init6
c0ace7f8 t __initcall_mdss_wb_driver_init6
c0ace7fc t __initcall_mdss_fb_init6
c0ace800 t __initcall_pty_init6
c0ace804 t __initcall_sysrq_init6
c0ace808 t __initcall_msm_serial_hsl_init6
c0ace80c t __initcall_rand_initialize6
c0ace810 t __initcall_msm_rng_init6
c0ace814 t __initcall_diagchar_init6
c0ace818 t __initcall_ion_page_pool_init6
c0ace81c t __initcall_kgsl_core_init6
c0ace820 t __initcall_kgsl_3d_init6
c0ace824 t __initcall_kgsl_2d_init6
c0ace828 t __initcall_topology_sysfs_init6
c0ace82c t __initcall_brd_init6
c0ace830 t __initcall_loop_init6
c0ace834 t __initcall_qseecom_init6
c0ace838 t __initcall_wcd9xxx_init6
c0ace83c t __initcall_pn544_dev_init6
c0ace840 t __initcall_msm_spi_init6
c0ace844 t __initcall_dummy_init_module6

c0aa87dc t fbmem_init drivers/video/fbmem.c
c0aa888c t video_setup 
drivers/video/fbmem.c
c0aa8938 t backlight_class_init 
drivers/video/backlight/backlight.c
c0aa89a8 t mdp3_driver_init 
drivers/video/msm/mdss/mdp3.c
c0aa89dc t mdss_mdp_driver_init 
drivers/video/msm/mdss/mdss_mdp.c
c0aa8a10 t msm_dsi_v2_driver_init drivers/video/msm/mdss/dsi_host_v2.c
c0aa8a3c t dsi_panel_module_init 
drivers/video/msm/mdss/dsi_panel_v2.c
c0aa8a48 t mdss_dsi_driver_init 
drivers/video/msm/mdss/mdss_dsi.c
c0aa8a74 t mdss_dsi_panel_init 
drivers/video/msm/mdss/mdss_dsi_panel.c
c0aa8a80 t mdss_edp_init 
drivers/video/msm/mdss/mdss_edp.c
c0aa8ab4 t mdss_wb_driver_init 
drivers/video/msm/mdss/mdss_wb.c
c0aa8ac0 T mdss_fb_init drivers/video/msm/mdss/mdss_fb.c
c0aa8ae0 t regulator_init drivers/regulator/core.c
c0aa8b60 t regulator_init_complete drivers/regulator/core.c
c0aa8ca4 T regulator_dummy_init drivers/regulator/dummy.c
c0aa8d2c T regulator_stub_init drivers/regulator/stub-regulator.c
c0aa8d5c T qpnp_regulator_init drivers/regulator/qpnp-regulator.c
c0aa8e04 t tty_class_init drivers/tty/tty_io.c
c0aa8e48 T console_init drivers/tty/tty_io.c
c0aa8e78 T tty_init drivers/tty/tty_io.c
c0aa8fbc t pty_init drivers/tty/pty.c

2  splash screen(boot from lk to kernel)

3  mdp3 dma and control

3.1 mdp3 control interface

int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
struct msm_mdp_interface *mdp3_interface = &mfd->mdp;
struct mdp3_session_data *mdp3_session = NULL;
u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
int rc; pr_debug("mdp3_ctrl_init\n");
mdp3_interface->on_fnc = mdp3_ctrl_on;
mdp3_interface->off_fnc = mdp3_ctrl_off;
mdp3_interface->do_histogram = NULL;
mdp3_interface->cursor_update = NULL;
mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
mdp3_interface->lut_update = mdp3_ctrl_lut_update; mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
if (!mdp3_session) {
pr_err("fail to allocate mdp3 private data structure");
return -ENOMEM;
}
memset(mdp3_session, , sizeof(struct mdp3_session_data));
mutex_init(&mdp3_session->lock);
INIT_WORK(&mdp3_session->vsync_work, mdp3_dispatch_vsync);
mutex_init(&mdp3_session->histo_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
if (!mdp3_session->dma) {
rc = -ENODEV;
goto init_done;
} rc = mdp3_dma_init(mdp3_session->dma);
if (rc) {
pr_err("fail to init dma\n");
goto init_done;
} intf_type = mdp3_ctrl_get_intf_type(mfd);
mdp3_session->intf = mdp3_get_display_intf(intf_type);
if (!mdp3_session->intf) {
rc = -ENODEV;
goto init_done;
}
rc = mdp3_intf_init(mdp3_session->intf);
if (rc) {
pr_err("fail to init interface\n");
goto init_done;
} mdp3_session->dma->output_config.out_sel = intf_type;
mdp3_session->mfd = mfd;
mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
mdp3_session->status = ;
mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
mdp3_bufq_init(&mdp3_session->bufq_in);
mdp3_bufq_init(&mdp3_session->bufq_out);
mdp3_session->histo_status = ;
mdp3_session->lut_sel = ; init_timer(&mdp3_session->vsync_timer);
mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
mdp3_session->vsync_timer.data = (u32)mdp3_session;
mdp3_session->vsync_period = / mfd->panel_info->mipi.frame_rate;
mfd->mdp.private1 = mdp3_session; rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
if (rc) {
pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
goto init_done;
} kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n"); init_done:
if (IS_ERR_VALUE(rc))
kfree(mdp3_session); return rc;
}

mdp3_ctrl_init(msm_fb_data_type *) : int
|------mdp3_init(msm_fb_data_type *) : int
|------------ mdp3_probe(platform_device *) : int
|-------------------{init mdp3_driver}() : platform_driver

static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)  
msm_mdp_interface::on_fnc : int (*)(msm_fb_data_type *)
|------mdp3_ctrl_init(msm_fb_data_type *) : int
|------mdss_fb_blank_sub(int, fb_info *, int) : int (2 matches)
|||||||||-----mdss_fb_blank(int, fb_info *) : int
|||||||||------mdss_fb_open(fb_info *, int) : int
|||||||||------mdss_fb_release(fb_info *, int) : int
|||||||||------mdss_fb_resume_sub(msm_fb_data_type *) : int
|||||||||----- -mdss_fb_set_par(fb_info *) : int (2 matches)
|||||||||------mdss_fb_suspend_sub(msm_fb_data_type *) : int
|------mdss_fb_dcm(msm_fb_data_type *, int) : int (2 matches)
|------mdss_mdp_overlay_init(msm_fb_data_type *) : int
|------mdss_qpic_overlay_init(msm_fb_data_type *) : int
 
=========Flow===========
01) mdp iommu enable  ->
02) mipi dsi on(clk, porch, dsi host reset, init)  ->
03) mipi panel on(initial cmds) ->
04) mdp clk(core, vsync) enable ->
05) enable mdp irq ->
06) mdp dma config(interface: dma_config) ->
07) load ppp lut and csc matrix ->
08) config(intf, &cfg); ->
09) mdp3_fbmem_clear() ->
10) start dma_p(depending on video or command mode) For video mode, maybe the primary dma transfer is started automatically every vsync; For command mode, the corresponding register MMSS_MDP_DMA_P_START should be set to start a DMA_P channel transfer.
11)Now it's time to enable timing generation and kick start DSI_VIDEO operation: MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, BIT(0));

3.2 interface of dma

int mdp3_dma_init(struct mdp3_dma *dma)
{
int ret = ; pr_debug("mdp3_dma_init\n");
switch (dma->dma_sel) {
case MDP3_DMA_P:
dma->dma_config = mdp3_dmap_config;
dma->config_cursor = mdp3_dmap_cursor_config;
dma->config_ccs = mdp3_dmap_ccs_config;
dma->config_histo = mdp3_dmap_histo_config;
dma->config_lut = mdp3_dmap_lut_config;
dma->update = mdp3_dmap_update;
dma->update_cursor = mdp3_dmap_cursor_update;
dma->get_histo = mdp3_dmap_histo_get;
dma->histo_op = mdp3_dmap_histo_op;
dma->vsync_enable = mdp3_dma_vsync_enable;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
break;
case MDP3_DMA_S:
dma->dma_config = mdp3_dmas_config;
dma->config_cursor = NULL;
dma->config_ccs = NULL;
dma->config_histo = NULL;
dma->config_lut = NULL;
dma->update = mdp3_dmas_update;
dma->update_cursor = NULL;
dma->get_histo = NULL;
dma->histo_op = NULL;
dma->vsync_enable = mdp3_dma_vsync_enable;
dma->start = mdp3_dma_start;
dma->stop = mdp3_dma_stop;
break;
case MDP3_DMA_E:
default:
ret = -ENODEV;
break;
} spin_lock_init(&dma->dma_lock);
spin_lock_init(&dma->histo_lock);
init_completion(&dma->vsync_comp);
init_completion(&dma->dma_comp);
init_completion(&dma->histo_comp);
dma->vsync_client.handler = NULL;
dma->vsync_client.arg = NULL;
dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE; memset(&dma->cursor, , sizeof(dma->cursor));
memset(&dma->ccs_config, , sizeof(dma->ccs_config));
memset(&dma->histogram_config, , sizeof(dma->histogram_config)); return ret;
}
int mdp3_intf_init(struct mdp3_intf *intf)
{
switch (intf->cfg.type) {
case MDP3_DMA_OUTPUT_SEL_LCDC:
intf->config = lcdc_config;
intf->start = lcdc_start;
intf->stop = lcdc_stop;
break;
case MDP3_DMA_OUTPUT_SEL_DSI_VIDEO:
intf->config = dsi_video_config;
intf->start = dsi_video_start;
intf->stop = dsi_video_stop;
break;
case MDP3_DMA_OUTPUT_SEL_DSI_CMD:
intf->config = dsi_cmd_config;
intf->start = dsi_cmd_start;
intf->stop = dsi_cmd_stop;
break; default:
return -EINVAL;
}
return ;
}

4 mipi dsi host controll

5 mipi dsi panel controll

6 interface for userspace

7 Memory Management of multimedia of display

7.1 probe of mdss_fb

7.1.1 allocate struct msm_fb_data_type

[cpp] view plaincopyprint?
/*
* alloc framebuffer info + par data
*/
fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);

The main and large memory allocation is placed in mdss_fb_register.

fix->line_length = var->xres * bpp; 

7.1.2 Now it's time to allocate framebuffer memory, the function is mdss_fb_alloc_fbmem in mdss_fb_register.

static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{ if (mfd->mdp.fb_mem_alloc_fnc)
return mfd->mdp.fb_mem_alloc_fnc(mfd);
else if (mfd->mdp.fb_mem_get_iommu_domain) {
int dom = mfd->mdp.fb_mem_get_iommu_domain();
if (dom >= )
return mdss_fb_alloc_fbmem_iommu(mfd, dom);
else
return -ENOMEM;
} else {
pr_err("no fb memory allocator function defined\n");
return -ENOMEM;
}
}

Because the function pointer fb_mem_alloc_fnc is registered in mdp3_probe in mdp3.c,

.fb_mem_alloc_fnc = mdp3_fbmem_alloc,  

he above function will be called. The implementation is as below,

static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
{
int ret = -ENOMEM, dom;
void *virt = NULL;
unsigned long phys = ;
size_t size;
u32 yres = mfd->fbi->var.yres_virtual; size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
......
ret = mdp3_alloc(size, &virt, &phys);
......
dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx; ret = ion_map_iommu(mdp3_res->ion_client, mdp3_res->ion_handle,
dom, , SZ_4K, , &mfd->iova,
(unsigned long *)&size, , );
......
mfd->fbi->screen_base = virt;
mfd->fbi->fix.smem_start = phys;
mfd->fbi->fix.smem_len = size;
return ;
......
}
Function mdp3_alloc get ion_handle, virtuall address and physical address from ion.
Once the Ion heap is allocated in the kernel side, the client has the Ion handle. But the client would need the kernel virtual address to access the Ion buffer that is associated with the Ion handle. ion_map_kernel can be used for this purpose. The return value of ion_map_kernel is a virtual address that the kernel can read and write directly:

void *ion_map_kernel(struct ion_client *client, struct ion_handle  *handle, unsigned long flags);  

ion_phys returns the physical address of the Ion buffer associated with the Ion handle. The 12 ion_phys function type definition is shown below. Its output is only correct if the heap returns 13 physically contiguous memory. In other cases, this API should not be implemented.

int ion_phys(struct ion_client *client, struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len);  

The implementation of mdp3_alloc is as follow:

static int mdp3_alloc(size_t size, void **virt, unsigned long *phys)
{
int ret = ; if (mdp3_res->ion_handle) {
pr_debug("memory already alloc\n");
*virt = mdp3_res->virt;
*phys = mdp3_res->phys;
return ;
} mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
SZ_1M,
ION_HEAP(ION_QSECOM_HEAP_ID), ); if (!IS_ERR_OR_NULL(mdp3_res->ion_handle)) {
*virt = ion_map_kernel(mdp3_res->ion_client,
mdp3_res->ion_handle);
......
ret = ion_phys(mdp3_res->ion_client, mdp3_res->ion_handle,
phys, &size);
......
mdp3_res->virt = *virt;
mdp3_res->phys = *phys;
mdp3_res->size = size;
} else
......
return ;
......
return -ENOMEM;
}

Regarding to ion spec, the doc 80-N9225-1_D_Intro_Ion_APIs.pdf can be refered to. I pasted some introduces from this documents

int ion_map_iommu(struct ion_client *client, struct ion_handle *handle,
int domain_num, int partition_num, unsigned long align,
unsigned long iova_length, unsigned long *iova,
unsigned long *buffer_size,
unsigned long flags, unsigned long iommu_flags)

Domains 
A domain represents the IOMMU virtual memory space. Each domain has its own virtual memory space in the IOMMU map. Four domains are defined in MSM8960 Android BSP release 1711, which means each context bank of 12 IOMMUs in the MSM8960 should be mapped into one of the four virtual memory spaces. 
The number of domains and domain enumerations are located in the file arch/arm/mach-msm/include/mach/iommu_domains.h.

enum {
VIDEO_DOMAIN,
CAMERA_DOMAIN,
DISPLAY_DOMAIN,
ROTATOR_DOMAIN,
MAX_DOMAINS
};

When an Ion client requests IOMMU virtual→physical mapping, it must specify the domain to which the Ion client wants to draw the virtual→physical map; e.g., the MDP display driver specifies the DISPLAY_DOMAIN domain when it requests the IOMMU virtual map. The following code snippet is used:

ion_map_iommu(display_iclient, *srcp_ihdl, DISPLAY_DOMAIN, GEN_POOL, SZ_4K,  , start, len, , ION_IOMMU_UNMAP_DELAYED);  

Partitions

A partition is a virtual address window in a domain. Therefore, a different partition means a different virtual address window in the 4 GB memory space. When an Ion client requests virtual physical mapping, the client specifies the partition to which the client wants the virtual  memory address to belong. There are currently three partitions. Each one has the following virtual address window (start address and size): 
        VIDEO_FIRMWARE_POOL 32
        |----Virtual addr start = SZ_128K 33
        |----Size of virtual address window = SZ_16M to SZ_128K

VIDEO_MAIN_POOL 
        |----Virtual addr start = SZ_16M 
        |----Size of virtual address window = SZ_256M to SZ_16M

GEN_POOL 
        |----Virtual addr start = SZ_256M 
        |----Size of virtual address window = SZ_2G to SZ_256M

For example, the MSM8960 video core firmware loading address must be less than 16 MB from the video core perspective because of the hardware requirement. The following code is an example to ensure that the virtual address belongs to the required address range. Here, VIDEO_FIRMWARE_POOL is passed to the ion_map_iommu call to ensure the virtual address range. The number and enumeration of the partition are located in the file arch/arm/mach-msm/include/mach/iommu_domains.h.

ion_map_iommu(ddl_context->video_ion_client, addr- >alloc_handle, VIDEO_DOMAIN, VIDEO_FIRMWARE_POOL, SZ_4K,  , &iova, &buffer_size, UNCACHED, );  

7.1.3 Allocate struct msm_fb_back_type

mfd->msm_fb_backup = kzalloc(sizeof(struct msm_fb_backup_type),
GFP_KERNEL);

7.1.4 allocate cmap

ret = fb_alloc_cmap(&fbi->cmap, , );  

7.2 probe of mdp3

mdp3_res = devm_kzalloc(&pdev->dev, sizeof(struct mdp3_hw_resource), GFP_KERNEL);  
static int mdp3_res_init(void)
{
int rc = ; rc = mdp3_irq_setup();
<p> ......</p> rc = mdp3_clk_setup();
......
mdp3_res->ion_client = msm_ion_client_create(-, mdp3_res->pdev->name);
......
rc = mdp3_iommu_init();
......
mdp3_res->bus_handle = mdp3_bus_handle;
rc = mdp3_bus_scale_register();
......
rc = mdp3_hw_init(); return rc;
}

The kernel module creates a new client by calling ion_client_create. The function definition msm_ion_client_create is the wrapper function of the generic API ion_client_create:

struct ion_client *ion_client_create(struct ion_device *dev, unsigned int heap_mask, const char *name)   

heap_mask indicates the type of heap that this client should allocate from all of the different heap types such ascarveout, system heap, system contig, IOMMU, etc. Once the client is created, ion_alloc can be used to allocate the actual memory out of the heap. ion_alloc is defined as:

struct ion_handle *ion_alloc(struct ion_client,*client, size_t len, size_t align, unsigned int flags);  
Here, flags are telling which ion_heap_id should be assigned for this allocation. One client can call ion_alloc multimple times, which means a single client can have muiltiple memory chunks out of Ion heap. This requires ion_handle to be unique per each memory chunk.
 
ion_alloc isn't called until mdp3_ctrl_on is called. After ion client is created, now it's time to initialize domain and context, as follow:
mdp3_iommu_domain_init and mdp3_iommu_context_initwhich are placed in mdp3_mmu_init.
int mdp3_iommu_domain_init(void)
{
struct msm_iova_layout layout;
int i; if (mdp3_res->domains) {
pr_warn("iommu domain already initialized\n");
return ;
} for (i = ; i < MDP3_IOMMU_DOMAIN_MAX; i++) {
int domain_idx;
layout.client_name = mdp3_iommu_domains[i].client_name;
layout.partitions = mdp3_iommu_domains[i].partitions;
layout.npartitions = mdp3_iommu_domains[i].npartitions;
layout.is_secure = false; domain_idx = msm_register_domain(&layout);
if (IS_ERR_VALUE(domain_idx))
return -EINVAL; mdp3_iommu_domains[i].domain_idx = domain_idx;
mdp3_iommu_domains[i].domain = msm_get_iommu_domain(domain_idx);
if (IS_ERR_OR_NULL(mdp3_iommu_domains[i].domain)) {
pr_err("unable to get iommu domain(%d)\n",
domain_idx);
if (!mdp3_iommu_domains[i].domain)
return -EINVAL;
else
return PTR_ERR(mdp3_iommu_domains[i].domain);
}
} mdp3_res->domains = mdp3_iommu_domains; return ;
}
int mdp3_iommu_context_init(void)
{
int i; if (mdp3_res->iommu_contexts) {
pr_warn("iommu context already initialized\n");
return ;
} for (i = ; i < MDP3_IOMMU_CTX_MAX; i++) {
mdp3_iommu_contexts[i].ctx =
msm_iommu_get_ctx(mdp3_iommu_contexts[i].ctx_name); if (IS_ERR_OR_NULL(mdp3_iommu_contexts[i].ctx)) {
pr_warn("unable to get iommu ctx(%s)\n",
mdp3_iommu_contexts[i].ctx_name);
if (!mdp3_iommu_contexts[i].ctx)
return -EINVAL;
else
return PTR_ERR(mdp3_iommu_contexts[i].ctx);
}
} mdp3_res->iommu_contexts = mdp3_iommu_contexts; return ;
}
Now at the stage of mdp3 probe, the memory is done.

7.3 probe of mdss dsi(msm_dsi_probe)

7.3.1 allocate dsi host private data in msm_dsi_init
dsi_host_private = kzalloc(sizeof(struct dsi_host_v2_private),
GFP_KERNEL);

7.3.2 allocate dsi private io data in msm_dsi_io_init

dsi_io_private = kzalloc(sizeof(struct msm_dsi_io_private),
GFP_KERNEL);
The allocation is few, only two structures' size.

7.4 the allocation of dsi_panel_probe

For panel, only panel private data, tx, rx buffer and initial on/off commands need to be allocated.

int dsi_panel_init(void)
{
panel_private = kzalloc(sizeof(struct dsi_panel_private), GFP_KERNEL);
dsi_buf_alloc(&panel_private->dsi_panel_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
dsi_buf_alloc(&panel_private->dsi_panel_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
return ;
}

dsi_panel_parse_init_cmds(platform_device *, dsi_panel_common_pdata *) : int
|-------dsi_panel_parse_dt(platform_device *, dsi_panel_common_pdata *, char *) : int
|--------------dsi_panel_probe(platform_device *) : int
|----------------------{init this_driver}() : platform_driver

static int dsi_panel_parse_init_cmds(struct platform_device *pdev,
struct dsi_panel_common_pdata *panel_data)
{
struct device_node *np = pdev->dev.of_node;
int i, len;
int cmd_plen, data_offset;
const char *data;
const char *on_cmds_state, *off_cmds_state;
int num_of_on_cmds = , num_of_off_cmds = ; data = of_get_property(np, "qcom,panel-on-cmds", &len); panel_private->on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL); memcpy(panel_private->on_cmds, data, len); data_offset = ;
cmd_plen = ;
while ((len - data_offset) >= DT_CMD_HDR) {
data_offset += (DT_CMD_HDR - );
cmd_plen = panel_private->on_cmds[data_offset++];
data_offset += cmd_plen;
num_of_on_cmds++;
} panel_private->on_cmds_list = kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
panel_private->on_cmds_list->buf = kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)), GFP_KERNEL); data_offset = ;
for (i = ; i < num_of_on_cmds; i++) {
panel_private->on_cmds_list->buf[i].dtype =
panel_private->on_cmds[data_offset++];
panel_private->on_cmds_list->buf[i].last =
panel_private->on_cmds[data_offset++];
panel_private->on_cmds_list->buf[i].vc =
panel_private->on_cmds[data_offset++];
panel_private->on_cmds_list->buf[i].ack =
panel_private->on_cmds[data_offset++];
panel_private->on_cmds_list->buf[i].wait =
panel_private->on_cmds[data_offset++];
panel_private->on_cmds_list->buf[i].dlen =
panel_private->on_cmds[data_offset++];
panel_private->on_cmds_list->buf[i].payload =
&panel_private->on_cmds[data_offset];
data_offset += (panel_private->on_cmds_list->buf[i].dlen);
} panel_private->on_cmds_list->size = num_of_on_cmds; on_cmds_state = of_get_property(pdev->dev.of_node,
"qcom,on-cmds-dsi-state", NULL);
if (!strncmp(on_cmds_state, "DSI_LP_MODE", )) {
panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
} else if (!strncmp(on_cmds_state, "DSI_HS_MODE", )) {
panel_private->on_cmds_list->ctrl_state = DSI_HS_MODE;
} else {
pr_debug("%s: ON cmds state not specified. Set Default\n", __func__);
panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
} panel_data->dsi_panel_on_cmds = panel_private->on_cmds_list; data = of_get_property(np, "qcom,panel-off-cmds", &len); panel_private->off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
memcpy(panel_private->off_cmds, data, len); data_offset = ;
cmd_plen = ;
while ((len - data_offset) >= DT_CMD_HDR) {
data_offset += (DT_CMD_HDR - );
cmd_plen = panel_private->off_cmds[data_offset++];
data_offset += cmd_plen;
num_of_off_cmds++;
} panel_private->off_cmds_list = kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL); panel_private->off_cmds_list->buf = kzalloc(num_of_off_cmds * sizeof(struct dsi_cmd_desc), GFP_KERNEL);
data_offset = ;
for (i = ; i < num_of_off_cmds; i++) {
panel_private->off_cmds_list->buf[i].dtype =
panel_private->off_cmds[data_offset++];
panel_private->off_cmds_list->buf[i].last =
panel_private->off_cmds[data_offset++];
panel_private->off_cmds_list->buf[i].vc =
panel_private->off_cmds[data_offset++];
panel_private->off_cmds_list->buf[i].ack =
panel_private->off_cmds[data_offset++];
panel_private->off_cmds_list->buf[i].wait =
panel_private->off_cmds[data_offset++];
panel_private->off_cmds_list->buf[i].dlen =
panel_private->off_cmds[data_offset++];
panel_private->off_cmds_list->buf[i].payload =
&panel_private->off_cmds[data_offset];
data_offset += (panel_private->off_cmds_list->buf[i].dlen);
} panel_private->off_cmds_list->size = num_of_off_cmds;
off_cmds_state = of_get_property(pdev->dev.of_node,
"qcom,off-cmds-dsi-state", NULL);
if (!strncmp(off_cmds_state, "DSI_LP_MODE", )) {
panel_private->off_cmds_list->ctrl_state =
DSI_LP_MODE;
} else if (!strncmp(off_cmds_state, "DSI_HS_MODE", )) {
panel_private->off_cmds_list->ctrl_state = DSI_HS_MODE;
} else {
pr_debug("%s: ON cmds state not specified. Set Default\n",
__func__);
panel_private->off_cmds_list->ctrl_state = DSI_LP_MODE;
} panel_data->dsi_panel_off_cmds = panel_private->off_cmds_list; return ;
}

7.5 unblank lcd: FB_BLANK_UNBLANK

fb_ioctl          fbmem.c
|--------do_fb_ioctl    fbmem.c
|--------fb_blank
case FBIOBLANK:
if (!lock_fb_info(info))
return -ENODEV;
console_lock();
info->flags |= FBINFO_MISC_USEREVENT;
ret = fb_blank(info, arg);
info->flags &= ~FBINFO_MISC_USEREVENT;
console_unlock();
unlock_fb_info(info);
break;
if (info->fbops->fb_blank)
ret = info->fbops->fb_blank(blank, info);

The function pointer is registered in mdss_fb.c

static struct fb_ops mdss_fb_ops = {
.owner = THIS_MODULE,
.fb_open = mdss_fb_open,
.fb_release = mdss_fb_release,
.fb_check_var = mdss_fb_check_var, /* vinfo check */
.fb_set_par = mdss_fb_set_par, /* set the video mode */
.fb_blank = mdss_fb_blank, /* blank display */
.fb_pan_display = mdss_fb_pan_display, /* pan display */
.fb_ioctl = mdss_fb_ioctl, /* perform fb specific ioctl */
.fb_mmap = mdss_fb_mmap,
};
|-------------------mdss_fb_blank in mdss_fb.c
|----------------------------mdss_fb_blank_sub in mdss_fb.c

static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; mdss_fb_pan_idle(mfd);
if (mfd->op_enable == ) {
if (blank_mode == FB_BLANK_UNBLANK)
mfd->suspend.panel_power_on = true;
else
mfd->suspend.panel_power_on = false;
return ;
}
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}

If lcd is to be opened, the following case will be called.

If lcd is to be opened, the following case will be called.

msm_mdp_interface::on_fnc : int (*)(msm_fb_data_type *)
|--------mdp3_ctrl_init(msm_fb_data_type *) : int
|----------------mdp3_init(msm_fb_data_type *) : int
|-----------------------mdp3_probe(platform_device *) : int
|---------------------------{init mdp3_driver}() : platform_driver
|--------mdss_fb_blank_sub(int, fb_info *, int) : int (2 matches)
|----------------mdss_fb_blank(int, fb_info *) : int
|-----------------------{init mdss_fb_ops}() : fb_ops
|----------------mdss_fb_open(fb_info *, int) : int
|----------------mdss_fb_release(fb_info *, int) : int
|----------------mdss_fb_resume_sub(msm_fb_data_type *) : int
|----------------mdss_fb_set_par(fb_info *) : int (2 matches)
|----------------mdss_fb_suspend_sub(msm_fb_data_type *) : int
|--------mdss_fb_dcm(msm_fb_data_type *, int) : int (2 matches)
|--------mdss_mdp_overlay_init(msm_fb_data_type *) : int
|--------mdss_qpic_overlay_init(msm_fb_data_type *) : int

Then the on_fnc is called, as follow:

mdp3_interface->on_fnc = mdp3_ctrl_on;
mdp3_interface->off_fnc = mdp3_ctrl_off;
mdp3_interface->do_histogram = NULL;
mdp3_interface->cursor_update = NULL;
mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
mdp3_interface->lut_update = mdp3_ctrl_lut_update;
Please refer to 3.1 and 3.2
Last, dma function pointer start would be called, as follow:

static int mdp3_dma_start(struct mdp3_dma *dma, struct mdp3_intf *intf)
{
unsigned long flag;
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
u32 dma_start_offset = MDP3_REG_DMA_P_START; if (dma->dma_sel == MDP3_DMA_P)
dma_start_offset = MDP3_REG_DMA_P_START;
else if (dma->dma_sel == MDP3_DMA_S)
dma_start_offset = MDP3_REG_DMA_S_START;
else
return -EINVAL; spin_lock_irqsave(&dma->dma_lock, flag);
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
MDP3_REG_WRITE(dma_start_offset, );
} intf->start(intf);
wmb();
init_completion(&dma->vsync_comp);
spin_unlock_irqrestore(&dma->dma_lock, flag); mdp3_dma_callback_enable(dma, cb_type);
pr_debug("mdp3_dma_start wait for vsync_comp in\n");
wait_for_completion_killable(&dma->vsync_comp);
pr_debug("mdp3_dma_start wait for vsync_comp out\n");
return ;
}

7.6 Now it's time to introduce overlay play and commit

Here, the double framebuffer address will be switched, so the performance can be improved.

8. suspend and resume

static struct platform_driver mdss_fb_driver = {
.probe = mdss_fb_probe,
.remove = mdss_fb_remove,
.suspend = mdss_fb_suspend,
.resume = mdss_fb_resume,
.shutdown = mdss_fb_shutdown,
.driver = {
.name = "mdss_fb",
.of_match_table = mdss_fb_dt_match,
.pm = &mdss_fb_pm_ops,
},
};
static const struct dev_pm_ops mdss_fb_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mdss_fb_pm_suspend, mdss_fb_pm_resume)
};
.suspend = mdss_fb_pm_suspend, \
.resume = mdss_fb_pm_resume, \
.freeze = mdss_fb_pm_suspend, \
.thaw = mdss_fb_pm_resume, \
.poweroff = mdss_fb_pm_suspend, \
.restore = mdss_fb_pm_resume,
#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP) /* CONFIG_PM=y and CONFIG_PM_SLEEP=y*/
static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
{
struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV; dev_dbg(&pdev->dev, "display suspend\n"); return mdss_fb_suspend_sub(mfd);
} static int mdss_fb_resume(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV; dev_dbg(&pdev->dev, "display resume\n"); return mdss_fb_resume_sub(mfd);
}
#else
#define mdss_fb_suspend NULL
#define mdss_fb_resume NULL
#endif
#ifdef CONFIG_PM_SLEEP /* CONFIG_PM_SLEEP = y */
static int mdss_fb_pm_suspend(struct device *dev)
{
struct msm_fb_data_type *mfd = dev_get_drvdata(dev); if (!mfd)
return -ENODEV; dev_dbg(dev, "display pm suspend\n"); return mdss_fb_suspend_sub(mfd);
} static int mdss_fb_pm_resume(struct device *dev)
{
struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
if (!mfd)
return -ENODEV; dev_dbg(dev, "display pm resume\n"); return mdss_fb_resume_sub(mfd);
}
#endif

9 Automatically generate lcd initial commands to dtsi

Please refer to 80-BA103-1_A_Display_GCDB_XML_Entries.pdf
 
To use the parser script, go to @//~/device/qcom/common/display/tools/parser.pl. The command to run the script is:

#perl parser.pl <.xml> <panel/platform>   

Use the following command to generate the panel dtsi and header files:

#perl parser.pl panel_cmd.xml panel  

This command generates dsi-panel-cmd.dtsi and panel_cmd.h files. Dtsi should be copied to dts folder @//~/kernel/arch/arm/boot/dts while header file should be copied to bootloader GCDB header file database @//~/bootable/bootloader/lk/dev/gcdb/display/include. 
Use the following command to generate the platform dtsi and header files for platform-msm8610.xml:

#perl parser.pl platform-msm8610.xml platform 

This command generates platform_msm8610.h and platform-msm8610.dtsi files. The content of the dtsi file should be copied to <target>-mdss.dtsi in @//~/kernel/arch/arm/boot/dts while the content of the header file should be copied to @//~/bootable/bootloader/lk/target/<target>/include/target/display.h for LK. In this example, <target> can be replaced with msm8610. 
This process can be followed for any new display and platform, by updating the XML files. This process 16 is also documented at @//~/device/qcom/common/display/tools/README.txt.

10 vsync controlling of mdp

11 lcd common resolution of mobile phone

The display resolution of a digital televisioncomputer monitor or display device is the number of distinct pixels in each dimension that can be displayed. It can be an ambiguous term especially as the displayed resolution is controlled by different factors in cathode ray tube(CRT), Flat panel display which includes Liquid crystal displays, or projection displays using fixed picture-element (pixel) arrays.

It is usually quoted as width × height, with the units in pixels: for example, "1024 × 768" means the width is 1024pixelsand the height is 768 pixels. This example would normally be spoken as "ten twenty-four by seven sixty-eight" or "ten twenty-four by seven six eight".

One use of the term “display resolution” applies to fixed-pixel-array displays such as plasma display panels (PDPs), liquid crystal displays (LCDs), digital light processing (DLP) projectors, or similar technologies, and is simply the physical number of columns and rows of pixels creating the display (e.g., 1920 × 1080). A consequence of having a fixed-grid display is that, for multi-format video inputs, all displays need a "scaling engine" (a digital video processor that includes a memory array) to match the incoming picture format to the display.

Note that for broadcast television standards the use of the word resolution here is a misnomer, though common. The term “display resolution” is usually used to mean pixel dimensions, the number of pixels in each dimension (e.g., 1920 × 1080), which does not tell anything about the pixel density of the display on which the image is actually formed: broadcast television resolution properly refers to the pixel density, the number of pixels per unit distance or area, not total number of pixels. In digital measurement, the display resolution would be given in pixels per inch. In analog measurement, if the screen is 10 inches high, then the horizontal resolution is measured across a square 10 inches wide. This is typically stated as "lines horizontal resolution, per picture height;"[1] for example, analog NTSC TVs can typically display about 340 lines of "per picture height" horizontal resolution from over-the-air sources, which is equivalent to about 440 total lines of actual picture information from left edge to right edge.

Please refer to the following wiki picture, which is very clear:

10 vsync controlling of mdp

11 lcd common resolution of mobile phone

The display resolution of a digital televisioncomputer monitor or display device is the number of distinct pixels in each dimension that can be displayed. It can be an ambiguous term especially as the displayed resolution is controlled by different factors in cathode ray tube(CRT), Flat panel display which includes Liquid crystal displays, or projection displays using fixed picture-element (pixel) arrays.

It is usually quoted as width × height, with the units in pixels: for example, "1024 × 768" means the width is 1024pixelsand the height is 768 pixels. This example would normally be spoken as "ten twenty-four by seven sixty-eight" or "ten twenty-four by seven six eight".

One use of the term “display resolution” applies to fixed-pixel-array displays such as plasma display panels (PDPs), liquid crystal displays (LCDs), digital light processing (DLP) projectors, or similar technologies, and is simply the physical number of columns and rows of pixels creating the display (e.g., 1920 × 1080). A consequence of having a fixed-grid display is that, for multi-format video inputs, all displays need a "scaling engine" (a digital video processor that includes a memory array) to match the incoming picture format to the display.

Note that for broadcast television standards the use of the word resolution here is a misnomer, though common. The term “display resolution” is usually used to mean pixel dimensions, the number of pixels in each dimension (e.g., 1920 × 1080), which does not tell anything about the pixel density of the display on which the image is actually formed: broadcast television resolution properly refers to the pixel density, the number of pixels per unit distance or area, not total number of pixels. In digital measurement, the display resolution would be given in pixels per inch. In analog measurement, if the screen is 10 inches high, then the horizontal resolution is measured across a square 10 inches wide. This is typically stated as "lines horizontal resolution, per picture height;"[1] for example, analog NTSC TVs can typically display about 340 lines of "per picture height" horizontal resolution from over-the-air sources, which is equivalent to about 440 total lines of actual picture information from left edge to right edge.

Please refer to the following wiki picture, which is very clear:
 
This chart shows the most common display resolutions, with the color of each resolution type indicating the display ratio (e.g., red indicates a 4:3 ratio)

12 dts and dtsi about lcd

12.1 On 8x10 platform, there is a version xx-xx-v2, this is corresponding to xx-v2-xx-dts, xx-v2-xx-dtsi, as follow:
~/mountpoint/project_xxxx/kernel/arch/arm/boot$ ll dts/dsi-panel-*
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-generic-720p-cmd.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-hx8379a-wvga-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-hx8394a-720p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-nt35521-720p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-nt35590-720p-cmd.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-nt35590-720p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-nt35596-1080p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-orise-720p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-otm8018b-fwvga-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-sharp-qhd-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-sim-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-ssd2080m-720p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-toshiba-720p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-truly-wvga-cmd.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-panel-truly-wvga-video.dtsi [plain] view plaincopyprint?
~/mountpoint/project_xxxx/kernel/arch/arm/boot$ ll dts/dsi-v2-panel-*
-rw-r--r-- yanghaibing users -- : dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-v2-panel-nt35590-720p-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-v2-panel-truly-wvga-cmd.dtsi
-rw-r--r-- yanghaibing users -- : dts/dsi-v2-panel-truly-wvga-video.dtsi [plain] view plaincopyprint?
yanghaibing@njyjs-cm:~/mountpoint/project_8210/kernel/arch/arm/boot/dts$ ll msm8610*
-rw-r--r-- yanghaibing users -- : msm8610-bus.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-camera.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-camera-sensor-cdp-mtp.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-cdp.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-coresight.dtsi
-rw-r--r-- yanghaibing users -- : msm8610.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-gpu.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-iommu-domains.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-ion.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-mdss.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-mdss-panels.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-mtp.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-qrd-camera-sensor.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-qrd.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-qrd-skuaa.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-qrd-skuab.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-regulator.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-rumi.dts
-rw-r--r-- yanghaibing users -- : msm8610-sim.dts
-rw-r--r-- yanghaibing users -- : msm8610-smp2p.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-v1-cdp.dts
-rw-r--r-- yanghaibing users -- : msm8610-v1.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-v1-mtp.dts
-rw-r--r-- yanghaibing users -- : msm8610-v1-pm.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-v1-qrd-skuaa.dts
-rw-r--r-- yanghaibing users -- : msm8610-v1-qrd-skuab.dts
-rw-r--r-- yanghaibing users -- : msm8610-v2-cdp.dts
-rw-r--r-- yanghaibing users -- : msm8610-v2.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-v2-mtp.dts
-rw-r--r-- yanghaibing users -- : msm8610-v2-pm.dtsi
-rw-r--r-- yanghaibing users -- : msm8610-v2-qrd-skuaa.dts
-rw-r--r-- yanghaibing users -- : msm8610-v2-qrd-skuab.dts
Our product version is mtp. The following code snippet is related to lcd
msm8610-mdss.dtsi    According to the campatible name (msm-dsi-v2) of mdss_dsi, it will be related todsi_host_v2.c, rather thanmdss_dsi.c.
 
This dtsi should be read carefully, because most of host display parameters and platform resources are here.
dsi_host_v2.c
static const struct of_device_id msm_dsi_v2_dt_match[] = {
{.compatible = "qcom,msm-dsi-v2"},
{}
};
MODULE_DEVICE_TABLE(of, msm_dsi_v2_dt_match); static struct platform_driver msm_dsi_v2_driver = {
.probe = msm_dsi_probe,
.remove = __devexit_p(msm_dsi_remove),
.shutdown = NULL,
.driver = {
.name = "msm_dsi_v2",
.of_match_table = msm_dsi_v2_dt_match,
},
};

mdss_dsi.c

static const struct of_device_id mdss_dsi_ctrl_dt_match[] = {
{.compatible = "qcom,mdss-dsi-ctrl"},
{}
};
MODULE_DEVICE_TABLE(of, mdss_dsi_ctrl_dt_match); static struct platform_driver mdss_dsi_ctrl_driver = {
.probe = mdss_dsi_ctrl_probe,
.remove = __devexit_p(mdss_dsi_ctrl_remove),
.shutdown = NULL,
.driver = {
.name = "mdss_dsi_ctrl",
.of_match_table = mdss_dsi_ctrl_dt_match,
},
};
&soc {
mdss_mdp: qcom,mdss_mdp@fd900000 {
compatible = "qcom,mdss_mdp3";
reg = <0xfd900000 0x100000>;
reg-names = "mdp_phys";
interrupts = < >; mdss_fb0: qcom,mdss_fb_primary {
cell-index = <>;
compatible = "qcom,mdss-fb";
qcom,memblock-reserve = <0x3200000 0x800000>;
};
}; mdss_dsi0: qcom,mdss_dsi@fdd00000 {
compatible = "qcom,msm-dsi-v2";
label = "MDSS DSI CTRL->0";
cell-index = <>;
reg = <0xfdd00000 0x100000>;
interrupts = < >;
vdd-supply = <&pm8110_l4>;
vdda-supply = <&pm8110_l19>;
vddio-supply = <&pm8110_l14>;
qcom,mdss-fb-map = <&mdss_fb0>;
qcom,mdss-mdp = <&mdss_mdp>;
qcom,platform-reset-gpio = <&msmgpio >;
/*
qcom,platform-te-gpio = <&msmgpio 12 0>;
qcom,platform-mode-gpio = <&msmgpio 7 0>;
*/ qcom,platform-reset-sequence = < >; qcom,platform-strength-ctrl = [ff ];
qcom,platform-bist-ctrl = [ 0f ];
qcom,platform-regulator-settings = [ ];
qcom,platform-lane-config = [ ]; qcom,platform-supply-entry1 {
qcom,supply-name = "vdd";
qcom,supply-min-voltage = <>;
qcom,supply-max-voltage = <>;
qcom,supply-enable-load = <>;
qcom,supply-disable-load = <>;
qcom,supply-pre-on-sleep = <>;
qcom,supply-post-on-sleep = <>;
qcom,supply-pre-off-sleep = <>;
qcom,supply-post-off-sleep = <>;
}; qcom,platform-supply-entry2 {
qcom,supply-name = "vddio";
qcom,supply-min-voltage = <>;
qcom,supply-max-voltage = <>;
qcom,supply-enable-load = <>;
qcom,supply-disable-load = <>;
qcom,supply-pre-on-sleep = <>;
qcom,supply-post-on-sleep = <>;
qcom,supply-pre-off-sleep = <>;
qcom,supply-post-off-sleep = <>;
}; qcom,platform-supply-entry3 {
qcom,supply-name = "vdda";
qcom,supply-min-voltage = <>;
qcom,supply-max-voltage = <>;
qcom,supply-enable-load = <>;
qcom,supply-disable-load = <>;
qcom,supply-pre-on-sleep = <>;
qcom,supply-post-on-sleep = <>;
qcom,supply-pre-off-sleep = <>;
qcom,supply-post-off-sleep = <>;
};
};
}; /include/ "msm8610-mdss-panels.dtsi"

msm8610-mdss-panels.dtsi (The default version is not v2.) So this dtsi will be related tomdss_dsi_panel.c, rather thandsi_panel_v2.c

/include/ "dsi-panel-truly-wvga-video.dtsi"
/include/ "dsi-panel-truly-wvga-cmd.dtsi"
/include/ "dsi-panel-nt35590-720p-video.dtsi"
/include/ "dsi-panel-otm8018b-fwvga-video.dtsi"
/include/ "dsi-panel-hx8379a-wvga-video.dtsi"

13 Actual memory allocated size of multimedia of lcd

MDP3_CLIENT_DMA_P, len:1658880
The actual size is 480(xres)*4(byte per pixel)*854(yres) = 1639690
The allocated size is 1658880, that is 0x1905000

if (iclient) {
data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
<span style="white-space:pre"> </span>......
}
if (client == MDP3_CLIENT_DMA_P) { /* Here is the called path */
dom = (mdp3_res->domains +
MDP3_DMA_IOMMU_DOMAIN)->domain_idx;
ret = ion_map_iommu(iclient, data->srcp_ihdl, dom, /* Fetch the length */
, SZ_4K, , start, len, , );
} else {
ret = mdp3_self_map_iommu(iclient, data->srcp_ihdl,
SZ_4K, data->padding, start, len, , );
}
if (IS_ERR_VALUE(ret)) {
<span style="white-space:pre"> </span>......
}
mdp3_get_img(msmfb_data *, mdp3_img_data *, int) : int
|--------mdp3_overlay_queue_buffer(msm_fb_data_type *, msmfb_overlay_data *) : int
|----------------mdp3_overlay_play(msm_fb_data_type *, msmfb_overlay_data *) : int
|------------------------mdp3_ctrl_ioctl_handler(msm_fb_data_type *, u32, void *) : int
|--------------------------------mdp3_ctrl_init(msm_fb_data_type *) : int
|
|--------mdp3_ppp_get_img(mdp_img *, mdp_blit_req *, mdp3_img_data *) : int

14 If reset isn't called first, sometimes slight flower screen would appear on lcd

We can refer to this file: dts/dsi-panel-otm8018b-fwvga-video.dtsi

qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
qcom,mdss-dsi-h-sync-pulse = <>;
qcom,mdss-dsi-traffic-mode = <>;
qcom,mdss-dsi-lane-map = <>;
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane--state;
qcom,mdss-dsi-lane--state;
qcom,mdss-dsi-panel-timings = [8B 1F 4A ];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <>;
qcom,mdss-dsi-bl-max-level = <>;
qcom,mdss-dsi-dma-trigger = <>;
qcom,mdss-dsi-mdp-trigger = <>;
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = < >, < >, < >; /* This field is necessory! */
Where do code parse this sequence? Please look at the following code snippet.
mdss_dsi_parse_reset_seq(device_node *, u32 *, u32 *, const char *) : int
|--------mdss_panel_parse_dt(device_node *, mdss_dsi_ctrl_pdata *) : int
|----------------mdss_dsi_panel_init(device_node *, mdss_dsi_ctrl_pdata *, int) : int
|-------------------------msm_dsi_probe(platform_device *) : int
|---------------------------------{init msm_dsi_v2_driver}() : platform_driver

static int mdss_dsi_parse_reset_seq(struct device_node *np,
u32 rst_seq[MDSS_DSI_RST_SEQ_LEN], u32 *rst_len,
const char *name)
{
int num = , i;
int rc;
struct property *data;
u32 tmp[MDSS_DSI_RST_SEQ_LEN];
*rst_len = ;
data = of_find_property(np, name, &num);
num /= sizeof(u32);
if (!data || !num || num > MDSS_DSI_RST_SEQ_LEN || num % ) {
pr_debug("%s:%d, error reading %s, length found = %d\n",
__func__, __LINE__, name, num); <span style="font-family:Arial,Helvetica,sans-serif; font-size:12px">/* I think here pr_debug should use pr_err. */</span>
} else {
rc = of_property_read_u32_array(np, name, tmp, num);
if (rc)
pr_debug("%s:%d, error reading %s, rc = %d\n",
__func__, __LINE__, name, rc); /* I think here pr_debug should use pr_err. */
else {
for (i = ; i < num; ++i)
rst_seq[i] = tmp[i];
*rst_len = num;
}
}
return ;
}

The following code snippet sequences are as following: if lcd is enabled, reset -> on cmds tx; if lcd is disabled, reset gpio set 0, and -> off cmds tx

static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
{
int rc = ;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; pr_debug("dsi_panel_handler enable=%d\n", enable);
if (!pdata)
return -ENODEV;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data); if (enable) {
dsi_ctrl_gpio_request(ctrl_pdata);
mdss_dsi_panel_reset(pdata, ); rc = dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
ctrl_pdata->on_cmds.cmds,
ctrl_pdata->on_cmds.cmd_cnt); if (rc)
pr_err("dsi_panel_handler panel on failed %d\n", rc);
} else {
if (dsi_intf.op_mode_config)
dsi_intf.op_mode_config(DSI_CMD_MODE, pdata); dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
ctrl_pdata->off_cmds.cmds,
ctrl_pdata->off_cmds.cmd_cnt); mdss_dsi_panel_reset(pdata, );
dsi_ctrl_gpio_free(ctrl_pdata);
}
return rc;
}

The following code snippet is an interface for mdp_ctrl.c. It implements dsi on/off, panel on/off and splash screen.

static int dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
int rc = ; if (!pdata) {
pr_err("%s: Invalid input data\n", __func__);
return -ENODEV;
} switch (event) {
case MDSS_EVENT_UNBLANK:
rc = dsi_on(pdata);
break;
case MDSS_EVENT_BLANK:
rc = dsi_off(pdata);
break;
case MDSS_EVENT_PANEL_ON:
rc = dsi_panel_handler(pdata, );
break;
case MDSS_EVENT_PANEL_OFF:
rc = dsi_panel_handler(pdata, );
break;
case MDSS_EVENT_CONT_SPLASH_BEGIN:
rc = dsi_splash_on(pdata);
break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
}
return rc;
}

15 tips

Tools→Options for xshell

delimitor:
\ :;`!@#$%^&*()=+|[]{}'",<>?

How to enable the debugfs

In kernel debug, sometimes you might need the debugfs (CONFIG_DEBUG_FS)。

you can manually mount as the commands:

# mount -t debugfs /sys/kernel/debug  

msm8610 lcd driver code analysis的更多相关文章

  1. 高通平台 lcd driver 调试小结

    一.概述 1.1 简介 本文档主要包括LCD模块的驱动流程分析.Framebuffer相关知识.Gralloc等相关内容,以及LCD调试的一些经验和相关bug的分析和讲解. 1.2  开发环境 And ...

  2. Cppcheck - A tool for static C/C++ code analysis

    cppcheck是一个个检测源码的工具,对编译工具的一个补充,mark Cppcheck - A tool for static C/C++ code analysis Syntax: cppchec ...

  3. The Ultimate List of Open Source Static Code Analysis Security Tools

    https://www.checkmarx.com/2014/11/13/the-ultimate-list-of-open-source-static-code-analysis-security- ...

  4. Top 40 Static Code Analysis Tools

    https://www.softwaretestinghelp.com/tools/top-40-static-code-analysis-tools/ In this article, I have ...

  5. 二十五、详述 IntelliJ IDEA 提交代码前的 Code Analysis 机制

    在我们用 IntelliJ IDEA 向 SVN 或者 Git 提交代码的时候,IntelliJ IDEA 提供了一个自动分析代码的功能,即Perform code analysis: 如上图所示,当 ...

  6. 十四、详述 IntelliJ IDEA 提交代码前的 Code Analysis 机制

    在我们用 IntelliJ IDEA 向 SVN 或者 Git 提交代码的时候,IntelliJ IDEA 提供了一个自动分析代码的功能,即Perform code analysis: 如上图所示,当 ...

  7. IntelliJ IDEA 提交代码时出现:Code analysis failed with exception: com.intellij.psi......

    IntelliJ IDEA 提交代码时出现:Code analysis failed with exception: com.intellij.psi...... 错误原因: 当我们勾选Perform ...

  8. DEA使用git提交代码时,点了commit之后卡死在performing code analysis部分,或者performing code analysis结束后没有进入下一步操作。

    把"Perform code analysis" 和 "Check TODO" 复选框前面的勾去掉就好了. 这个可能是因为所分析的目标文件太大了,造成一直分析不 ...

  9. IDEA使用git提交代码时,点了commit之后卡死在performing code analysis部分,或者performing code analysis结束后没有进入下一步操作

    把"Perform code analysis" 和 "Check TODO" 复选框前面的勾去掉就好了. 这个可能是因为所分析的目标文件太大了,造成一直分析不 ...

随机推荐

  1. HTML5 改良的 input 元素的种类

    html5中增加改良的input 元素 . 在过去我们制作网页输入框,会用到不少JS验证,如今有了HTML5写这种效果已经没有那么麻烦了,下面我来给大家介绍两种HTML5的input的新增加的类型应用 ...

  2. mysql 清空表 Truncate及delete区别

    1.delete from 表名[where]; 2.truncate table 表名; 3.delete将mysql表中所有记录一条一条删除到删完 4.truncate保留mysql表的结构,重新 ...

  3. URL传参中不能带特殊的字符以及处理方案

    有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.编码的格式为:%加字符的ASCII码,即一个百分号%,后面跟对应字符的ASCII(16进制)码值.例如 ...

  4. Spring之Spring MVC

    Spring调配半天没搞定,原来是web.xml应该放在WEB-INF的目录下,而不是webcontent目录下: java.lang.ClassNotFoundException: org.spri ...

  5. PDF转WORD工具 Solid Converter PDF v9.1.6744

    Solid Converter PDF中文破解版(pdf转换成word转换器)是一款功能强大的PDF格式转换软件.Solid Converter PDF允许用户将PDF转换为Word(PDF to W ...

  6. 图片Base64编码 简单使用

    图片在线转换Base64,图片编码base64 http://tool.css-js.com/base64.html HTML5 + js <input type="file" ...

  7. Xcode:只修改 Bundle Identifier,不修改项目名

    找到 xx-Info.plist,打开 直接去修改 Bundle identifier 即可(默认后缀是项目名字).

  8. Java数据库连接关闭后无法启动

    错误如下: java.sql.SQLException: No operations allowed after connection closed. at com.mysql.jdbc.Connec ...

  9. Hbase热点问题

    需求描述:扫描(查询)某个区间--->列用hbase多节点的资源,分布式扫描,加快速度==> 然后拼接到一起 如何打散数据 冠字号逆序,hash 并不一定数据连续就会造成热点,这个是由数据 ...

  10. [原博客] POJ 2425 A Chess Game

    题目链接题意:给定一个有向无环图(DAG),上面放有一些旗子,旗子可以重合,两个人轮流操作,每次可以把一个旗子从一个位置移动到相邻的位置,无法移动时输,询问先手是否必胜. 这道题可以把每个旗子看作单独 ...