| /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/sched.h> |
| #include <linux/time.h> |
| #include <linux/init.h> |
| #include <linux/interrupt.h> |
| #include <linux/hrtimer.h> |
| #include <linux/delay.h> |
| #include <mach/hardware.h> |
| #include <linux/io.h> |
| |
| #include <asm/system.h> |
| #include <asm/mach-types.h> |
| #include <linux/semaphore.h> |
| #include <linux/spinlock.h> |
| |
| #include <linux/fb.h> |
| |
| #include "mdp.h" |
| #include "msm_fb.h" |
| #include "mdp4.h" |
| |
| static struct mdp4_overlay_pipe *mddi_pipe; |
| static struct mdp4_overlay_pipe *pending_pipe; |
| static struct msm_fb_data_type *mddi_mfd; |
| |
| #define WHOLESCREEN |
| |
| void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd) |
| { |
| MDPIBUF *iBuf = &mfd->ibuf; |
| uint8 *src; |
| int bpp, ptype; |
| uint32 format; |
| uint32 mddi_ld_param; |
| uint16 mddi_vdo_packet_reg; |
| struct mdp4_overlay_pipe *pipe; |
| |
| if (mfd->key != MFD_KEY) |
| return; |
| |
| mddi_mfd = mfd; /* keep it */ |
| |
| bpp = iBuf->bpp; |
| |
| if (bpp == 2) |
| format = MDP_RGB_565; |
| else if (bpp == 3) |
| format = MDP_RGB_888; |
| else |
| format = MDP_ARGB_8888; |
| |
| /* MDP cmd block enable */ |
| mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); |
| |
| if (mddi_pipe == NULL) { |
| ptype = mdp4_overlay_format2type(format); |
| pipe = mdp4_overlay_pipe_alloc(); |
| pipe->pipe_type = ptype; |
| /* use RGB1 pipe */ |
| pipe->pipe_num = OVERLAY_PIPE_RGB1; |
| pipe->mixer_num = MDP4_MIXER0; |
| pipe->src_format = format; |
| mdp4_overlay_format2pipe(pipe); |
| |
| mddi_pipe = pipe; /* keep it */ |
| |
| mddi_ld_param = 0; |
| mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; |
| |
| if (mfd->panel_info.type == MDDI_PANEL) { |
| if (mfd->panel_info.pdest == DISPLAY_1) |
| mddi_ld_param = 0; |
| else |
| mddi_ld_param = 1; |
| } else { |
| mddi_ld_param = 2; |
| } |
| |
| MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); |
| MDP_OUTP(MDP_BASE + 0x00094, |
| (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); |
| } else { |
| pipe = mddi_pipe; |
| } |
| |
| |
| src = (uint8 *) iBuf->buf; |
| |
| #ifdef WHOLESCREEN |
| { |
| struct fb_info *fbi; |
| |
| fbi = mfd->fbi; |
| pipe->src_height = fbi->var.yres; |
| pipe->src_width = fbi->var.xres; |
| pipe->src_h = fbi->var.yres; |
| pipe->src_w = fbi->var.xres; |
| pipe->src_y = 0; |
| pipe->src_x = 0; |
| pipe->dst_h = fbi->var.yres; |
| pipe->dst_w = fbi->var.xres; |
| pipe->dst_y = 0; |
| pipe->dst_x = 0; |
| pipe->srcp0_addr = (uint32)src; |
| pipe->srcp0_ystride = fbi->var.xres_virtual * bpp; |
| } |
| |
| #else |
| if (mdp4_overlay_active(MDP4_MIXER0)) { |
| struct fb_info *fbi; |
| |
| fbi = mfd->fbi; |
| pipe->src_height = fbi->var.yres; |
| pipe->src_width = fbi->var.xres; |
| pipe->src_h = fbi->var.yres; |
| pipe->src_w = fbi->var.xres; |
| pipe->src_y = 0; |
| pipe->src_x = 0; |
| pipe->dst_h = fbi->var.yres; |
| pipe->dst_w = fbi->var.xres; |
| pipe->dst_y = 0; |
| pipe->dst_x = 0; |
| pipe->srcp0_addr = (uint32) src; |
| pipe->srcp0_ystride = fbi->var.xres_virtual * bpp; |
| } else { |
| /* starting input address */ |
| src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * bpp; |
| |
| pipe->src_height = iBuf->dma_h; |
| pipe->src_width = iBuf->dma_w; |
| pipe->src_h = iBuf->dma_h; |
| pipe->src_w = iBuf->dma_w; |
| pipe->src_y = 0; |
| pipe->src_x = 0; |
| pipe->dst_h = iBuf->dma_h; |
| pipe->dst_w = iBuf->dma_w; |
| pipe->dst_y = iBuf->dma_y; |
| pipe->dst_x = iBuf->dma_x; |
| pipe->srcp0_addr = (uint32) src; |
| pipe->srcp0_ystride = iBuf->ibuf_width * bpp; |
| } |
| #endif |
| |
| pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; |
| |
| mdp4_overlay_rgb_setup(pipe); |
| |
| mdp4_mixer_stage_up(pipe); |
| |
| mdp4_overlayproc_cfg(pipe); |
| |
| mdp4_overlay_dmap_xy(pipe); |
| |
| mdp4_overlay_dmap_cfg(mfd, 0); |
| |
| /* MDP cmd block disable */ |
| mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); |
| |
| } |
| |
| /* |
| * mdp4_overlay0_done_mddi: called from isr |
| */ |
| void mdp4_overlay0_done_mddi() |
| { |
| if (pending_pipe) |
| complete(&pending_pipe->comp); |
| } |
| |
| void mdp4_mddi_overlay_restore(void) |
| { |
| /* mutex holded by caller */ |
| mdp4_overlay_update_lcd(mddi_mfd); |
| mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe); |
| } |
| |
| void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd, |
| struct mdp4_overlay_pipe *pipe) |
| { |
| #ifdef MDP4_NONBLOCKING |
| unsigned long flag; |
| |
| spin_lock_irqsave(&mdp_spin_lock, flag); |
| if (mfd->dma->busy == TRUE) { |
| INIT_COMPLETION(pipe->comp); |
| pending_pipe = pipe; |
| } |
| spin_unlock_irqrestore(&mdp_spin_lock, flag); |
| |
| if (pending_pipe != NULL) { |
| /* wait until DMA finishes the current job */ |
| wait_for_completion_killable(&pipe->comp); |
| pending_pipe = NULL; |
| } |
| down(&mfd->sem); |
| mdp_enable_irq(MDP_OVERLAY0_TERM); |
| mfd->dma->busy = TRUE; |
| /* start OVERLAY pipe */ |
| mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd); |
| up(&mfd->sem); |
| #else |
| down(&mfd->sem); |
| mdp_enable_irq(MDP_OVERLAY0_TERM); |
| mfd->dma->busy = TRUE; |
| INIT_COMPLETION(pipe->comp); |
| pending_pipe = pipe; |
| |
| /* start OVERLAY pipe */ |
| mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd); |
| up(&mfd->sem); |
| |
| /* wait until DMA finishes the current job */ |
| wait_for_completion_killable(&pipe->comp); |
| mdp_disable_irq(MDP_OVERLAY0_TERM); |
| #endif |
| |
| } |
| |
| void mdp4_mddi_overlay(struct msm_fb_data_type *mfd) |
| { |
| mutex_lock(&mfd->dma->ov_mutex); |
| |
| if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { |
| mdp4_overlay_update_lcd(mfd); |
| |
| mdp4_mddi_overlay_kickoff(mfd, mddi_pipe); |
| |
| /* signal if pan function is waiting for the update completion */ |
| if (mfd->pan_waiting) { |
| mfd->pan_waiting = FALSE; |
| complete(&mfd->pan_comp); |
| } |
| } |
| |
| mutex_unlock(&mfd->dma->ov_mutex); |
| } |