TE Signal: The signal can connect a resistor for testing it. The following commands need to send to driver ic of panel used foropening TE output: 0x35, 0x00
Voltage: 1.8V, 2.85V, 1.2V // voltage is right or wrong? swing?
For 720P or 1080P panel, analog voltage should be paid more attention to, because maybe the supply voltage value is +/- 5V. If so, an extra DCDC converter should be added to supply this voltage to panel, such as R1286-e, which is designed for AMOLED display power source. It contains a step up DC/DC converter and an inverting DC/DC converter. It generates boosted output voltage to4.6V ~ 5.8V(Selectable) and negative voltage down to -2.0V ~ -6.0V(Selectable).
Now let's consider how to enable this converter. Actually, it's simple, first, add the power PVcc and Vcc. Then, according to the reference design, connect all the other pin. Voutn / Voutp is the positive/negative output pin. CE is the enable pin. If we wanna the chip work, CE should be set to HIGH. If we wanna disable the chip, just set CE to LOW.
Reset: 20, 2, 20 // success or fail?
PWM output right or wrong? If the source of PWM is panel, we can check if panel commands are sent successfully?
CLOCK P/N: Check using oscilloscope(OSC)
DATA0 P/N: Check using oscilloscope and check the initial commands are right or wrong?
DATA1 P/N: Check using oscilloscope and check HDST is right or wrong?
For every frame, VFP is at the front of data, and VBP is at the back of data
Power supply mode: LDO or DCDC. This mode should be selected via writing registers. Normally, the default mode is DCDC. So how to select LDO mode? As below:
#define DSIPHY_LDO_MODE_1P2_EN BIT(6) #define DSIPHY_LDO_VREF_SEL_MAX (BIT(5) | BIT(4) | BIT(3)) #define DSIPHY_LDO_VREF_DIV_EN BIT(2) #define DSIPHY_LDO_VREF_CGM_EN BIT(1) #define DSIPHY_LDO_MODE_0P4_EN BIT(0) int data; --- a/drivers/video/msm/mdss/msm_mdss_io_8974.c +++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c @@ -569,7 +569,7 @@ void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on) void mdss_dsi_phy_init(struct mdss_panel_data *pdata) { struct mdss_dsi_phy_ctrl *pd; - int i, off, ln, offset; + int i, off, ln, offset, data; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, @@ -610,9 +610,12 @@ void mdss_dsi_phy_init(struct mdss_panel_data *pdata) MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]); /* LDO ctrl 0 */ - if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1) - MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00); - else + if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1) { + /* mipi voltage supply used LDO mode, rather than DCDC, Voltage reference is 0.475V */ + data = DSIPHY_LDO_VREF_SEL_MAX | DSIPHY_LDO_VREF_DIV_EN | + DSIPHY_LDO_MODE_0P4_EN; /* When LDO_VREF_DIV_EN=1, 111: 0.475V */ + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, data); + } else MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00); off = 0x0440; /* phy timing ctrl 0 - 11 */
Common-mode rejection / High frequency common mode inductor shoud be paid attention to.
共模电感(Common mode Choke),也叫共模扼流圈,常用于电脑的开关电源中过滤共模的电磁干扰信号。在板卡设计中,共模电感也是起EMI滤波的作用,用于抑制高速信号线产生的电磁波向外辐射发射。(baidu baike)
电源滤波器要抑制的噪声可分为以下的二种:
...panel...dtsi These fields in dtsi shoud be corresponding to panel code, such as mdss_dsi_panel.c
msm8226-mdss.dtsi // common initial commands, such as voltage supply pin, gpio, lane config, regulator setting and dsi, mdp, fb
msm8226-mdss-panel.dtsi // include specific panel
msm8226-mtp.dtsi // Basic information, such as splash screen, mdss_mdp and so on.
pwm source needs to be paid attention to. maybe PMIC or panel.
Some panel only use two lanes, the swap of lane should be paid attention to too, because normally, there are four lanes, hardware engineer can select data1, data2 or data0, data1 or data2, data3 or data3, data4.
RGB sequence should be paid attention to too.
Timing control should be paid much more attention to too, because this is related to panel clock.
reset time is at LP11 or LP00 or other place? This position maybe affects the reset of orise IC, which then can't work.
If the log is stopped and hung at lk switching to kernel from serial port. maybe NULL pointer is encountered or dead cycle is encountered, then dloader will be came into.
How to enable engineer mode of orise chip of panel, as follow:
C1A0 -> 0x80 and B3D0 -> 0x14
Local static variables should be noticed.
3.1 How to test width of pulse, just click down CURSOR. Then you can test width usingNAVIGATION.
If we wanna test the actual voltage, we can adjust MENU: Meas. Type fromTimetoVoltage.
3.2
Please pay attention to the permission which should be 644!
ro.qualcomm.cabl=0 // This field is used for closing cabl which is corresponding to histogram in kernel.
ro.sf.lcd_density=217 // This density affects specific picture size,sqrt root(x*x + y*y)/size, Eg: sqrt root(960*960+540*540)/5.0.
# Skip /sys/power/wait_for_fb_* nodes and
# force FB to be always on
debug.sf.fb_always_on=1
debug.composition.type=dyn
debug.gralloc.map_fb_memory=0
debug.hwc.dynThreshold=1.5
dalvik.vm.heapsize=36m
dev.pm.dyn_samplingrate=1
ro.hdmi.enable=true // for mobile phone, hdmi shouldn't be enabled.
tunnel.decode=true
First, MMSS_DSI_0_PHY_REG_DISPHY_REGULATOR_CTRL_0 BIT[0], If this bit's value is 1, it means DC DC mode is enabled. But DC DC mode and LDO mode can't be enabled at the same time, so DSIPHY_LDO_CNTRL[LDO_MODE_EN] must be set to 0.
If LDO should be enabled, DCDC mode must be disabled.
msm: mdss: use LDO mode in DSI PHY on 8x10. DSI PHY supports two regulator modes: LDO and DCDC.
While DCDC offers power efficiency, it requires an external inductor which adds to the BOM cost. On 8x10, it is required to use LDO mode to save the
extra cost.
If we wanna adjust amplitude of HS mode, regulator[0] and DSI_DSIPHY_LDO_CNTRL[0,1,2, [3,4,5]] should be adjusted. Then DSIPHY regulator reference voltage can be selected, such as 0.4V, 0.415V, 0.385V, 0.37V, 0.43V, 0.445V, 0.46V, 0.475V and so on. According to select these voltages, the amplitude of HS mode can be changed, such as [66mV, 413mV], [20mV, 366mV] and so on. Basically, these results meet the mipi d-phy specification.
frameworks/base/core/res/res/values/config.xml: <integer name="config_screenBrightnessSettingMinimum">10</integer>
frameworks/base/core/res/res/values/config.xml: <integername="config_screenBrightnessSettingMaximum">255</integer>
frameworks/base/core/res/res/values/config.xml: <integername="config_screenBrightnessSettingDefault">102</integer>
frameworks/base/core/res/res/values/config.xml: <integer name="config_screenBrightnessDim">10</integer>
Embedded DisplayPort (eDP) 1.0 standard was adopted in December 2008. It aims to define a standardized display panel interface for internal connections; e.g., graphics cards to notebook display panels.[20] It has advanced power-saving features including seamless refresh rate switching. Version 1.1 was approved in October 2009 followed by version 1.1a in November 2009. Version 1.2 was approved in May 2010 and includes DisplayPort 1.2 data rates, 120 Hz sequential color monitors, and a new display panel control protocol that works through the AUX channel.[15] Version 1.3 was published in February 2011; it includes a new Panel Self-Refresh (PSR) feature developed to save system power and further extend battery life in portable PC systems.[21] PSR mode allows GPU to enter power saving state in between frame updates by including framebuffermemory in the display panel controller.[15] Version 1.4 is expected before end of 2012; it reduces power consumption with partial-frame updates in PSR mode, regional backlight control, lower interface voltage, and additional link rates; the auxiliary channel supports multi-touch panel data to accommodate different form factors.[22]
write /proc/sys/kernel/printk "7 6 1 7"
mdss_mdp_display_wakeup_time(mdss_mdp_ctl *, ktime_t *) : int mdss_mdp_overlay_update_pm(mdss_overlay_private *) : void mdss_mdp_overlay_kickoff(msm_fb_data_type *, mdp_display_commit *) : intThe function mdss_mdp_display_wakeup_time will calculate the actual wakeup time and transfer this time to timer: activate_event_timer which is implemented in event_timer.c by qualcomm(arch/arm/mach-msm/event_timer.c)
static void mdss_mdp_overlay_update_pm(struct mdss_overlay_private *mdp5_data) { ktime_t wakeup_time; if (!mdp5_data->cpu_pm_hdl) return; if (mdss_mdp_display_wakeup_time(mdp5_data->ctl, &wakeup_time)) return; activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time); }
int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl, ktime_t *wakeup_time) { struct mdss_panel_info *pinfo; u32 clk_rate, clk_period; u32 current_line, total_line; u32 time_of_line, time_to_vsync; ktime_t current_time = ktime_get(); // Get current time if (!ctl->read_line_cnt_fnc) return -ENOSYS; pinfo = &ctl->panel_data->panel_info; if (!pinfo) return -ENODEV; clk_rate = mdss_mdp_get_pclk_rate(ctl); clk_rate /= 1000; /* in kHz */ if (!clk_rate) return -EINVAL; /* * calculate clk_period as pico second to maintain good * accuracy with high pclk rate and this number is in 17 bit * range. */ clk_period = 1000000000 / clk_rate; if (!clk_period) return -EINVAL; time_of_line = (pinfo->lcdc.h_back_porch + pinfo->lcdc.h_front_porch + pinfo->lcdc.h_pulse_width + pinfo->xres) * clk_period; time_of_line /= 1000; /* in nano second */ if (!time_of_line) return -EINVAL; current_line = ctl->read_line_cnt_fnc(ctl); // Get the current line from mdp register total_line = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width + pinfo->yres; if (current_line > total_line) return -EINVAL; time_to_vsync = time_of_line * (total_line - current_line); // Get the remaining time if (!time_to_vsync) return -EINVAL; *wakeup_time = ktime_add_ns(current_time, time_to_vsync); // transfer to function parameter pr_debug("clk_rate=%dkHz clk_period=%d cur_line=%d tot_line=%d\n", clk_rate, clk_period, current_line, total_line); pr_debug("time_to_vsync=%d current_time=%d wakeup_time=%d\n", time_to_vsync, (int)ktime_to_ms(current_time), (int)ktime_to_ms(*wakeup_time)); return 0; }
static inline u32 mdss_mdp_video_line_count(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_video_ctx *ctx; u32 line_cnt = 0; if (!ctl || !ctl->priv_data) goto line_count_exit; ctx = ctl->priv_data; mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); line_cnt = mdp_video_read(ctx, MDSS_MDP_REG_INTF_LINE_COUNT); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); line_count_exit: return line_cnt; }
12.2 vsync interface
The following function is in mdss_mdp_overlay.c
static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void __user *argp)
case MSMFB_VSYNC_CTRL: case MSMFB_OVERLAY_VSYNC_CTRL: if (!copy_from_user(&val, argp, sizeof(val))) { ret = mdss_mdp_overlay_vsync_ctrl(mfd, val); } else { pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed (%d)\n", ret); ret = -EFAULT; } break;
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en) { struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd); int rc; <span style="white-space:pre"> </span>/* ... omit ... */ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); if (en) rc = ctl->add_vsync_handler(ctl, &ctl->vsync_handler); // This is the function pointer else rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler); // This is the function pointer mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); return rc; }
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl) { struct mdss_data_type *mdata; struct mdss_panel_info *pinfo; struct mdss_mdp_video_ctx *ctx; struct mdss_mdp_mixer *mixer; struct intf_timing_params itp = {0}; u32 dst_bpp; int i; mdata = ctl->mdata; pinfo = &ctl->panel_data->panel_info; mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT); /* ...omit... */ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num, mdss_mdp_video_vsync_intr_done, ctl); mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_UNDER_RUN, ctl->intf_num, mdss_mdp_video_underrun_intr_done, ctl); itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width; /* ...omit.. */ if (mdss_mdp_video_timegen_setup(ctl, &itp)) { pr_err("unable to get timing parameters\n"); return -EINVAL; } mdp_video_write(ctx, MDSS_MDP_REG_INTF_PANEL_FORMAT, ctl->dst_format); ctl->stop_fnc = mdss_mdp_video_stop; ctl->display_fnc = mdss_mdp_video_display; ctl->wait_fnc = mdss_mdp_video_wait4comp; ctl->read_line_cnt_fnc = mdss_mdp_video_line_count; ctl->add_vsync_handler = mdss_mdp_video_add_vsync_handler; ctl->remove_vsync_handler = mdss_mdp_video_remove_vsync_handler; ctl->config_fps_fnc = mdss_mdp_video_config_fps; return 0; }
Now let us see how to add vsync handler and remove vsync handler:
static int mdss_mdp_video_add_vsync_handler(struct mdss_mdp_ctl *ctl, struct mdss_mdp_vsync_handler *handle) { struct mdss_mdp_video_ctx *ctx; unsigned long flags; int ret = 0; bool irq_en = false; ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data; spin_lock_irqsave(&ctx->vsync_lock, flags); if (!handle->enabled) { handle->enabled = true; list_add(&handle->list, &ctx->vsync_handlers); irq_en = true; } spin_unlock_irqrestore(&ctx->vsync_lock, flags); if (irq_en) video_vsync_irq_enable(ctl, false); exit: return ret; } static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl, struct mdss_mdp_vsync_handler *handle) { struct mdss_mdp_video_ctx *ctx; unsigned long flags; bool irq_dis = false; ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data; spin_lock_irqsave(&ctx->vsync_lock, flags); if (handle->enabled) { handle->enabled = false; list_del_init(&handle->list); irq_dis = true; } spin_unlock_irqrestore(&ctx->vsync_lock, flags); if (irq_dis) video_vsync_irq_disable(ctl); return 0; }
For video_vsync_irq_enable and video_vsync_irq_disable, the implementation is as follow, this is simple, only need to enable or disable the corresponding registers.
static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear) { struct mdss_mdp_video_ctx *ctx = ctl->priv_data; if (atomic_inc_return(&ctx->vsync_ref) == 1) mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num); else if (clear) mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num); } static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_video_ctx *ctx = ctl->priv_data; if (atomic_dec_return(&ctx->vsync_ref) == 0) mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num); }