void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd) { /*--------------------------------------------------------- // kick off PPP engine /---------------------------------------------------------*/ if (term == MDP_PPP_TERM) { if (mdp_debug[MDP_PPP_BLOCK]) { jiffies_to_timeval(jiffies, &mdp_ppp_timeval); } INIT_COMPLETION(mdp_ppp_comp); mdp_ppp_waiting = TRUE; // let's turn on PPP block mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE); //HWIO_OUT(MDP_DISPLAY0_START, 0x1000); outpdw(MDP_BASE + 0x30, 0x1000); wait_for_completion_interruptible(&mdp_ppp_comp); if (mdp_debug[MDP_PPP_BLOCK]) { struct timeval now; jiffies_to_timeval(jiffies, &now); mdp_ppp_timeval.tv_usec = now.tv_usec - mdp_ppp_timeval.tv_usec; MSM_FB_INFO("MDP-PPP: %d\n", (int)mdp_ppp_timeval.tv_usec); } } else if (term == MDP_DMA2_TERM) { if (mdp_debug[MDP_DMA2_BLOCK]) { MSM_FB_INFO("MDP-DMA2: %d\n", (int)mdp_dma2_timeval.tv_usec); jiffies_to_timeval(jiffies, &mdp_dma2_timeval); } // DMA update timestamp mdp_dma2_last_update_time = ktime_get_real(); // let's turn on DMA2 block // mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON,FALSE); #ifdef CONFIG_FB_MSM_MDP22 outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0); // start DMA #else outpdw(MDP_BASE + 0x0044, 0x0); // start DMA #endif } else if (term == MDP_DMA_S_TERM) { mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); outpdw(MDP_BASE + 0x0048, 0x0); // start DMA } }
static void mdp_set_vsync(unsigned long data) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; struct msm_fb_panel_data *pdata = NULL; pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; if ((pdata) && (pdata->set_vsync_notifier == NULL)) return; init_timer(&mfd->vsync_resync_timer); mfd->vsync_resync_timer.function = mdp_set_vsync; mfd->vsync_resync_timer.data = data; mfd->vsync_resync_timer.expires = jiffies + mfd->panel_info.lcd.vsync_notifier_period; add_timer(&mfd->vsync_resync_timer); if ((mfd->panel_info.lcd.vsync_enable) && (mfd->panel_power_on) && (!mfd->vsync_handler_pending)) { mfd->vsync_handler_pending = TRUE; if (!queue_work(mdp_vsync_wq, &mfd->vsync_resync_worker)) { MSM_FB_INFO ("mdp_set_vsync: can't queue_work! -> needs to increase vsync_resync_timer_duration\n"); } } else { MSM_FB_DEBUG ("mdp_set_vsync failed! EN:%d PWR:%d PENDING:%d\n", mfd->panel_info.lcd.vsync_enable, mfd->panel_power_on, mfd->vsync_handler_pending); } }
static void mipi_s6d6aa0_set_panel(struct mipi_s6d6aa0_data *dsi_data) { dsi_data->panel = dsi_data->pdata->panels[0]; MSM_FB_INFO("panel: %s\n", dsi_data->panel->name); dsi_data->panel_data.panel_info = *dsi_data->panel->pctrl->get_panel_info(); }
void mipi_dsi_set_default_panel(struct mipi_dsi_data *dsi_data) { if (dsi_data->default_panels[0] != NULL) dsi_data->panel = dsi_data->default_panels[0]; else dsi_data->panel = dsi_data->panels[0]; MSM_FB_INFO("default panel: %s\n", dsi_data->panel->name); dsi_data->panel_data.panel_info = *dsi_data->panel->pctrl->get_panel_info(); dsi_data->panel_data.panel_info.width = dsi_data->panel->width; dsi_data->panel_data.panel_info.height = dsi_data->panel->height; }
void mipi_dsi_set_default_panel(struct mipi_dsi_data *dsi_data) { if (dsi_data->default_panels[0] != NULL) dsi_data->panel = dsi_data->default_panels[0]; else dsi_data->panel = dsi_data->panels[0]; MSM_FB_INFO("default panel: %s\n", dsi_data->panel->name); dsi_data->panel_data.panel_info = *dsi_data->panel->pctrl->get_panel_info(); dsi_data->panel_data.panel_info.width = dsi_data->panel->width; dsi_data->panel_data.panel_info.height = dsi_data->panel->height; #ifdef CONFIG_FB_MSM_RECOVER_PANEL dsi_data->nvrw_panel_detective = false; #endif }
uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd) { uint32 elapsed_usec_time; uint32 lcd_line; ktime_t last_vsync_timetick_local; ktime_t curr_time; unsigned long flag; if ((!mfd->panel_info.lcd.vsync_enable) || (!vsync_mode)) return 0; spin_lock_irqsave(&mdp_spin_lock, flag); last_vsync_timetick_local = mfd->last_vsync_timetick; spin_unlock_irqrestore(&mdp_spin_lock, flag); curr_time = ktime_get_real(); elapsed_usec_time = ((curr_time.tv.sec - last_vsync_timetick_local.tv.sec) * 1000000) + ((curr_time.tv.nsec - last_vsync_timetick_local.tv.nsec) / 1000); elapsed_usec_time = elapsed_usec_time % mfd->lcd_ref_usec_time; /* lcd line calculation referencing to line counter = 0 */ lcd_line = (elapsed_usec_time * mfd->total_lcd_lines) / mfd->lcd_ref_usec_time; /* lcd line adjusment referencing to the actual line counter at vsync */ lcd_line = (mfd->total_lcd_lines - mfd->panel_info.lcd.v_back_porch + lcd_line) % (mfd->total_lcd_lines + 1); if (lcd_line > mfd->total_lcd_lines) { MSM_FB_INFO ("mdp_get_lcd_line_counter: mdp_lcd_rd_cnt >= mfd->total_lcd_lines error!\n"); } return lcd_line; }
uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd) { uint32 elapsed_usec_time; uint32 lcd_line; ktime_t last_vsync_timetick_local; ktime_t curr_time; unsigned long flag; if ((!mfd->panel_info.lcd.vsync_enable) || (!vsync_mode)) return 0; spin_lock_irqsave(&mdp_spin_lock, flag); last_vsync_timetick_local = mfd->last_vsync_timetick; spin_unlock_irqrestore(&mdp_spin_lock, flag); curr_time = ktime_get_real(); elapsed_usec_time = ktime_to_us(ktime_sub(curr_time, last_vsync_timetick_local)); elapsed_usec_time = elapsed_usec_time % mfd->lcd_ref_usec_time; /* */ lcd_line = (elapsed_usec_time * mfd->total_lcd_lines) / mfd->lcd_ref_usec_time; /* */ lcd_line = (mfd->total_lcd_lines - mfd->panel_info.lcd.v_back_porch + lcd_line) % (mfd->total_lcd_lines + 1); if (lcd_line > mfd->total_lcd_lines) { MSM_FB_INFO ("mdp_get_lcd_line_counter: mdp_lcd_rd_cnt >= mfd->total_lcd_lines error!\n"); } return lcd_line; }
static int mddi_probe(struct platform_device *pdev) { struct msm_fb_data_type *mfd; struct platform_device *mdp_dev = NULL; struct msm_fb_panel_data *pdata = NULL; int rc; resource_size_t size ; u32 clk_rate; if ((pdev->id == 0) && (pdev->num_resources >= 0)) { mddi_pdata = pdev->dev.platform_data; size = resource_size(&pdev->resource[0]); msm_pmdh_base = ioremap(pdev->resource[0].start, size); MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n", pdev->resource[0].start, (int) msm_pmdh_base); if (unlikely(!msm_pmdh_base)) return -ENOMEM; if (mddi_pdata && mddi_pdata->mddi_power_save) mddi_pdata->mddi_power_save(1); mddi_resource_initialized = 1; return 0; } if (!mddi_resource_initialized) return -EPERM; mfd = platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) return -ENOMEM; mdp_dev = platform_device_alloc("mdp", pdev->id); if (!mdp_dev) return -ENOMEM; /* * link to the latest pdev */ mfd->pdev = mdp_dev; mfd->dest = DISPLAY_LCD; /* * alloc panel device data */ if (platform_device_add_data (mdp_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))) { printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n"); platform_device_put(mdp_dev); return -ENOMEM; } /* * data chain */ pdata = mdp_dev->dev.platform_data; pdata->on = mddi_on; pdata->off = mddi_off; pdata->next = pdev; pdata->clk_func = pmdh_clk_func; /* * get/set panel specific fb info */ mfd->panel_info = pdata->panel_info; if (mfd->index == 0) mfd->fb_imgType = MSMFB_DEFAULT_TYPE; else mfd->fb_imgType = MDP_RGB_565; clk_rate = mfd->panel_info.clk_max; if (mddi_pdata && mddi_pdata->mddi_sel_clk && mddi_pdata->mddi_sel_clk(&clk_rate)) printk(KERN_ERR "%s: can't select mddi io clk targate rate = %d\n", __func__, clk_rate); if (clk_set_max_rate(mddi_clk, clk_rate) < 0) printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); mfd->panel_info.clk_rate = mfd->panel_info.clk_min; if (!mddi_client_type) mddi_client_type = mfd->panel_info.lcd.rev; else if (!mfd->panel_info.lcd.rev) printk(KERN_ERR "%s: mddi client is trying to revert back to type 1 !!!\n", __func__); /* * set driver data */ platform_set_drvdata(mdp_dev, mfd); rc = pm_runtime_set_active(&pdev->dev); if (rc < 0) printk(KERN_ERR "pm_runtime: fail to set active\n"); rc = 0; pm_runtime_enable(&pdev->dev); #ifndef CONFIG_MSM_BUS_SCALING mfd->ebi1_clk = clk_get(NULL, "ebi1_mddi_clk"); if (IS_ERR(mfd->ebi1_clk)) return PTR_ERR(mfd->ebi1_clk); clk_set_rate(mfd->ebi1_clk, 65000000); #endif /* * register in mdp driver */ rc = platform_device_add(mdp_dev); if (rc) goto mddi_probe_err; pdev_list[pdev_list_cnt++] = pdev; #ifdef CONFIG_HAS_EARLYSUSPEND mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; mfd->mddi_early_suspend.suspend = mddi_early_suspend; mfd->mddi_early_suspend.resume = mddi_early_resume; register_early_suspend(&mfd->mddi_early_suspend); #endif return 0; mddi_probe_err: platform_device_put(mdp_dev); return rc; }
static int mddi_ext_probe(struct platform_device *pdev) { struct msm_fb_data_type *mfd; struct platform_device *mdp_dev = NULL; struct msm_fb_panel_data *pdata = NULL; int rc; resource_size_t size ; u32 clk_rate; if ((pdev->id == 0) && (pdev->num_resources >= 0)) { mddi_ext_pdata = pdev->dev.platform_data; size = resource_size(&pdev->resource[0]); msm_emdh_base = ioremap(pdev->resource[0].start, size); MSM_FB_INFO("external mddi base address = 0x%x\n", pdev->resource[0].start); if (unlikely(!msm_emdh_base)) return -ENOMEM; mddi_ext_resource_initialized = 1; return 0; } if (!mddi_ext_resource_initialized) return -EPERM; mfd = platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) return -ENOMEM; mdp_dev = platform_device_alloc("mdp", pdev->id); if (!mdp_dev) return -ENOMEM; mfd->pdev = mdp_dev; mfd->dest = DISPLAY_EXT_MDDI; if (platform_device_add_data (mdp_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))) { printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n"); platform_device_put(mdp_dev); return -ENOMEM; } pdata = mdp_dev->dev.platform_data; pdata->on = mddi_ext_on; pdata->off = mddi_ext_off; pdata->next = pdev; mfd->panel_info = pdata->panel_info; mfd->fb_imgType = MDP_RGB_565; clk_rate = mfd->panel_info.clk_max; if (mddi_ext_pdata && mddi_ext_pdata->mddi_sel_clk && mddi_ext_pdata->mddi_sel_clk(&clk_rate)) printk(KERN_ERR "%s: can't select mddi io clk targate rate = %d\n", __func__, clk_rate); if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0) printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); mfd->panel_info.clk_rate = mfd->panel_info.clk_min; platform_set_drvdata(mdp_dev, mfd); rc = platform_device_add(mdp_dev); if (rc) goto mddi_ext_probe_err; pdev_list[pdev_list_cnt++] = pdev; #ifdef CONFIG_HAS_EARLYSUSPEND mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend; mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume; register_early_suspend(&mfd->mddi_ext_early_suspend); #endif return 0; mddi_ext_probe_err: platform_device_put(mdp_dev); return rc; }
void mdp_config_vsync(struct msm_fb_data_type *mfd) { /* vsync on primary lcd only for now */ if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1) || (!vsync_mode)) { goto err_handle; } vsync_clk_status = 0; if (mfd->panel_info.lcd.vsync_enable) { mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch + mfd->panel_info.lcd.v_front_porch + mfd->panel_info.lcd.v_pulse_width; mfd->total_lcd_lines = mfd->panel_info.yres + mfd->total_porch_lines; mfd->lcd_ref_usec_time = 100000000 / mfd->panel_info.lcd.refx100; mfd->vsync_handler_pending = FALSE; mfd->last_vsync_timetick.tv.sec = 0; mfd->last_vsync_timetick.tv.nsec = 0; #ifdef MDP_HW_VSYNC if (mdp_vsync_clk == NULL) mdp_vsync_clk = clk_get(NULL, "mdp_vsync_clk"); if (IS_ERR(mdp_vsync_clk)) { printk(KERN_ERR "error: can't get mdp_vsync_clk!\n"); mfd->use_mdp_vsync = 0; } else mfd->use_mdp_vsync = 1; if (mfd->use_mdp_vsync) { uint32 vsync_cnt_cfg, vsync_cnt_cfg_dem; uint32 mdp_vsync_clk_speed_hz; mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk); if (mdp_vsync_clk_speed_hz == 0) { mfd->use_mdp_vsync = 0; } else { /* * Do this calculation in 2 steps for * rounding uint32 properly. */ vsync_cnt_cfg_dem = (mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) / 100; vsync_cnt_cfg = (mdp_vsync_clk_speed_hz) / vsync_cnt_cfg_dem; /* MDP cmd block enable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_hw_vsync_clk_enable(mfd); mdp_set_sync_cfg_0(mfd, vsync_cnt_cfg); #ifdef CONFIG_FB_MSM_MDP40 if (mdp_hw_revision < MDP4_REVISION_V2_1) mdp_set_sync_cfg_1(mfd, vsync_cnt_cfg); #endif /* * load the last line + 1 to be in the * safety zone */ vsync_load_cnt = mfd->panel_info.yres; /* line counter init value at the next pulse */ MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_INIT_VAL, vsync_load_cnt); #ifdef CONFIG_FB_MSM_MDP40 if (mdp_hw_revision < MDP4_REVISION_V2_1) { MDP_OUTP(MDP_BASE + MDP_SEC_VSYNC_INIT_VAL, vsync_load_cnt); } #endif /* * external vsync source pulse width and * polarity flip */ MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_OUT_CTRL, BIT(0)); #ifdef CONFIG_FB_MSM_MDP40 if (mdp_hw_revision < MDP4_REVISION_V2_1) { MDP_OUTP(MDP_BASE + MDP_SEC_VSYNC_OUT_CTRL, BIT(0)); MDP_OUTP(MDP_BASE + MDP_VSYNC_SEL, 0x20); } #endif /* threshold */ #ifdef CONFIG_MACH_ACER_A4 MDP_OUTP(MDP_BASE + MDP_SYNC_THRESH_0, (vsync_above_th << 16) | (vsync_start_th)); MDP_OUTP(MDP_BASE + MDP_SYNC_THRESH_1, (vsync_above_th << 16) | (vsync_start_th)); #else MDP_OUTP(MDP_BASE + 0x200, (vsync_above_th << 16) | (vsync_start_th)); #endif mdp_hw_vsync_clk_disable(mfd); /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } } #else mfd->use_mdp_vsync = 0; hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler; mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4); #endif #ifdef CONFIG_FB_MSM_MDDI mfd->channel_irq = 0; if (mfd->panel_info.lcd.hw_vsync_mode) { u32 vsync_gpio = mfd->vsync_gpio; u32 ret; if (vsync_gpio == -1) { MSM_FB_INFO("vsync_gpio not defined!\n"); goto err_handle; } ret = gpio_tlmm_config(GPIO_CFG (vsync_gpio, (mfd->use_mdp_vsync) ? 1 : 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); if (ret) goto err_handle; /* * if use_mdp_vsync, then no interrupt need since * mdp_vsync is feed directly to mdp to reset the * write pointer counter. therefore no irq_handler * need to reset write pointer counter. */ if (!mfd->use_mdp_vsync) { mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio); if (request_irq (mfd->channel_irq, &mdp_hw_vsync_handler_proxy, IRQF_TRIGGER_FALLING, "VSYNC_GPIO", (void *)mfd)) { MSM_FB_INFO ("irq=%d failed! vsync_gpio=%d\n", mfd->channel_irq, vsync_gpio); goto err_handle; } } } #endif mdp_hw_vsync_clk_enable(mfd); mdp_set_vsync((unsigned long)mfd); } return; err_handle: if (mfd->vsync_width_boundary) vfree(mfd->vsync_width_boundary); mfd->panel_info.lcd.vsync_enable = FALSE; printk(KERN_ERR "%s: failed!\n", __func__); }
void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state, boolean isr) { boolean mdp_all_blocks_off = TRUE; int i; unsigned long flag; spin_lock_irqsave(&mdp_spin_lock, flag); if (MDP_BLOCK_POWER_ON == state) { mdp_block_power_cnt[block]++; if (MDP_DMA2_BLOCK == block) mdp_in_processing = TRUE; } else { mdp_block_power_cnt[block]--; if (mdp_block_power_cnt[block] < 0) { ////////////////////////////////////////////////////////////////// // Master has to serve a request to power off MDP always // It also has a timer to power off. // So, in case of timer expires first and DMA2 finishes later, // master has to power off two times // // There shouldn't be multiple power-off request for other blocks ////////////////////////////////////////////////////////////////// if (block != MDP_MASTER_BLOCK) { MSM_FB_INFO ("mdp_block_power_cnt[block=%d] multiple power-off request\n", block); } mdp_block_power_cnt[block] = 0; } if (MDP_DMA2_BLOCK == block) mdp_in_processing = FALSE; } spin_unlock_irqrestore(&mdp_spin_lock, flag); ///////////////////////////////////////////////////////////////// // If it's in isr, we send our request to workqueue. // Otherwise, processing happens in the current context ///////////////////////////////////////////////////////////////// if (isr) { //////////////////////////////////////////////////// //checking all blocks power state //////////////////////////////////////////////////// for (i = 0; i < MDP_MAX_BLOCK; i++) { if (mdp_block_power_cnt[i] > 0) mdp_all_blocks_off = FALSE; } //////////////////////////////////////////////////// if ((mdp_all_blocks_off) && (mdp_current_clk_on)) { //send workqueue to turn off mdp power queue_delayed_work(mdp_pipe_ctrl_wq, &mdp_pipe_ctrl_worker, mdp_timer_duration); } } else { down(&mdp_pipe_ctrl_mutex); //////////////////////////////////////////////////// //checking all blocks power state //////////////////////////////////////////////////// for (i = 0; i < MDP_MAX_BLOCK; i++) { if (mdp_block_power_cnt[i] > 0) mdp_all_blocks_off = FALSE; } //////////////////////////////////////////////////// //find out whether a delayable work item is currently pending if (delayed_work_pending(&mdp_pipe_ctrl_worker)) { // try to cancel the current work *** // if it fails to stop (which means del_timer can't delete it // from the list, it's about to expire and run), we have to // let it run. queue_delayed_work won't accept the next job // which is same as queue_delayed_work(mdp_timer_duration = 0) cancel_delayed_work(&mdp_pipe_ctrl_worker); } if ((mdp_all_blocks_off) && (mdp_current_clk_on)) { if (block == MDP_MASTER_BLOCK) { mdp_current_clk_on = FALSE; // turn off MDP clk if (mdp_clk != NULL) { clk_disable(mdp_clk); disable_irq(INT_MDP); MSM_FB_DEBUG("MDP CLK OFF\n"); } } else { //send workqueue to turn off mdp power queue_delayed_work(mdp_pipe_ctrl_wq, &mdp_pipe_ctrl_worker, mdp_timer_duration); } } else if ((!mdp_all_blocks_off) && (!mdp_current_clk_on)) { mdp_current_clk_on = TRUE; // turn on MDP clk if (mdp_clk != NULL) { enable_irq(INT_MDP); clk_enable(mdp_clk); MSM_FB_DEBUG("MDP CLK ON\n"); } } up(&mdp_pipe_ctrl_mutex); } }
void mdp_config_vsync(struct platform_device *pdev, struct msm_fb_data_type *mfd) { /* vsync on primary lcd only for now */ if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1) || (!vsync_mode)) { goto err_handle; } vsync_clk_status = 0; if (mfd->panel_info.lcd.vsync_enable) { mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch + mfd->panel_info.lcd.v_front_porch + mfd->panel_info.lcd.v_pulse_width; mfd->total_lcd_lines = mfd->panel_info.yres + mfd->total_porch_lines; mfd->lcd_ref_usec_time = 100000000 / mfd->panel_info.lcd.refx100; mfd->vsync_handler_pending = FALSE; mfd->last_vsync_timetick.tv64 = 0; #ifdef MDP_HW_VSYNC if (mdp_vsync_clk == NULL) mdp_vsync_clk = clk_get(&pdev->dev, "vsync_clk"); if (IS_ERR(mdp_vsync_clk)) { printk(KERN_ERR "error: can't get mdp_vsync_clk!\n"); mfd->use_mdp_vsync = 0; } else mfd->use_mdp_vsync = 1; if (mfd->use_mdp_vsync) { uint32 vsync_cnt_cfg_dem; uint32 mdp_vsync_clk_speed_hz; mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk); if (mdp_vsync_clk_speed_hz == 0) { mfd->use_mdp_vsync = 0; } else { /* * Do this calculation in 2 steps for * rounding uint32 properly. */ vsync_cnt_cfg_dem = (mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) / 100; vsync_cnt_cfg = (mdp_vsync_clk_speed_hz) / vsync_cnt_cfg_dem; mdp_vsync_cfg_regs(mfd, TRUE); } } #else mfd->use_mdp_vsync = 0; hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler; mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4); #endif #ifdef CONFIG_FB_MSM_MDDI mfd->channel_irq = 0; if (mfd->panel_info.lcd.hw_vsync_mode) { u32 vsync_gpio = mfd->vsync_gpio; u32 ret; if (vsync_gpio == -1) { MSM_FB_INFO("vsync_gpio not defined!\n"); goto err_handle; } ret = gpio_tlmm_config(GPIO_CFG (vsync_gpio, (mfd->use_mdp_vsync) ? 1 : 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); if (ret) goto err_handle; /* * if use_mdp_vsync, then no interrupt need since * mdp_vsync is feed directly to mdp to reset the * write pointer counter. therefore no irq_handler * need to reset write pointer counter. */ if (!mfd->use_mdp_vsync) { mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio); if (request_irq (mfd->channel_irq, &mdp_hw_vsync_handler_proxy, IRQF_TRIGGER_FALLING, "VSYNC_GPIO", (void *)mfd)) { MSM_FB_INFO ("irq=%d failed! vsync_gpio=%d\n", mfd->channel_irq, vsync_gpio); goto err_handle; } } } #endif mdp_hw_vsync_clk_enable(mfd); mdp_set_vsync((unsigned long)mfd); } return; err_handle: if (mfd->vsync_width_boundary) vfree(mfd->vsync_width_boundary); mfd->panel_info.lcd.vsync_enable = FALSE; printk(KERN_ERR "%s: failed!\n", __func__); }
static int mipi_dsi_on(struct platform_device *pdev) { int ret = 0; u32 clk_rate; struct msm_fb_data_type *mfd; struct fb_info *fbi; struct fb_var_screeninfo *var; struct msm_panel_info *pinfo; struct mipi_panel_info *mipi; u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; u32 ystride, bpp, data; u32 dummy_xres, dummy_yres; int target_type = 0; mfd = platform_get_drvdata(pdev); fbi = mfd->fbi; var = &fbi->var; pinfo = &mfd->panel_info; MSM_FB_INFO("%s: %d\n",__func__,__LINE__); if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save) mipi_dsi_pdata->dsi_power_save(1); cont_splash_clk_ctrl(0); mipi_dsi_prepare_clocks(); local_bh_disable(); mipi_dsi_ahb_ctrl(1); local_bh_enable(); clk_rate = mfd->fbi->var.pixclock; clk_rate = min(clk_rate, mfd->panel_info.clk_max); mipi_dsi_phy_ctrl(1); if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata) target_type = mipi_dsi_pdata->target_type; mipi_dsi_phy_init(0, &(mfd->panel_info), target_type); local_bh_disable(); mipi_dsi_clk_enable(); local_bh_enable(); MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1); MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0); hbp = var->left_margin; hfp = var->right_margin; vbp = var->upper_margin; vfp = var->lower_margin; hspw = var->hsync_len; vspw = var->vsync_len; width = mfd->panel_info.xres; height = mfd->panel_info.yres; mipi = &mfd->panel_info.mipi; if (mfd->panel_info.type == MIPI_VIDEO_PANEL) { dummy_xres = mfd->panel_info.lcdc.xres_pad; dummy_yres = mfd->panel_info.lcdc.yres_pad; if (mdp_rev >= MDP_REV_41) { MIPI_OUTP(MIPI_DSI_BASE + 0x20, ((hspw + hbp + width + dummy_xres) << 16 | (hspw + hbp))); MIPI_OUTP(MIPI_DSI_BASE + 0x24, ((vspw + vbp + height + dummy_yres) << 16 | (vspw + vbp))); MIPI_OUTP(MIPI_DSI_BASE + 0x28, (vspw + vbp + height + dummy_yres + vfp - 1) << 16 | (hspw + hbp + width + dummy_xres + hfp - 1)); } else { /* DSI_LAN_SWAP_CTRL */ MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, mipi->dlane_swap); MIPI_OUTP(MIPI_DSI_BASE + 0x20, ((hbp + width + dummy_xres) << 16 | (hbp))); MIPI_OUTP(MIPI_DSI_BASE + 0x24, ((vbp + height + dummy_yres) << 16 | (vbp))); MIPI_OUTP(MIPI_DSI_BASE + 0x28, (vbp + height + dummy_yres + vfp) << 16 | (hbp + width + dummy_xres + hfp)); } MIPI_OUTP(MIPI_DSI_BASE + 0x2c, (hspw << 16)); MIPI_OUTP(MIPI_DSI_BASE + 0x30, 0); MIPI_OUTP(MIPI_DSI_BASE + 0x34, (vspw << 16)); } else { /* command mode */ if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) bpp = 2; else bpp = 3; /* Default format set to RGB888 */ ystride = width * bpp + 1; /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */ data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE; MIPI_OUTP(MIPI_DSI_BASE + 0x5c, data); MIPI_OUTP(MIPI_DSI_BASE + 0x54, data); /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */ data = height << 16 | width; MIPI_OUTP(MIPI_DSI_BASE + 0x60, data); MIPI_OUTP(MIPI_DSI_BASE + 0x58, data); } mipi_dsi_host_init(mipi); if (mipi->force_clk_lane_hs) { u32 tmp; tmp = MIPI_INP(MIPI_DSI_BASE + 0xA8); tmp |= (1<<28); MIPI_OUTP(MIPI_DSI_BASE + 0xA8, tmp); wmb(); } if (mdp_rev >= MDP_REV_41) mutex_lock(&mfd->dma->ov_mutex); else down(&mfd->dma->mutex); ret = panel_next_on(pdev); mipi_dsi_op_mode_config(mipi->mode); if (mfd->panel_info.type == MIPI_CMD_PANEL) { if (pinfo->lcd.vsync_enable) { if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) { if (mdp_rev >= MDP_REV_41) { if (gpio_request(vsync_gpio, "MDP_VSYNC") == 0) gpio_direction_input( vsync_gpio); else pr_err("%s: unable to \ request gpio=%d\n", __func__, vsync_gpio); } else if (mdp_rev == MDP_REV_303) { if (!tlmm_settings && gpio_request( vsync_gpio, "MDP_VSYNC") == 0) { ret = gpio_tlmm_config( GPIO_CFG( vsync_gpio, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); if (ret) { pr_err( "%s: unable to config \ tlmm = %d\n", __func__, vsync_gpio); } tlmm_settings = TRUE; gpio_direction_input( vsync_gpio); } else { if (!tlmm_settings) { pr_err( "%s: unable to request \ gpio=%d\n", __func__, vsync_gpio); } } }
static int mipi_dsi_probe(struct platform_device *pdev) { struct msm_fb_data_type *mfd; struct fb_info *fbi; struct msm_panel_info *pinfo; struct mipi_panel_info *mipi; struct platform_device *mdp_dev = NULL; struct msm_fb_panel_data *pdata = NULL; int rc; uint8 lanes = 0, bpp; uint32 h_period, v_period, dsi_pclk_rate; resource_size_t size ; if ((pdev->id == 1) && (pdev->num_resources >= 0)) { mipi_dsi_pdata = pdev->dev.platform_data; size = resource_size(&pdev->resource[0]); mipi_dsi_base = ioremap(pdev->resource[0].start, size); MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n", pdev->resource[0].start, (int) mipi_dsi_base); if (!mipi_dsi_base) return -ENOMEM; if (mdp_rev >= MDP_REV_41) { mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100); MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x," "virt = 0x%x\n", MMSS_SFPB_BASE_PHY, (int) mmss_sfpb_base); if (!mmss_sfpb_base) return -ENOMEM; } dsi_irq = platform_get_irq(pdev, 0); if (dsi_irq < 0) { pr_err("mipi_dsi: can not get mdp irq\n"); return -ENOMEM; } rc = request_irq(dsi_irq, mipi_dsi_isr, IRQF_DISABLED, "MIPI_DSI", 0); if (rc) { pr_err("mipi_dsi_host request_irq() failed!\n"); return rc; } disable_irq(dsi_irq); if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata && mipi_dsi_pdata->target_type == 1) { /* Target type is 1 for device with (De)serializer * 0x4f00000 is the base for TV Encoder. * Unused Offset 0x1000 is used for * (de)serializer on emulation platform */ periph_base = ioremap(MMSS_SERDES_BASE_PHY, 0x100); if (periph_base) { pr_debug("periph_base %p\n", periph_base); writel(0x4, periph_base + 0x28); writel(0xc, periph_base + 0x28); } else { pr_err("periph_base is NULL\n"); free_irq(dsi_irq, 0); return -ENOMEM; } } if (mipi_dsi_pdata) { vsync_gpio = mipi_dsi_pdata->vsync_gpio; pr_debug("%s: vsync_gpio=%d\n", __func__, vsync_gpio); if (mdp_rev == MDP_REV_303 && mipi_dsi_pdata->dsi_client_reset) { if (mipi_dsi_pdata->dsi_client_reset()) pr_err("%s: DSI Client Reset failed!\n", __func__); else pr_debug("%s: DSI Client Reset success\n", __func__); } } mipi_dsi_resource_initialized = 1; return 0; } mipi_dsi_clk_init(&pdev->dev); if (!mipi_dsi_resource_initialized) return -EPERM; mfd = platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) return -ENOMEM; mdp_dev = platform_device_alloc("mdp", pdev->id); if (!mdp_dev) return -ENOMEM; /* * link to the latest pdev */ mfd->pdev = mdp_dev; mfd->dest = DISPLAY_LCD; /* * alloc panel device data */ if (platform_device_add_data (mdp_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))) { pr_err("mipi_dsi_probe: platform_device_add_data failed!\n"); platform_device_put(mdp_dev); return -ENOMEM; } /* * data chain */ pdata = mdp_dev->dev.platform_data; pdata->on = mipi_dsi_on; pdata->off = mipi_dsi_off; pdata->next = pdev; /* * get/set panel specific fb info */ mfd->panel_info = pdata->panel_info; pinfo = &mfd->panel_info; if (mdp_rev == MDP_REV_303 && mipi_dsi_pdata->get_lane_config) { if (mipi_dsi_pdata->get_lane_config() != 2) { pr_info("Changing to DSI Single Mode Configuration\n"); #ifdef CONFIG_FB_MSM_MDP303 update_lane_config(pinfo); #endif } } if (mfd->index == 0) mfd->fb_imgType = MSMFB_DEFAULT_TYPE; else mfd->fb_imgType = MDP_RGB_565; fbi = mfd->fbi; fbi->var.pixclock = mfd->panel_info.clk_rate; fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch; fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch; fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch; fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch; fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width; fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width; h_period = ((mfd->panel_info.lcdc.h_pulse_width) + (mfd->panel_info.lcdc.h_back_porch) + (mfd->panel_info.xres) + (mfd->panel_info.lcdc.h_front_porch)); v_period = ((mfd->panel_info.lcdc.v_pulse_width) + (mfd->panel_info.lcdc.v_back_porch) + (mfd->panel_info.yres) + (mfd->panel_info.lcdc.v_front_porch)); mipi = &mfd->panel_info.mipi; if (mipi->data_lane3) lanes += 1; if (mipi->data_lane2) lanes += 1; if (mipi->data_lane1) lanes += 1; if (mipi->data_lane0) lanes += 1; if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888) || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE)) bpp = 3; else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565)) bpp = 2; else bpp = 3; /* Default format set to RGB888 */ if (mfd->panel_info.type == MIPI_VIDEO_PANEL && !mfd->panel_info.clk_rate) { h_period += mfd->panel_info.mipi.xres_pad; v_period += mfd->panel_info.mipi.yres_pad; if (lanes > 0) { mfd->panel_info.clk_rate = ((h_period * v_period * (mipi->frame_rate) * bpp * 8) / lanes); } else { pr_err("%s: forcing mipi_dsi lanes to 1\n", __func__); mfd->panel_info.clk_rate = (h_period * v_period * (mipi->frame_rate) * bpp * 8); } } pll_divider_config.clk_rate = mfd->panel_info.clk_rate; rc = mipi_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate); if (rc) goto mipi_dsi_probe_err; if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000)) dsi_pclk_rate = 35000000; mipi->dsi_pclk_rate = dsi_pclk_rate; /* * set driver data */ platform_set_drvdata(mdp_dev, mfd); /* * register in mdp driver */ rc = platform_device_add(mdp_dev); if (rc) goto mipi_dsi_probe_err; pdev_list[pdev_list_cnt++] = pdev; return 0; mipi_dsi_probe_err: platform_device_put(mdp_dev); return rc; }
void mdp_config_vsync(struct msm_fb_data_type *mfd) { // vsync on primary lcd only for now if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1) || (!vsync_mode)) { goto err_handle; } if (mfd->panel_info.lcd.vsync_enable) { mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch + mfd->panel_info.lcd.v_front_porch + mfd->panel_info.lcd.v_pulse_width; mfd->total_lcd_lines = mfd->panel_info.yres + mfd->total_porch_lines; mfd->lcd_ref_usec_time = 100000000 / mfd->panel_info.lcd.refx100; mfd->vsync_handler_pending = FALSE; mfd->last_vsync_timetick.tv.sec = 0; mfd->last_vsync_timetick.tv.nsec = 0; #ifdef MDP_HW_VSYNC if (mdp_vsync_clk == NULL) mdp_vsync_clk = clk_get(NULL, "mdp_vsync_clk"); if (IS_ERR(mdp_vsync_clk)) { printk(KERN_ERR "error: can't get mdp_vsync_clk!\n"); mfd->use_mdp_vsync = 0; } else mfd->use_mdp_vsync = 1; if (mfd->use_mdp_vsync) { uint32 vsync_cnt_cfg, vsync_cnt_cfg_dem; uint32 mdp_vsync_clk_speed_hz; mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk); if (mdp_vsync_clk_speed_hz == 0) { mfd->use_mdp_vsync = 0; } else { // Do this calculation in 2 steps for rounding uint32 properly. vsync_cnt_cfg_dem = (mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) / 100; vsync_cnt_cfg = (mdp_vsync_clk_speed_hz) / vsync_cnt_cfg_dem; //MDP cmd block enable mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_hw_vsync_clk_enable(mfd); MDP_OUTP(MDP_BASE + 0x300, ((mfd->total_lcd_lines - 1) << MDP_SYNCFG_HGT_LOC) | (mfd-> panel_info. lcd. hw_vsync_mode ? MDP_SYNCFG_VSYNC_EXT_EN : 0) | MDP_SYNCFG_VSYNC_INT_EN | vsync_cnt_cfg); // load the last line + 1 to be in the safety zone vsync_load_cnt = mfd->panel_info.yres; // line counter init value at the next pulse MDP_OUTP(MDP_BASE + 0x328, vsync_load_cnt); // external vsync source pulse width and polarity flip MDP_OUTP(MDP_BASE + 0x318, BIT(30) | BIT(0)); // threshold MDP_OUTP(MDP_BASE + 0x200, (vsync_above_th << 16) | (vsync_start_th)); mdp_hw_vsync_clk_disable(mfd); // MDP cmd block disable mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } } #else mfd->use_mdp_vsync = 0; hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler; mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4); #endif mfd->channel_irq = 0; if (mfd->panel_info.lcd.hw_vsync_mode) { u32 vsync_gpio = mfd->vsync_gpio; u32 ret; if (vsync_gpio == -1) { MSM_FB_INFO("vsync_gpio not defined!\n"); goto err_handle; } ret = gpio_tlmm_config(GPIO_CFG (vsync_gpio, (mfd->use_mdp_vsync) ? 1 : 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), GPIO_ENABLE); if (ret) goto err_handle; if (!mfd->use_mdp_vsync) { mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio); if (request_irq (mfd->channel_irq, &mdp_hw_vsync_handler_proxy, IRQF_TRIGGER_FALLING, "VSYNC_GPIO", (void *)mfd)) { MSM_FB_INFO ("irq=%d failed! vsync_gpio=%d\n", mfd->channel_irq, vsync_gpio); goto err_handle; } } } mdp_set_vsync((unsigned long)mfd); } return; err_handle: if (mfd->vsync_width_boundary) vfree(mfd->vsync_width_boundary); mfd->panel_info.lcd.vsync_enable = FALSE; printk(KERN_ERR "%s: failed!\n", __func__); }
static int mdp_probe(struct platform_device *pdev) { struct platform_device *msm_fb_dev = NULL; struct msm_fb_data_type *mfd; struct msm_fb_panel_data *pdata = NULL; int rc; unsigned long flag; resource_size_t size ; if ((pdev->id == 0) && (pdev->num_resources > 0)) { mdp_pdata = pdev->dev.platform_data; size = resource_size(&pdev->resource[0]); msm_mdp_base = ioremap(pdev->resource[0].start, size); MSM_FB_INFO("MDP HW Base Address = 0x%x\n", (int)pdev->resource[0].start); if (unlikely(!msm_mdp_base)) return -ENOMEM; mdp_resource_initialized = 1; return 0; } if (!mdp_resource_initialized) return -EPERM; mfd = platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) return -ENOMEM; msm_fb_dev = platform_device_alloc("msm_fb", pdev->id); if (!msm_fb_dev) return -ENOMEM; ///////////////////////////////////////// // link to the latest pdev ///////////////////////////////////////// mfd->pdev = msm_fb_dev; ///////////////////////////////////////// // add panel data ///////////////////////////////////////// if (platform_device_add_data (msm_fb_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))) { printk(KERN_ERR "mdp_probe: platform_device_add_data failed!\n"); rc = -ENOMEM; goto mdp_probe_err; } ///////////////////////////////////////// // data chain ///////////////////////////////////////// pdata = msm_fb_dev->dev.platform_data; pdata->on = mdp_on; pdata->off = mdp_off; pdata->next = pdev; switch (mfd->panel.type) { case EXT_MDDI_PANEL: case MDDI_PANEL: case EBI2_PANEL: INIT_WORK(&mfd->dma_update_worker, mdp_lcd_update_workqueue_handler); INIT_WORK(&mfd->vsync_resync_worker, mdp_vsync_resync_workqueue_handler); mfd->hw_refresh = FALSE; if (mfd->panel.type == EXT_MDDI_PANEL) mfd->refresh_timer_duration = (66 * HZ / 1000); // 15 fps -> 66 msec else mfd->refresh_timer_duration = (42 * HZ / 1000); // 24 fps -> 42 msec #ifdef CONFIG_FB_MSM_MDP22 mfd->dma_fnc = mdp_dma2_update; mfd->dma = &dma2_data; #else if (mfd->panel_info.pdest == DISPLAY_1) { mfd->dma_fnc = mdp_dma2_update; mfd->dma = &dma2_data; } else { mfd->dma_fnc = mdp_dma_s_update; mfd->dma = &dma_s_data; } #endif if (mdp_pdata) mfd->vsync_gpio = mdp_pdata->gpio; else mfd->vsync_gpio = -1; mdp_config_vsync(mfd); break; case LCDC_PANEL: pdata->on = mdp_lcdc_on; pdata->off = mdp_lcdc_off; mfd->hw_refresh = TRUE; mfd->cursor_update = mdp_hw_cursor_update; mfd->dma_fnc = mdp_lcdc_update; mfd->dma = &dma2_data; spin_lock_irqsave(&mdp_spin_lock, flag); mdp_intr_mask &= ~MDP_DMA_P_DONE; outp32(MDP_INTR_ENABLE, mdp_intr_mask); spin_unlock_irqrestore(&mdp_spin_lock, flag); break; case TV_PANEL: pdata->on = mdp_dma3_on; pdata->off = mdp_dma3_off; mfd->hw_refresh = TRUE; mfd->dma_fnc = mdp_dma3_update; mfd->dma = &dma3_data; break; default: printk(KERN_ERR "mdp_probe: unknown device type!\n"); rc = -ENODEV; goto mdp_probe_err; } ///////////////////////////////////////// // set driver data ///////////////////////////////////////// platform_set_drvdata(msm_fb_dev, mfd); rc = platform_device_add(msm_fb_dev); if (rc) { goto mdp_probe_err; } pdev_list[pdev_list_cnt++] = pdev; return 0; mdp_probe_err: platform_device_put(msm_fb_dev); return rc; }
static int mddi_ext_probe(struct platform_device *pdev) { struct msm_fb_data_type *mfd; struct platform_device *mdp_dev = NULL; struct msm_fb_panel_data *pdata = NULL; int rc; resource_size_t size ; u32 clk_rate; if ((pdev->id == 0) && (pdev->num_resources >= 0)) { mddi_ext_pdata = pdev->dev.platform_data; mddi_ext_clk = clk_get(&pdev->dev, "core_clk"); if (IS_ERR(mddi_ext_clk)) { pr_err("can't find emdh_clk\n"); return PTR_ERR(mddi_ext_clk); } clk_prepare_enable(mddi_ext_clk); mddi_ext_pclk = clk_get(&pdev->dev, "iface_clk"); if (IS_ERR(mddi_ext_pclk)) mddi_ext_pclk = NULL; else clk_prepare_enable(mddi_ext_pclk); size = resource_size(&pdev->resource[0]); msm_emdh_base = ioremap(pdev->resource[0].start, size); MSM_FB_INFO("external mddi base address = 0x%x\n", pdev->resource[0].start); if (unlikely(!msm_emdh_base)) return -ENOMEM; mddi_ext_resource_initialized = 1; return 0; } if (!mddi_ext_resource_initialized) return -EPERM; mfd = platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) return -ENOMEM; mdp_dev = platform_device_alloc("mdp", pdev->id); if (!mdp_dev) return -ENOMEM; /* * link to the latest pdev */ mfd->pdev = mdp_dev; mfd->dest = DISPLAY_EXT_MDDI; /* * alloc panel device data */ if (platform_device_add_data (mdp_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))) { printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n"); platform_device_put(mdp_dev); return -ENOMEM; } /* * data chain */ pdata = mdp_dev->dev.platform_data; pdata->on = mddi_ext_on; pdata->off = mddi_ext_off; pdata->next = pdev; /* * get/set panel specific fb info */ mfd->panel_info = pdata->panel_info; mfd->fb_imgType = MDP_RGB_565; clk_rate = mfd->panel_info.clk_max; if (mddi_ext_pdata && mddi_ext_pdata->mddi_sel_clk && mddi_ext_pdata->mddi_sel_clk(&clk_rate)) printk(KERN_ERR "%s: can't select mddi io clk targate rate = %d\n", __func__, clk_rate); if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0) printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); mfd->panel_info.clk_rate = mfd->panel_info.clk_min; /* * set driver data */ platform_set_drvdata(mdp_dev, mfd); rc = pm_runtime_set_active(&pdev->dev); if (rc < 0) printk(KERN_ERR "pm_runtime: fail to set active\n"); rc = 0; pm_runtime_enable(&pdev->dev); /* * register in mdp driver */ rc = platform_device_add(mdp_dev); if (rc) goto mddi_ext_probe_err; pdev_list[pdev_list_cnt++] = pdev; #ifdef CONFIG_HAS_EARLYSUSPEND mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend; mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume; register_early_suspend(&mfd->mddi_ext_early_suspend); #endif return 0; mddi_ext_probe_err: platform_device_put(mdp_dev); return rc; }
static int mipi_dsi_probe(struct platform_device *pdev) { struct msm_fb_data_type *mfd; struct fb_info *fbi; struct platform_device *mdp_dev = NULL; struct msm_fb_panel_data *pdata = NULL; int rc; resource_size_t size ; if ((pdev->id == 0) && (pdev->num_resources >= 0)) { mipi_dsi_pdata = pdev->dev.platform_data; size = resource_size(&pdev->resource[0]); mipi_dsi_base = ioremap(pdev->resource[0].start, size); MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n", pdev->resource[0].start, (int) mipi_dsi_base); if (!mipi_dsi_base) return -ENOMEM; mmss_cc_base = ioremap(MMSS_CC_BASE_PHY, 0x200); MSM_FB_INFO("mmss_cc base phy_addr = 0x%x virt = 0x%x\n", MMSS_CC_BASE_PHY, (int) mmss_cc_base); if (!mmss_cc_base) return -ENOMEM; mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100); MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x virt = 0x%x\n", MMSS_SFPB_BASE_PHY, (int) mmss_sfpb_base); if (!mmss_cc_base) return -ENOMEM; rc = request_irq(DSI_IRQ, mipi_dsi_isr, IRQF_DISABLED, "MIPI_DSI", 0); if (rc) { printk(KERN_ERR "mipi_dsi_host request_irq() failed!\n"); return rc; } disable_irq(DSI_IRQ); mipi_dsi_calibration(); if (mipi_dsi_mxo_selected()) dsi_cc_data |= BIT(8); /* use MXO for DSI PLL clkref */ else dsi_cc_data &= ~BIT(8); /* use PXO */ mipi_dsi_resource_initialized = 1; return 0; } if (!mipi_dsi_resource_initialized) return -EPERM; mfd = platform_get_drvdata(pdev); if (!mfd) return -ENODEV; if (mfd->key != MFD_KEY) return -EINVAL; if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) return -ENOMEM; mdp_dev = platform_device_alloc("mdp", pdev->id); if (!mdp_dev) return -ENOMEM; /* * link to the latest pdev */ mfd->pdev = mdp_dev; mfd->dest = DISPLAY_LCD; /* * alloc panel device data */ if (platform_device_add_data (mdp_dev, pdev->dev.platform_data, sizeof(struct msm_fb_panel_data))) { printk(KERN_ERR "mipi_dsi_probe: platform_device_add_data failed!\n"); platform_device_put(mdp_dev); return -ENOMEM; } /* * data chain */ pdata = mdp_dev->dev.platform_data; pdata->on = mipi_dsi_on; pdata->off = mipi_dsi_off; pdata->next = pdev; /* * get/set panel specific fb info */ mfd->panel_info = pdata->panel_info; if (mfd->index == 0) mfd->fb_imgType = MSMFB_DEFAULT_TYPE; else mfd->fb_imgType = MDP_RGB_565; fbi = mfd->fbi; fbi->var.pixclock = mfd->panel_info.clk_rate; fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch; fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch; fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch; fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch; fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width; fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width; #ifdef DSI_CLK clk_rate = mfd->panel_info.clk_max; if (clk_set_max_rate(mipi_dsi_clk, clk_rate) < 0) printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); mfd->panel_info.clk_rate = mfd->panel_info.clk_min; #endif /* * set driver data */ platform_set_drvdata(mdp_dev, mfd); /* * register in mdp driver */ rc = platform_device_add(mdp_dev); if (rc) goto mipi_dsi_probe_err; pdev_list[pdev_list_cnt++] = pdev; mfd->pm_qos_req = pm_qos_add_request(PM_QOS_SYSTEM_BUS_FREQ, PM_QOS_DEFAULT_VALUE); if (!mfd->pm_qos_req) goto mipi_dsi_probe_err; return 0; mipi_dsi_probe_err: platform_device_put(mdp_dev); return rc; }
void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd) { /* complete all the writes before starting */ wmb(); /* kick off PPP engine */ if (term == MDP_PPP_TERM) { if (mdp_debug[MDP_PPP_BLOCK]) jiffies_to_timeval(jiffies, &mdp_ppp_timeval); /* let's turn on PPP block */ mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_enable_irq(term); INIT_COMPLETION(mdp_ppp_comp); mdp_ppp_waiting = TRUE; outpdw(MDP_BASE + 0x30, 0x1000); wait_for_completion_killable(&mdp_ppp_comp); mdp_disable_irq(term); if (mdp_debug[MDP_PPP_BLOCK]) { struct timeval now; jiffies_to_timeval(jiffies, &now); mdp_ppp_timeval.tv_usec = now.tv_usec - mdp_ppp_timeval.tv_usec; MSM_FB_INFO("MDP-PPP: %d\n", (int)mdp_ppp_timeval.tv_usec); } } else if (term == MDP_DMA2_TERM) { if (mdp_debug[MDP_DMA2_BLOCK]) { MSM_FB_INFO("MDP-DMA2: %d\n", (int)mdp_dma2_timeval.tv_usec); jiffies_to_timeval(jiffies, &mdp_dma2_timeval); } /* DMA update timestamp */ mdp_dma2_last_update_time = ktime_get_real(); /* let's turn on DMA2 block */ #if 0 mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); #endif #ifdef CONFIG_FB_MSM_MDP22 outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0);/* start DMA */ #else mdp_lut_enable(); #ifdef CONFIG_FB_MSM_MDP40 outpdw(MDP_BASE + 0x000c, 0x0); /* start DMA */ #else outpdw(MDP_BASE + 0x0044, 0x0); /* start DMA */ #endif #endif #ifdef CONFIG_FB_MSM_MDP40 } else if (term == MDP_DMA_S_TERM) { mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); outpdw(MDP_BASE + 0x0010, 0x0); /* start DMA */ } else if (term == MDP_DMA_E_TERM) { mdp_pipe_ctrl(MDP_DMA_E_BLOCK, MDP_BLOCK_POWER_ON, FALSE); outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */ } else if (term == MDP_OVERLAY0_TERM) { mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_lut_enable(); outpdw(MDP_BASE + 0x0004, 0); } else if (term == MDP_OVERLAY1_TERM) { mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_lut_enable(); outpdw(MDP_BASE + 0x0008, 0); } #else }
static int __init mipi_cmd_sony_wvga_pt_init(void) { int ret; if (msm_fb_detect_client("mipi_cmd_sony_wvga")) return 0; MSM_FB_INFO("[DISP] panel: mipi_cmd_sony_wvga\n"); pinfo.xres = 480; pinfo.yres = 800; pinfo.type = MIPI_CMD_PANEL; pinfo.pdest = DISPLAY_1; pinfo.wait_cycle = 0; pinfo.bpp = 24; pinfo.lcdc.h_back_porch = 2; pinfo.lcdc.h_front_porch = 2; pinfo.lcdc.h_pulse_width = 2; pinfo.lcdc.v_back_porch = 2; pinfo.lcdc.v_front_porch = 2; pinfo.lcdc.v_pulse_width = 2; pinfo.lcdc.border_clr = 0; /* blk */ pinfo.lcdc.underflow_clr = 0xff; /* blue */ pinfo.lcdc.hsync_skew = 0; pinfo.lcd.v_back_porch = 2; pinfo.lcd.v_front_porch = 2; pinfo.lcd.v_pulse_width = 2; pinfo.bl_max = 255; pinfo.bl_min = 1; pinfo.fb_num = 2; pinfo.clk_rate = 499000000; pinfo.lcd.vsync_enable = TRUE; pinfo.lcd.hw_vsync_mode = TRUE; pinfo.lcd.refx100 = 6500; /* adjust refx100 to prevent tearing */ pinfo.mipi.mode = DSI_CMD_MODE; pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; pinfo.mipi.vc = 0; pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; pinfo.mipi.data_lane0 = TRUE; pinfo.mipi.t_clk_post = 0x20; pinfo.mipi.t_clk_pre = 0x2c; pinfo.mipi.stream = 0; /* dma_p */ pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */ pinfo.mipi.interleave_max = 1; pinfo.mipi.insert_dcs_cmd = TRUE; pinfo.mipi.wr_mem_continue = 0x3c; pinfo.mipi.wr_mem_start = 0x2c; pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; pinfo.mipi.tx_eot_append = 0x01; pinfo.mipi.rx_eot_ignore = 0; pinfo.mipi.dlane_swap = 0x01; ret = mipi_sony_device_register(&pinfo, MIPI_DSI_PRIM, MIPI_DSI_PANEL_WVGA_PT); if (ret) pr_err("%s: failed to register device!\n", __func__); return ret; }