1 interface for userspace
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,
};
static const struct dev_pm_ops mdss_fb_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mdss_fb_pm_suspend, mdss_fb_pm_resume)
};
static const struct of_device_id mdss_fb_dt_match[] = {
{ .compatible = "qcom,mdss-fb",},
{}
};
EXPORT_COMPAT("qcom,mdss-fb");
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,
},
};
2 panel related (dsi_panel_v2.c)
static int __devinit dsi_panel_probe(struct platform_device *pdev)
{
int rc = 0;
static struct dsi_panel_common_pdata vendor_pdata;
static const char *panel_name;
pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
if (!pdev->dev.of_node)
return -ENODEV;
panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
if (!panel_name)
pr_debug("%s:%d, panel name not specified\n",
__func__, __LINE__);
else
pr_debug("%s: Panel Name = %s\n", __func__, panel_name);
rc = dsi_panel_init();
if (rc) {
pr_err("dsi_panel_init failed %d\n", rc);
goto dsi_panel_probe_error;
}
rc = dsi_panel_parse_dt(pdev, &vendor_pdata, &panel_private->bl_ctrl);
if (rc) {
pr_err("dsi_panel_parse_dt failed %d\n", rc);
goto dsi_panel_probe_error;
}
vendor_pdata.on = dsi_panel_on; // panel on initial command
vendor_pdata.off = dsi_panel_off; // panel off command
vendor_pdata.reset = dsi_panel_reset; // panel reset
vendor_pdata.bl_fnc = dsi_panel_bl_ctrl; // panel backlight control
rc = dsi_panel_device_register_v2(pdev, &vendor_pdata,
panel_private->bl_ctrl); // dsi_v2.c
if (rc) {
pr_err("dsi_panel_device_register_v2 failed %d\n", rc);
goto dsi_panel_probe_error;
}
return 0;
dsi_panel_probe_error:
dsi_panel_deinit();
return rc;
}
static int __devexit dsi_panel_remove(struct platform_device *pdev)
{
dsi_panel_deinit();
return 0;
}
static const struct of_device_id dsi_panel_match[] = {
{.compatible = "qcom,dsi-panel-v2"}, // the name is used for matching platform device(dtsi)
{}
};
static struct platform_driver this_driver = {
.probe = dsi_panel_probe,
.remove = __devexit_p(dsi_panel_remove),
.driver = {
.name = "dsi_v2_panel",
.of_match_table = dsi_panel_match,
},
};
static int __init dsi_panel_module_init(void)
{
return platform_driver_register(&this_driver);
}
module_init(dsi_panel_module_init);
3 dsi of host and dsi engine
These functionality are in dsi_v2.c, as follow:
dsi_on
dsi_panel_handler
dsi
4 Enabling new lcd in lk
4.1 Add the following code in dev/panel/msm/rules.mk
ifeq ($(PLATFORM),msm8610)
OBJS += \
$(LOCAL_DIR)/xx_mipi_otm8018b_video_fwvga.o \
$(LOCAL_DIR)/mipi_otm8018b_video_fwvga.o \
$(LOCAL_DIR)/mipi_truly_video_wvga.o \
$(LOCAL_DIR)/mipi_truly_cmd_wvga.o
endif
4.2 Add the specfic initial funcition in target/msm8610/target_display.c in the corresponding function: display_init
void display_init(void)
{
uint32_t hw_id = board_hardware_id();
dprintf(SPEW, "display_init(),target_id=%d.\n", hw_id);
switch (hw_id) {
case HW_PLATFORM_QRD:
case HW_PLATFORM_MTP:
case HW_PLATFORM_SURF:
mipi_truly_video_wvga_init(&(panel.panel_info));
panel.clk_func = msm8610_mdss_dsi_panel_clock;
panel.power_func = msm8610_mipi_panel_power;
panel.fb.base = MIPI_FB_ADDR;
panel.fb.width = panel.panel_info.xres;
panel.fb.height = panel.panel_info.yres;
panel.fb.stride = panel.panel_info.xres;
panel.fb.bpp = panel.panel_info.bpp;
panel.fb.format = FB_FORMAT_RGB888;
panel.mdp_rev = MDP_REV_304;
break;
default:
return;
};
if (msm_display_init(&panel)) // This function is the real initial function
{
dprintf(CRITICAL, "Display init failed!\n");
return;
}
display_enable = 1;
}
msm_display_init, msm_display_off, msm_display_on, msm_display_config, msm_fb_alloc are in
platform/msm_shared/display.c, dsi related is in
platform/msm_shared/mipi_dsi.c, such as
mipi_dsi_cmds_tx, mipi_dsi_cmd_bta_sw_trigger, mdss_dsi_panel_initialize, mdss_dsi_config, mipi_dsi_on, mipi_dsi_off
and so on. mdp3 related is in platform/msm_shared/mdp3.c, mdp3.h, such as
mdp_dsi_video_config, mdp_disable, mdp_set_version, mdp_dma_on, mdp_dsi_video_on
, and so on.
4.3 Implement the functionality for the specific lcd
void mipi_booyi_video_fwvga_init(struct msm_panel_info *pinfo)
{
...
pinfo->xres = BOOYI_CPT_FB_WIDTH;
pinfo->yres = BOOYI_CPT_FB_HEIGHT;
pinfo->mipi.mode = DSI_VIDEO_MODE;
pinfo->mipi.traffic_mode = 1;
pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
pinfo->mipi.mdss_dsi_phy_db = &dsi_video_mode_phy_db;
pinfo->mipi.tx_eot_append = TRUE;
pinfo->mipi.lane_swap = 1;
...
}
int mipi_panel_video_fwvga_config(void *pdata)
{
...
ret = mdss_dsi_video_mode_config((pinfo->xres),
(pinfo->yres),
(pinfo->xres),
(pinfo->yres),
(lcdc->h_front_porch),
(lcdc->h_back_porch),
(lcdc->v_front_porch),
(lcdc->v_back_porch),
(lcdc->h_pulse_width),
(lcdc->v_pulse_width),
pinfo->mipi.dst_format,
pinfo->mipi.traffic_mode,
lane_en,
low_pwr_stop_mode,
eof_bllp_pwr,
interleav,
MIPI_DSI0_BASE);
return ret;
}
4.4 Show green color in lk
static void show_color(unsigned int x, unsigned int y,
unsigned char pixel[4])
{
unsigned int i = 0;
unsigned int j = 0;
for (i = y; i < (y + config->height); i++) {
for (j = x; j < (x + config->width); j++) {
/* B */
*((unsigned char *)((int)config->base +
(i * config->width + j) * 3) + 0) = pixel[0];
/* G */
*((unsigned char *)((int)config->base +
(i * config->width + j) * 3) + 1) = pixel[1];
/* R */
*((unsigned char *)((int)config->base +
(i * config->width + j) * 3) + 2) = pixel[2];
}
}
}
void show_green_color(unsigned int x, unsigned int y)
{
unsigned char pixel[4];
/* green */
pixel[0] = 0x00; /* B */
pixel[1] = 0xFF; /* G */
pixel[2] = 0x00; /* R */
pixel[3] = 0xFF; /* A */
show_color(x, y, pixel);
}
5 Remember that dsi timing and lane swap are quite important
If dsi timing is wrong, normally, lcd can't show any picture, it would remain white or black. The timing and other parameters can be got from an excel from qualcomm. Sometimes lane is swapped, because these lanes maybe connect oppositely. So if sometimes lcd can't show any picture, the lane between host and driver ic is maybe opposite.
6 The commands for initialize lcd can be defined as following
#define CMD(cnt, len, cmds...) \
static char booyi_disp_init##cnt[len] = { \
cmds \
}
#define INSERT(cnt, wait) \
{ sizeof(booyi_disp_init##cnt), booyi_disp_init##cnt, wait }
7 dsi bit/core/byte/pixel clk calculation
void dsi_calc_clk_rate(uint32_t *dsiclk_rate, uint32_t *byteclk_rate)
{
uint32_t hbp, hfp, vbp, vfp, hspw, vspw, width, height;
uint32_t bitclk_rate;
int frame_rate, lanes;
width = panel.panel_info.xres;
height = panel.panel_info.yres;
hbp = panel.panel_info.lcdc.h_back_porch;
hfp = panel.panel_info.lcdc.h_front_porch;
hspw = panel.panel_info.lcdc.h_pulse_width;
vbp = panel.panel_info.lcdc.v_back_porch;
vfp = panel.panel_info.lcdc.v_front_porch;
vspw = panel.panel_info.lcdc.v_pulse_width;
lanes = panel.panel_info.mipi.num_of_lanes;
frame_rate = panel.panel_info.mipi.frame_rate;
bitclk_rate = (width + hbp + hfp + hspw) * (height + vbp + vfp + vspw);
bitclk_rate *= frame_rate;
bitclk_rate *= panel.panel_info.bpp;
bitclk_rate /= lanes;
*byteclk_rate = bitclk_rate / 8;
*dsiclk_rate = *byteclk_rate * lanes;
}
8
root@xx:/sys/class/leds # ll
lrwxrwxrwx root root 2009-01-02 13:00 button-backlight -> ../../devices/leds-qpnp-d8b0de00/leds/button-
backlight
lrwxrwxrwx root root 1970-01-02 15:13 flashlight -> ../../devices/qcom,leds-gpio-flash.57/leds/flashlig
ht
lrwxrwxrwx root root 2009-01-02 13:00 lcd-backlight -> ../../devices/fd900000.qcom,mdss_mdp/qcom,mdss_f
b_primary.119/leds/lcd-backlight
lrwxrwxrwx root root 1970-01-02 15:13 mmc0:: -> ../../devices/msm_sdcc.1/leds/mmc0::
lrwxrwxrwx root root 1970-01-02 15:13 mmc1:: -> ../../devices/msm_sdcc.2/leds/mmc1::
lrwxrwxrwx root root 1970-01-02 15:13 rgb -> ../../devices/leds-qpnp-d8b10000/leds/rgb
root@xx:/sys/class/graphics/fb0 # ll
-rw-r--r-- root root 4096 1970-01-02 15:13 bits_per_pixel // 32bits
-rw-r--r-- root root 4096 1970-01-02 15:13 blank //
-rw-r--r-- root root 4096 1970-01-02 15:13 console
-rw-r--r-- root root 4096 1970-01-02 15:13 cursor
-r--r--r-- root root 4096 1970-01-02 15:13 dev
-rw-r--r-- root root 4096 1970-01-02 15:13 mode
-rw-r--r-- root root 4096 1970-01-02 15:13 modes // U:480*854p-5
-r--r--r-- root root 4096 1970-01-02 15:13 msm_fb_split
-r--r--r-- root root 4096 1970-01-01 01:28 msm_fb_type // mipi dsi video panel
-r--r--r-- root root 4096 1970-01-02 15:13 name // mdss_fb_80000
-rw-r--r-- root root 4096 1970-01-02 15:13 pan
drwxr-xr-x root root 1970-01-01 01:28 power
-rw-r--r-- root root 4096 1970-01-02 15:13 rotate
-r--r--r-- root root 4096 1970-01-02 15:13 show_blank_event // panel_power_on = 0
-rw-r--r-- root root 4096 1970-01-02 15:13 state
-r--r--r-- root root 4096 1970-01-02 15:13 stride
lrwxrwxrwx root root 1970-01-02 15:13 subsystem -> ../../../../class/graphics
-rw-r--r-- root root 4096 1970-01-01 01:28 uevent
-rw-r--r-- root root 4096 1970-01-02 15:13 virtual_size // 480, 1708
-r--r--r-- root root 4096 1970-01-01 01:28 vsync_event
root@xx:/sys/devices/soc0 # ll
-r--r--r-- root root 4096 1970-01-02 15:23 accessory_chip
-r--r--r-- root root 4096 1970-01-02 15:23 build_id // 8x10A-DAAAANAZA-40000000
-r--r--r-- root root 4096 1970-01-01 01:28 hw_platform
-r--r--r-- root root 4096 1970-01-02 15:23 machine // Snapdragon
-r--r--r-- root root 4096 1970-01-02 15:23 platform_subtype
-r--r--r-- root root 4096 1970-01-01 01:28 platform_version
-r--r--r-- root root 4096 1970-01-02 15:23 pmic_die_revision
-r--r--r-- root root 4096 1970-01-02 15:23 pmic_model
drwxr-xr-x root root 1970-01-02 15:23 power
-r--r--r-- root root 4096 1970-01-02 15:23 raw_id
-r--r--r-- root root 4096 1970-01-02 15:23 raw_version
-r--r--r-- root root 4096 1970-01-02 15:23 revision // 1.1
-r--r--r-- root root 4096 1970-01-01 01:28 soc_id // 162
lrwxrwxrwx root root 1970-01-02 15:23 subsystem -> ../../bus/soc
-rw-r--r-- root root 4096 1970-01-02 15:23 uevent
-r--r--r-- root root 4096 1970-01-02 15:23 vendor // qualcomm
root@xx:/sys/devices/fd900000.qcom,mdss_mdp # ll
lrwxrwxrwx root root 1970-01-02 15:27 driver -> ../../bus/platform/drivers/mdp3
-r--r--r-- root root 4096 1970-01-02 15:27 modalias
drwxr-xr-x root root 1970-01-01 01:28 power
drwxr-xr-x root root 1970-01-01 01:28 qcom,mdss_fb_primary.119
lrwxrwxrwx root root 1970-01-02 15:27 subsystem -> ../../bus/platform
-rw-r--r-- root root 4096 1970-01-01 01:28 uevent
root@VodafoneSmart4:/sys/devices/fd900000.qcom,mdss_mdp # cat uevent
DRIVER=mdp3
OF_NAME=qcom,mdss_mdp
OF_FULLNAME=/soc/qcom,mdss_mdp@fd900000
OF_COMPATIBLE_0=qcom,mdss_mdp3
OF_COMPATIBLE_N=1
MODALIAS=of:Nqcom,mdss_mdpT<NULL>Cqcom,mdss_mdp3
# mount -t debugfs debugfs /sys/kernel/debug
root@xx:/sys/kernel/debug/ion # ll
-rw-rw-r-- root root 0 1970-01-01 01:28 250
-rw-rw-r-- root root 0 1970-01-02 15:33 4080
-rw-rw-r-- root root 0 1970-01-02 15:33 4083
-rw-rw-r-- root root 0 1970-01-01 01:28 415
-rw-rw-r-- root root 0 2009-01-02 13:00 adsprpc-smd
-rw-rw-r-- root root 0 1970-01-02 15:33 audio_acdb_client
-rw-rw-r-- root root 0 1970-01-02 15:33 audio_client
-rw-rw-r-- root root 0 1970-01-01 00:00 fd900000.qcom,mdss_mdp
-rw-rw-r-- root root 0 1970-01-01 00:00 iommu
-rw-rw-r-- root root 0 1970-01-01 00:00 kmalloc
-rw-rw-r-- root root 0 1970-01-01 00:00 pil
-rw-rw-r-- root root 0 1970-01-01 00:00 pil_1
-rw-rw-r-- root root 0 1970-01-01 00:00 pil_2
-rw-rw-r-- root root 0 1970-01-01 00:00 qsecom
-rw-rw-r-- root root 0 1970-01-01 00:00 qsee_log
-rw-rw-r-- root root 0 1970-01-01 00:00 qseecom-kernel
-rw-rw-r-- root root 0 1970-01-01 00:00 vmalloc
-rw-rw-r-- root root 0 1970-01-01 01:28 voc_cal
-rw-rw-r-- root root 0 1970-01-01 01:28 voip_client
root@xx:/sys/kernel/debug/ion # cat fd900000.qcom*
cat fd900000.qcom*
heap_name: size_in_bytes : handle refcount : buffer
iommu: 195000 : 1 : d7144100 // decimal size is 1658880, actual size is 1639680. need to align
iommu: 195000 : 1 : d27d6780
root@VodafoneSmart4:/sys/kernel/debug/ion # cat iommu
client pid size
----------------------------------------------------
init 1 8192
fd900000.qcom,mdss_mdp 1 3317760 // Total framebuffer decimal size
----------------------------------------------------
orphaned allocations (info is from last known client):
Binder_2 250 1658880 0 1
Binder_2 250 1658880 0 1
Binder_2 250 1658880 0 1
----------------------------------------------------
total orphaned 4976640
total 8302592
----------------------------------------------------
Cached Pools:
0 order 9 highmem pages in pool = 0 total
0 order 9 lowmem pages in pool = 0 total
0 order 8 highmem pages in pool = 0 total
0 order 8 lowmem pages in pool = 0 total
0 order 4 highmem pages in pool = 0 total
0 order 4 lowmem pages in pool = 0 total
0 order 0 highmem pages in pool = 0 total
1971 order 0 lowmem pages in pool = 7b3000 total
Uncached Pools:
0 order 9 highmem pages in pool = 0 total
0 order 9 lowmem pages in pool = 0 total
0 order 8 highmem pages in pool = 0 total
1 order 8 lowmem pages in pool = 100000 total
0 order 4 highmem pages in pool = 0 total
59 order 4 lowmem pages in pool = 3b0000 total
0 order 0 highmem pages in pool = 0 total
42 order 0 lowmem pages in pool = 2a000 total
Total bytes in pool: c8d000