The version of qualcomm code is LNX.LA.3.2-01430-8x10.0
mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o #1
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 #2: dsi_host_v2, #3: 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 #4
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
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, 0, 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 = 0;
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 = 0;
mdp3_session->lut_sel = 0;
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 = 1000 / 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
static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
int mdp3_dma_init(struct mdp3_dma *dma)
{
int ret = 0;
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, 0, sizeof(dma->cursor));
memset(&dma->ccs_config, 0, sizeof(dma->ccs_config));
memset(&dma->histogram_config, 0, 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 0;
}
/*
* 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 >= 0)
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,
the 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 = 0;
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, 0, SZ_4K, 0, &mfd->iova,
(unsigned long *)&size, 0, 0);
......
mfd->fbi->screen_base = virt;
mfd->fbi->fix.smem_start = phys;
mfd->fbi->fix.smem_len = size;
return 0;
......
}
Function mdp3_alloc get ion_handle, virtuall address and physical address from ion.
void *ion_map_kernel(struct ion_client *client, struct ion_handle 8 *handle, unsigned long flags);
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 = 0;
if (mdp3_res->ion_handle) {
pr_debug("memory already alloc\n");
*virt = mdp3_res->virt;
*phys = mdp3_res->phys;
return 0;
}
mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
SZ_1M,
ION_HEAP(ION_QSECOM_HEAP_ID), 0);
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 0;
......
return -ENOMEM;
}
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)
enum {
VIDEO_DOMAIN,
CAMERA_DOMAIN,
DISPLAY_DOMAIN,
ROTATOR_DOMAIN,
MAX_DOMAINS
};
ion_map_iommu(display_iclient, *srcp_ihdl, DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 23 0, start, len, 0, 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-13 >alloc_handle, VIDEO_DOMAIN, VIDEO_FIRMWARE_POOL, SZ_4K, 15 0, &iova, &buffer_size, UNCACHED, 0);
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, 256, 0);
mdp3_res = devm_kzalloc(&pdev->dev, sizeof(struct mdp3_hw_resource), GFP_KERNEL);
static int mdp3_res_init(void)
{
int rc = 0;
rc = mdp3_irq_setup();
......
rc = mdp3_clk_setup(); ...... mdp3_res->ion_client = msm_ion_client_create(-1, 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)
struct ion_handle *ion_alloc(struct ion_client,*client, size_t len, size_t align, unsigned int flags);
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 0;
}
for (i = 0; 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 0;
}
int mdp3_iommu_context_init(void)
{
int i;
if (mdp3_res->iommu_contexts) {
pr_warn("iommu context already initialized\n");
return 0;
}
for (i = 0; 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 0;
}
dsi_host_private = kzalloc(sizeof(struct dsi_host_v2_private),
GFP_KERNEL);
dsi_io_private = kzalloc(sizeof(struct msm_dsi_io_private),
GFP_KERNEL);
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 0;
}
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 = 0, num_of_off_cmds = 0;
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 = 0;
cmd_plen = 0;
while ((len - data_offset) >= DT_CMD_HDR) {
data_offset += (DT_CMD_HDR - 1);
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 = 0;
for (i = 0; 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", 11)) {
panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
} else if (!strncmp(on_cmds_state, "DSI_HS_MODE", 11)) {
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 = 0;
cmd_plen = 0;
while ((len - data_offset) >= DT_CMD_HDR) {
data_offset += (DT_CMD_HDR - 1);
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 = 0;
for (i = 0; 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", 11)) {
panel_private->off_cmds_list->ctrl_state =
DSI_LP_MODE;
} else if (!strncmp(off_cmds_state, "DSI_HS_MODE", 11)) {
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 0;
}
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
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 == 0) {
if (blank_mode == FB_BLANK_UNBLANK)
mfd->suspend.panel_power_on = true;
else
mfd->suspend.panel_power_on = false;
return 0;
}
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
If lcd is to be opened, the following case will be called.
case FB_BLANK_UNBLANK:
if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
ret = mfd->mdp.on_fnc(mfd);
if (ret == 0)
mfd->panel_power_on = true;
mutex_lock(&mfd->update.lock);
mfd->update.type = NOTIFY_TYPE_UPDATE;
mutex_unlock(&mfd->update.lock);
}
break;
msm_mdp_interface::
on_fnc : int (*)(msm_fb_data_type *)
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;
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, 1);
}
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 0;
}
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
#perl parser.pl <.xml>
#perl parser.pl panel_cmd.xml panel
#perl parser.pl platform-msm8610.xml platform
The display resolution of a digital television, computer 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.
~/mountpoint/project_xxxx/kernel/arch/arm/boot$ ll dts/dsi-panel-*
-rw-r--r-- 1 yanghaibing users 3231 2013-11-06 06:42 dts/dsi-panel-generic-720p-cmd.dtsi
-rw-r--r-- 1 yanghaibing users 3640 2013-11-06 06:42 dts/dsi-panel-hx8379a-wvga-video.dtsi
-rw-r--r-- 1 yanghaibing users 3632 2013-11-06 06:42 dts/dsi-panel-hx8394a-720p-video.dtsi
-rw-r--r-- 1 yanghaibing users 10926 2013-11-06 06:42 dts/dsi-panel-nt35521-720p-video.dtsi
-rw-r--r-- 1 yanghaibing users 17782 2013-11-06 06:42 dts/dsi-panel-nt35590-720p-cmd.dtsi
-rw-r--r-- 1 yanghaibing users 17623 2013-11-06 06:42 dts/dsi-panel-nt35590-720p-video.dtsi
-rw-r--r-- 1 yanghaibing users 18348 2013-11-06 06:42 dts/dsi-panel-nt35596-1080p-video.dtsi
-rw-r--r-- 1 yanghaibing users 2360 2013-11-06 06:42 dts/dsi-panel-orise-720p-video.dtsi
-rw-r--r-- 1 yanghaibing users 6495 2013-11-06 06:42 dts/dsi-panel-otm8018b-fwvga-video.dtsi
-rw-r--r-- 1 yanghaibing users 2911 2013-11-06 06:42 dts/dsi-panel-sharp-qhd-video.dtsi
-rw-r--r-- 1 yanghaibing users 1663 2013-11-06 06:42 dts/dsi-panel-sim-video.dtsi
-rw-r--r-- 1 yanghaibing users 4720 2013-11-06 06:42 dts/dsi-panel-ssd2080m-720p-video.dtsi
-rw-r--r-- 1 yanghaibing users 4122 2013-11-06 06:42 dts/dsi-panel-toshiba-720p-video.dtsi
-rw-r--r-- 1 yanghaibing users 5314 2013-11-06 06:42 dts/dsi-panel-truly-wvga-cmd.dtsi
-rw-r--r-- 1 yanghaibing users 5149 2013-11-06 06:42 dts/dsi-panel-truly-wvga-video.dtsi
~/mountpoint/project_xxxx/kernel/arch/arm/boot$ ll dts/dsi-v2-panel-*
-rw-r--r-- 1 yanghaibing users 3290 2013-11-06 06:42 dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
-rw-r--r-- 1 yanghaibing users 15730 2013-11-06 06:42 dts/dsi-v2-panel-nt35590-720p-video.dtsi
-rw-r--r-- 1 yanghaibing users 5817 2013-09-27 06:00 dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
-rw-r--r-- 1 yanghaibing users 4659 2013-09-25 06:11 dts/dsi-v2-panel-truly-wvga-cmd.dtsi
-rw-r--r-- 1 yanghaibing users 4583 2013-09-25 06:11 dts/dsi-v2-panel-truly-wvga-video.dtsi
yanghaibing@njyjs-cm:~/mountpoint/project_8210/kernel/arch/arm/boot/dts$ ll msm8610*
-rw-r--r-- 1 yanghaibing users 19506 2013-11-06 06:42 msm8610-bus.dtsi
-rw-r--r-- 1 yanghaibing users 1941 2013-09-25 06:11 msm8610-camera.dtsi
-rw-r--r-- 1 yanghaibing users 10757 2013-11-06 06:42 msm8610-camera-sensor-cdp-mtp.dtsi
-rw-r--r-- 1 yanghaibing users 9670 2013-11-06 06:42 msm8610-cdp.dtsi
-rw-r--r-- 1 yanghaibing users 8723 2013-11-06 06:42 msm8610-coresight.dtsi
-rw-r--r-- 1 yanghaibing users 28159 2013-11-06 06:42 msm8610.dtsi
-rw-r--r-- 1 yanghaibing users 4186 2013-09-25 06:11 msm8610-gpu.dtsi
-rw-r--r-- 1 yanghaibing users 1112 2013-09-25 06:11 msm8610-iommu-domains.dtsi
-rw-r--r-- 1 yanghaibing users 1326 2013-09-25 06:11 msm8610-ion.dtsi
-rw-r--r-- 1 yanghaibing users 2801 2013-11-06 06:42 msm8610-mdss.dtsi
-rw-r--r-- 1 yanghaibing users 755 2013-11-06 06:42 msm8610-mdss-panels.dtsi
-rw-r--r-- 1 yanghaibing users 9910 2013-11-06 06:42 msm8610-mtp.dtsi
-rw-r--r-- 1 yanghaibing users 3187 2013-11-06 06:42 msm8610-qrd-camera-sensor.dtsi
-rw-r--r-- 1 yanghaibing users 8959 2013-11-06 06:42 msm8610-qrd.dtsi
-rw-r--r-- 1 yanghaibing users 1671 2013-11-06 06:42 msm8610-qrd-skuaa.dtsi
-rw-r--r-- 1 yanghaibing users 3117 2013-11-06 06:42 msm8610-qrd-skuab.dtsi
-rw-r--r-- 1 yanghaibing users 9764 2013-11-06 06:42 msm8610-regulator.dtsi
-rw-r--r-- 1 yanghaibing users 794 2013-09-25 06:11 msm8610-rumi.dts
-rw-r--r-- 1 yanghaibing users 1986 2013-11-06 06:42 msm8610-sim.dts
-rw-r--r-- 1 yanghaibing users 5657 2013-09-25 06:11 msm8610-smp2p.dtsi
-rw-r--r-- 1 yanghaibing users 850 2013-11-06 06:42 msm8610-v1-cdp.dts
-rw-r--r-- 1 yanghaibing users 861 2013-11-06 06:42 msm8610-v1.dtsi
-rw-r--r-- 1 yanghaibing users 850 2013-11-06 06:42 msm8610-v1-mtp.dts
-rw-r--r-- 1 yanghaibing users 8892 2013-11-06 06:42 msm8610-v1-pm.dtsi
-rw-r--r-- 1 yanghaibing users 791 2013-11-06 06:42 msm8610-v1-qrd-skuaa.dts
-rw-r--r-- 1 yanghaibing users 783 2013-11-06 06:42 msm8610-v1-qrd-skuab.dts
-rw-r--r-- 1 yanghaibing users 894 2013-11-06 06:42 msm8610-v2-cdp.dts
-rw-r--r-- 1 yanghaibing users 906 2013-11-06 06:42 msm8610-v2.dtsi
-rw-r--r-- 1 yanghaibing users 894 2013-11-06 06:42 msm8610-v2-mtp.dts
-rw-r--r-- 1 yanghaibing users 7974 2013-11-06 06:42 msm8610-v2-pm.dtsi
-rw-r--r-- 1 yanghaibing users 792 2013-11-06 06:42 msm8610-v2-qrd-skuaa.dts
-rw-r--r-- 1 yanghaibing users 783 2013-11-06 06:42 msm8610-v2-qrd-skuab.dts
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 = <0 72 0>;
mdss_fb0: qcom,mdss_fb_primary {
cell-index = <0>;
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 = <0>;
reg = <0xfdd00000 0x100000>;
interrupts = <0 30 0>;
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 41 0>;
/*
qcom,platform-te-gpio = <&msmgpio 12 0>;
qcom,platform-mode-gpio = <&msmgpio 7 0>;
*/
qcom,platform-reset-sequence = <1 20 0 2 1 20 2>;
qcom,platform-strength-ctrl = [ff 06];
qcom,platform-bist-ctrl = [03 03 00 00 0f 00];
qcom,platform-regulator-settings = [02 08 05 00 20 03];
qcom,platform-lane-config = [80 45 00 00 01 66
80 45 00 00 01 66
80 45 00 00 01 66
80 45 00 00 01 66
40 67 00 00 01 88];
qcom,platform-supply-entry1 {
qcom,supply-name = "vdd";
qcom,supply-min-voltage = <1200000>;
qcom,supply-max-voltage = <1200000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
qcom,supply-pre-on-sleep = <0>;
qcom,supply-post-on-sleep = <20>;
qcom,supply-pre-off-sleep = <0>;
qcom,supply-post-off-sleep = <20>;
};
qcom,platform-supply-entry2 {
qcom,supply-name = "vddio";
qcom,supply-min-voltage = <1800000>;
qcom,supply-max-voltage = <1800000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
qcom,supply-pre-on-sleep = <0>;
qcom,supply-post-on-sleep = <0>;
qcom,supply-pre-off-sleep = <0>;
qcom,supply-post-off-sleep = <0>;
};
qcom,platform-supply-entry3 {
qcom,supply-name = "vdda";
qcom,supply-min-voltage = <2850000>;
qcom,supply-max-voltage = <2850000>;
qcom,supply-enable-load = <100000>;
qcom,supply-disable-load = <100>;
qcom,supply-pre-on-sleep = <0>;
qcom,supply-post-on-sleep = <0>;
qcom,supply-pre-off-sleep = <0>;
qcom,supply-post-off-sleep = <0>;
};
};
};
/include/ "msm8610-mdss-panels.dtsi"
msm8610-mdss-panels.dtsi (
The default version is not v2.) So this dtsi will be related to
mdss_dsi_panel.c, rather than
dsi_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"
if (iclient) {
data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
......
}
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 */
0, SZ_4K, 0, start, len, 0, 0);
} else {
ret = mdp3_self_map_iommu(iclient, data->srcp_ihdl,
SZ_4K, data->padding, start, len, 0, 0);
}
if (IS_ERR_VALUE(ret)) {
......
}
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = <1>;
qcom,mdss-dsi-lane-map = <1>;
qcom,mdss-dsi-bllp-eof-power-mode;
qcom,mdss-dsi-bllp-power-mode;
qcom,mdss-dsi-lane-0-state;
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-panel-timings = [8B 1F 14 00 45 4A 19 23 23 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <255>;
qcom,mdss-dsi-dma-trigger = <4>;
qcom,mdss-dsi-mdp-trigger = <0>;
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>; /* This field is necessory! */
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 = 0, i;
int rc;
struct property *data;
u32 tmp[MDSS_DSI_RST_SEQ_LEN];
*rst_len = 0;
data = of_find_property(np, name, &num);
num /= sizeof(u32);
if (!data || !num || num > MDSS_DSI_RST_SEQ_LEN || num % 2) {
pr_debug("%s:%d, error reading %s, length found = %d\n",
__func__, __LINE__, name, num); /* I think here pr_debug should use pr_err. */
} 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 = 0; i < num; ++i)
rst_seq[i] = tmp[i];
*rst_len = num;
}
}
return 0;
}
static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
{
int rc = 0;
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, 1);
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, 0);
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 = 0;
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, 1);
break;
case MDSS_EVENT_PANEL_OFF:
rc = dsi_panel_handler(pdata, 0);
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;
}
Tools→Options for xshell
delimitor:
\ :;`!@#$%^&*()=+|[]{}'",<>?
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